diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-12 22:28:50 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-12 22:28:50 -0500 |
| commit | c7d7b98671552abade78834c522b7308bda73c0d (patch) | |
| tree | 062dab589e90a8006d2be5d55f8f95f4f16be93b | |
| parent | 818099574b04c5301eacbbcd441022b353a65466 (diff) | |
| parent | 1a118ccfd60fc78e64c0a3ab9e85075545839d6e (diff) | |
Merge tag 'for-f2fs-3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs
Pull f2fs updates from Jaegeuk Kim:
"Major changes are to:
- add f2fs_io_tracer and F2FS_IOC_GETVERSION
- fix wrong acl assignment from parent
- fix accessing wrong data blocks
- fix wrong condition check for f2fs_sync_fs
- align start block address for direct_io
- add and refactor the readahead flows of FS metadata
- refactor atomic and volatile write policies
But most of patches are for clean-ups and minor bug fixes. Some of
them refactor old code too"
* tag 'for-f2fs-3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (64 commits)
f2fs: use spinlock for segmap_lock instead of rwlock
f2fs: fix accessing wrong indexed data blocks
f2fs: avoid variable length array
f2fs: fix sparse warnings
f2fs: allocate data blocks in advance for f2fs_direct_IO
f2fs: introduce macros to convert bytes and blocks in f2fs
f2fs: call set_buffer_new for get_block
f2fs: check node page contents all the time
f2fs: avoid data offset overflow when lseeking huge file
f2fs: fix to use highmem for pages of newly created directory
f2fs: introduce a batched trim
f2fs: merge {invalidate,release}page for meta/node/data pages
f2fs: show the number of writeback pages in stat
f2fs: keep PagePrivate during releasepage
f2fs: should fail mount when trying to recover data on read-only dev
f2fs: split UMOUNT and FASTBOOT flags
f2fs: avoid write_checkpoint if f2fs is mounted readonly
f2fs: support norecovery mount option
f2fs: fix not to drop mount options when retrying fill_super
f2fs: merge flags in struct f2fs_sb_info
...
| -rw-r--r-- | Documentation/ABI/testing/sysfs-fs-f2fs | 6 | ||||
| -rw-r--r-- | Documentation/filesystems/f2fs.txt | 6 | ||||
| -rw-r--r-- | fs/f2fs/Kconfig | 10 | ||||
| -rw-r--r-- | fs/f2fs/Makefile | 1 | ||||
| -rw-r--r-- | fs/f2fs/acl.c | 6 | ||||
| -rw-r--r-- | fs/f2fs/checkpoint.c | 95 | ||||
| -rw-r--r-- | fs/f2fs/data.c | 218 | ||||
| -rw-r--r-- | fs/f2fs/debug.c | 59 | ||||
| -rw-r--r-- | fs/f2fs/dir.c | 3 | ||||
| -rw-r--r-- | fs/f2fs/f2fs.h | 120 | ||||
| -rw-r--r-- | fs/f2fs/file.c | 100 | ||||
| -rw-r--r-- | fs/f2fs/gc.c | 38 | ||||
| -rw-r--r-- | fs/f2fs/gc.h | 33 | ||||
| -rw-r--r-- | fs/f2fs/inline.c | 32 | ||||
| -rw-r--r-- | fs/f2fs/inode.c | 37 | ||||
| -rw-r--r-- | fs/f2fs/namei.c | 2 | ||||
| -rw-r--r-- | fs/f2fs/node.c | 154 | ||||
| -rw-r--r-- | fs/f2fs/node.h | 45 | ||||
| -rw-r--r-- | fs/f2fs/recovery.c | 11 | ||||
| -rw-r--r-- | fs/f2fs/segment.c | 194 | ||||
| -rw-r--r-- | fs/f2fs/segment.h | 29 | ||||
| -rw-r--r-- | fs/f2fs/super.c | 75 | ||||
| -rw-r--r-- | fs/f2fs/trace.c | 159 | ||||
| -rw-r--r-- | fs/f2fs/trace.h | 46 | ||||
| -rw-r--r-- | include/linux/f2fs_fs.h | 7 | ||||
| -rw-r--r-- | include/trace/events/f2fs.h | 148 |
26 files changed, 1075 insertions, 559 deletions
diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 6f9157f16725..2c4cc42006e8 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs | |||
| @@ -74,3 +74,9 @@ Date: March 2014 | |||
| 74 | Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com> | 74 | Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com> |
| 75 | Description: | 75 | Description: |
| 76 | Controls the memory footprint used by f2fs. | 76 | Controls the memory footprint used by f2fs. |
| 77 | |||
| 78 | What: /sys/fs/f2fs/<disk>/trim_sections | ||
| 79 | Date: February 2015 | ||
| 80 | Contact: "Jaegeuk Kim" <jaegeuk@kernel.org> | ||
| 81 | Description: | ||
| 82 | Controls the trimming rate in batch mode. | ||
diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index e0950c483c22..dac11d7fef27 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt | |||
| @@ -106,6 +106,8 @@ background_gc=%s Turn on/off cleaning operations, namely garbage | |||
| 106 | Default value for this option is on. So garbage | 106 | Default value for this option is on. So garbage |
| 107 | collection is on by default. | 107 | collection is on by default. |
| 108 | disable_roll_forward Disable the roll-forward recovery routine | 108 | disable_roll_forward Disable the roll-forward recovery routine |
| 109 | norecovery Disable the roll-forward recovery routine, mounted read- | ||
| 110 | only (i.e., -o ro,disable_roll_forward) | ||
| 109 | discard Issue discard/TRIM commands when a segment is cleaned. | 111 | discard Issue discard/TRIM commands when a segment is cleaned. |
| 110 | no_heap Disable heap-style segment allocation which finds free | 112 | no_heap Disable heap-style segment allocation which finds free |
| 111 | segments for data from the beginning of main area, while | 113 | segments for data from the beginning of main area, while |
| @@ -197,6 +199,10 @@ Files in /sys/fs/f2fs/<devname> | |||
| 197 | checkpoint is triggered, and issued during the | 199 | checkpoint is triggered, and issued during the |
| 198 | checkpoint. By default, it is disabled with 0. | 200 | checkpoint. By default, it is disabled with 0. |
| 199 | 201 | ||
| 202 | trim_sections This parameter controls the number of sections | ||
| 203 | to be trimmed out in batch mode when FITRIM | ||
| 204 | conducts. 32 sections is set by default. | ||
| 205 | |||
| 200 | ipu_policy This parameter controls the policy of in-place | 206 | ipu_policy This parameter controls the policy of in-place |
| 201 | updates in f2fs. There are five policies: | 207 | updates in f2fs. There are five policies: |
| 202 | 0x01: F2FS_IPU_FORCE, 0x02: F2FS_IPU_SSR, | 208 | 0x01: F2FS_IPU_FORCE, 0x02: F2FS_IPU_SSR, |
diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig index 736a348509f7..94e2d2ffabe1 100644 --- a/fs/f2fs/Kconfig +++ b/fs/f2fs/Kconfig | |||
| @@ -71,3 +71,13 @@ config F2FS_CHECK_FS | |||
| 71 | Enables BUG_ONs which check the filesystem consistency in runtime. | 71 | Enables BUG_ONs which check the filesystem consistency in runtime. |
| 72 | 72 | ||
| 73 | If you want to improve the performance, say N. | 73 | If you want to improve the performance, say N. |
| 74 | |||
| 75 | config F2FS_IO_TRACE | ||
| 76 | bool "F2FS IO tracer" | ||
| 77 | depends on F2FS_FS | ||
| 78 | depends on FUNCTION_TRACER | ||
| 79 | help | ||
| 80 | F2FS IO trace is based on a function trace, which gathers process | ||
| 81 | information and block IO patterns in the filesystem level. | ||
| 82 | |||
| 83 | If unsure, say N. | ||
diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile index 2e35da12d292..d92397731db8 100644 --- a/fs/f2fs/Makefile +++ b/fs/f2fs/Makefile | |||
| @@ -5,3 +5,4 @@ f2fs-y += checkpoint.o gc.o data.o node.o segment.o recovery.o | |||
| 5 | f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o | 5 | f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o |
| 6 | f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o | 6 | f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o |
| 7 | f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o | 7 | f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o |
| 8 | f2fs-$(CONFIG_F2FS_IO_TRACE) += trace.o | ||
diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index 1ccb26bc2a0b..742202779bd5 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c | |||
| @@ -62,7 +62,7 @@ static struct posix_acl *f2fs_acl_from_disk(const char *value, size_t size) | |||
| 62 | if (count == 0) | 62 | if (count == 0) |
| 63 | return NULL; | 63 | return NULL; |
| 64 | 64 | ||
| 65 | acl = posix_acl_alloc(count, GFP_KERNEL); | 65 | acl = posix_acl_alloc(count, GFP_NOFS); |
| 66 | if (!acl) | 66 | if (!acl) |
| 67 | return ERR_PTR(-ENOMEM); | 67 | return ERR_PTR(-ENOMEM); |
| 68 | 68 | ||
| @@ -116,7 +116,7 @@ static void *f2fs_acl_to_disk(const struct posix_acl *acl, size_t *size) | |||
| 116 | int i; | 116 | int i; |
| 117 | 117 | ||
| 118 | f2fs_acl = kmalloc(sizeof(struct f2fs_acl_header) + acl->a_count * | 118 | f2fs_acl = kmalloc(sizeof(struct f2fs_acl_header) + acl->a_count * |
| 119 | sizeof(struct f2fs_acl_entry), GFP_KERNEL); | 119 | sizeof(struct f2fs_acl_entry), GFP_NOFS); |
| 120 | if (!f2fs_acl) | 120 | if (!f2fs_acl) |
| 121 | return ERR_PTR(-ENOMEM); | 121 | return ERR_PTR(-ENOMEM); |
| 122 | 122 | ||
| @@ -396,7 +396,7 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage, | |||
| 396 | posix_acl_release(default_acl); | 396 | posix_acl_release(default_acl); |
| 397 | } | 397 | } |
| 398 | if (acl) { | 398 | if (acl) { |
| 399 | if (error) | 399 | if (!error) |
| 400 | error = __f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, | 400 | error = __f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, |
| 401 | ipage); | 401 | ipage); |
| 402 | posix_acl_release(acl); | 402 | posix_acl_release(acl); |
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index e6c271fefaca..7f794b72b3b7 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c | |||
| @@ -20,10 +20,11 @@ | |||
| 20 | #include "f2fs.h" | 20 | #include "f2fs.h" |
| 21 | #include "node.h" | 21 | #include "node.h" |
| 22 | #include "segment.h" | 22 | #include "segment.h" |
| 23 | #include "trace.h" | ||
| 23 | #include <trace/events/f2fs.h> | 24 | #include <trace/events/f2fs.h> |
| 24 | 25 | ||
| 25 | static struct kmem_cache *ino_entry_slab; | 26 | static struct kmem_cache *ino_entry_slab; |
| 26 | static struct kmem_cache *inode_entry_slab; | 27 | struct kmem_cache *inode_entry_slab; |
| 27 | 28 | ||
| 28 | /* | 29 | /* |
| 29 | * We guarantee no failure on the returned page. | 30 | * We guarantee no failure on the returned page. |
| @@ -50,6 +51,11 @@ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) | |||
| 50 | { | 51 | { |
| 51 | struct address_space *mapping = META_MAPPING(sbi); | 52 | struct address_space *mapping = META_MAPPING(sbi); |
| 52 | struct page *page; | 53 | struct page *page; |
| 54 | struct f2fs_io_info fio = { | ||
| 55 | .type = META, | ||
| 56 | .rw = READ_SYNC | REQ_META | REQ_PRIO, | ||
| 57 | .blk_addr = index, | ||
| 58 | }; | ||
| 53 | repeat: | 59 | repeat: |
| 54 | page = grab_cache_page(mapping, index); | 60 | page = grab_cache_page(mapping, index); |
| 55 | if (!page) { | 61 | if (!page) { |
| @@ -59,8 +65,7 @@ repeat: | |||
| 59 | if (PageUptodate(page)) | 65 | if (PageUptodate(page)) |
| 60 | goto out; | 66 | goto out; |
| 61 | 67 | ||
| 62 | if (f2fs_submit_page_bio(sbi, page, index, | 68 | if (f2fs_submit_page_bio(sbi, page, &fio)) |
| 63 | READ_SYNC | REQ_META | REQ_PRIO)) | ||
| 64 | goto repeat; | 69 | goto repeat; |
| 65 | 70 | ||
| 66 | lock_page(page); | 71 | lock_page(page); |
| @@ -112,14 +117,12 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type | |||
| 112 | block_t prev_blk_addr = 0; | 117 | block_t prev_blk_addr = 0; |
| 113 | struct page *page; | 118 | struct page *page; |
| 114 | block_t blkno = start; | 119 | block_t blkno = start; |
| 115 | |||
| 116 | struct f2fs_io_info fio = { | 120 | struct f2fs_io_info fio = { |
| 117 | .type = META, | 121 | .type = META, |
| 118 | .rw = READ_SYNC | REQ_META | REQ_PRIO | 122 | .rw = READ_SYNC | REQ_META | REQ_PRIO |
| 119 | }; | 123 | }; |
| 120 | 124 | ||
| 121 | for (; nrpages-- > 0; blkno++) { | 125 | for (; nrpages-- > 0; blkno++) { |
| 122 | block_t blk_addr; | ||
| 123 | 126 | ||
| 124 | if (!is_valid_blkaddr(sbi, blkno, type)) | 127 | if (!is_valid_blkaddr(sbi, blkno, type)) |
| 125 | goto out; | 128 | goto out; |
| @@ -130,27 +133,27 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type | |||
| 130 | NAT_BLOCK_OFFSET(NM_I(sbi)->max_nid))) | 133 | NAT_BLOCK_OFFSET(NM_I(sbi)->max_nid))) |
| 131 | blkno = 0; | 134 | blkno = 0; |
| 132 | /* get nat block addr */ | 135 | /* get nat block addr */ |
| 133 | blk_addr = current_nat_addr(sbi, | 136 | fio.blk_addr = current_nat_addr(sbi, |
| 134 | blkno * NAT_ENTRY_PER_BLOCK); | 137 | blkno * NAT_ENTRY_PER_BLOCK); |
| 135 | break; | 138 | break; |
| 136 | case META_SIT: | 139 | case META_SIT: |
| 137 | /* get sit block addr */ | 140 | /* get sit block addr */ |
| 138 | blk_addr = current_sit_addr(sbi, | 141 | fio.blk_addr = current_sit_addr(sbi, |
| 139 | blkno * SIT_ENTRY_PER_BLOCK); | 142 | blkno * SIT_ENTRY_PER_BLOCK); |
| 140 | if (blkno != start && prev_blk_addr + 1 != blk_addr) | 143 | if (blkno != start && prev_blk_addr + 1 != fio.blk_addr) |
| 141 | goto out; | 144 | goto out; |
| 142 | prev_blk_addr = blk_addr; | 145 | prev_blk_addr = fio.blk_addr; |
| 143 | break; | 146 | break; |
| 144 | case META_SSA: | 147 | case META_SSA: |
| 145 | case META_CP: | 148 | case META_CP: |
| 146 | case META_POR: | 149 | case META_POR: |
| 147 | blk_addr = blkno; | 150 | fio.blk_addr = blkno; |
| 148 | break; | 151 | break; |
| 149 | default: | 152 | default: |
| 150 | BUG(); | 153 | BUG(); |
| 151 | } | 154 | } |
| 152 | 155 | ||
| 153 | page = grab_cache_page(META_MAPPING(sbi), blk_addr); | 156 | page = grab_cache_page(META_MAPPING(sbi), fio.blk_addr); |
| 154 | if (!page) | 157 | if (!page) |
| 155 | continue; | 158 | continue; |
| 156 | if (PageUptodate(page)) { | 159 | if (PageUptodate(page)) { |
| @@ -158,7 +161,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type | |||
| 158 | continue; | 161 | continue; |
| 159 | } | 162 | } |
| 160 | 163 | ||
| 161 | f2fs_submit_page_mbio(sbi, page, blk_addr, &fio); | 164 | f2fs_submit_page_mbio(sbi, page, &fio); |
| 162 | f2fs_put_page(page, 0); | 165 | f2fs_put_page(page, 0); |
| 163 | } | 166 | } |
| 164 | out: | 167 | out: |
| @@ -187,7 +190,7 @@ static int f2fs_write_meta_page(struct page *page, | |||
| 187 | 190 | ||
| 188 | trace_f2fs_writepage(page, META); | 191 | trace_f2fs_writepage(page, META); |
| 189 | 192 | ||
| 190 | if (unlikely(sbi->por_doing)) | 193 | if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) |
| 191 | goto redirty_out; | 194 | goto redirty_out; |
| 192 | if (wbc->for_reclaim && page->index < GET_SUM_BLOCK(sbi, 0)) | 195 | if (wbc->for_reclaim && page->index < GET_SUM_BLOCK(sbi, 0)) |
| 193 | goto redirty_out; | 196 | goto redirty_out; |
| @@ -299,6 +302,8 @@ static int f2fs_set_meta_page_dirty(struct page *page) | |||
| 299 | if (!PageDirty(page)) { | 302 | if (!PageDirty(page)) { |
| 300 | __set_page_dirty_nobuffers(page); | 303 | __set_page_dirty_nobuffers(page); |
| 301 | inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META); | 304 | inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META); |
| 305 | SetPagePrivate(page); | ||
| 306 | f2fs_trace_pid(page); | ||
| 302 | return 1; | 307 | return 1; |
| 303 | } | 308 | } |
| 304 | return 0; | 309 | return 0; |
| @@ -308,6 +313,8 @@ const struct address_space_operations f2fs_meta_aops = { | |||
| 308 | .writepage = f2fs_write_meta_page, | 313 | .writepage = f2fs_write_meta_page, |
| 309 | .writepages = f2fs_write_meta_pages, | 314 | .writepages = f2fs_write_meta_pages, |
| 310 | .set_page_dirty = f2fs_set_meta_page_dirty, | 315 | .set_page_dirty = f2fs_set_meta_page_dirty, |
| 316 | .invalidatepage = f2fs_invalidate_page, | ||
| 317 | .releasepage = f2fs_release_page, | ||
| 311 | }; | 318 | }; |
| 312 | 319 | ||
| 313 | static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) | 320 | static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) |
| @@ -462,7 +469,7 @@ void recover_orphan_inodes(struct f2fs_sb_info *sbi) | |||
| 462 | if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG)) | 469 | if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG)) |
| 463 | return; | 470 | return; |
| 464 | 471 | ||
| 465 | sbi->por_doing = true; | 472 | set_sbi_flag(sbi, SBI_POR_DOING); |
| 466 | 473 | ||
| 467 | start_blk = __start_cp_addr(sbi) + 1 + | 474 | start_blk = __start_cp_addr(sbi) + 1 + |
| 468 | le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload); | 475 | le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload); |
| @@ -483,7 +490,7 @@ void recover_orphan_inodes(struct f2fs_sb_info *sbi) | |||
| 483 | } | 490 | } |
| 484 | /* clear Orphan Flag */ | 491 | /* clear Orphan Flag */ |
| 485 | clear_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG); | 492 | clear_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG); |
| 486 | sbi->por_doing = false; | 493 | clear_sbi_flag(sbi, SBI_POR_DOING); |
| 487 | return; | 494 | return; |
| 488 | } | 495 | } |
| 489 | 496 | ||
| @@ -567,7 +574,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, | |||
| 567 | if (crc_offset >= blk_size) | 574 | if (crc_offset >= blk_size) |
| 568 | goto invalid_cp1; | 575 | goto invalid_cp1; |
| 569 | 576 | ||
| 570 | crc = le32_to_cpu(*((__u32 *)((unsigned char *)cp_block + crc_offset))); | 577 | crc = le32_to_cpu(*((__le32 *)((unsigned char *)cp_block + crc_offset))); |
| 571 | if (!f2fs_crc_valid(crc, cp_block, crc_offset)) | 578 | if (!f2fs_crc_valid(crc, cp_block, crc_offset)) |
| 572 | goto invalid_cp1; | 579 | goto invalid_cp1; |
| 573 | 580 | ||
| @@ -582,7 +589,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, | |||
| 582 | if (crc_offset >= blk_size) | 589 | if (crc_offset >= blk_size) |
| 583 | goto invalid_cp2; | 590 | goto invalid_cp2; |
| 584 | 591 | ||
| 585 | crc = le32_to_cpu(*((__u32 *)((unsigned char *)cp_block + crc_offset))); | 592 | crc = le32_to_cpu(*((__le32 *)((unsigned char *)cp_block + crc_offset))); |
| 586 | if (!f2fs_crc_valid(crc, cp_block, crc_offset)) | 593 | if (!f2fs_crc_valid(crc, cp_block, crc_offset)) |
| 587 | goto invalid_cp2; | 594 | goto invalid_cp2; |
| 588 | 595 | ||
| @@ -669,7 +676,7 @@ fail_no_cp: | |||
| 669 | return -EINVAL; | 676 | return -EINVAL; |
| 670 | } | 677 | } |
| 671 | 678 | ||
| 672 | static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new) | 679 | static int __add_dirty_inode(struct inode *inode, struct inode_entry *new) |
| 673 | { | 680 | { |
| 674 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | 681 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); |
| 675 | 682 | ||
| @@ -686,7 +693,7 @@ static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new) | |||
| 686 | void update_dirty_page(struct inode *inode, struct page *page) | 693 | void update_dirty_page(struct inode *inode, struct page *page) |
| 687 | { | 694 | { |
| 688 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | 695 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); |
| 689 | struct dir_inode_entry *new; | 696 | struct inode_entry *new; |
| 690 | int ret = 0; | 697 | int ret = 0; |
| 691 | 698 | ||
| 692 | if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode)) | 699 | if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode)) |
| @@ -710,12 +717,13 @@ void update_dirty_page(struct inode *inode, struct page *page) | |||
| 710 | kmem_cache_free(inode_entry_slab, new); | 717 | kmem_cache_free(inode_entry_slab, new); |
| 711 | out: | 718 | out: |
| 712 | SetPagePrivate(page); | 719 | SetPagePrivate(page); |
| 720 | f2fs_trace_pid(page); | ||
| 713 | } | 721 | } |
| 714 | 722 | ||
| 715 | void add_dirty_dir_inode(struct inode *inode) | 723 | void add_dirty_dir_inode(struct inode *inode) |
| 716 | { | 724 | { |
| 717 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | 725 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); |
| 718 | struct dir_inode_entry *new = | 726 | struct inode_entry *new = |
| 719 | f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS); | 727 | f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS); |
| 720 | int ret = 0; | 728 | int ret = 0; |
| 721 | 729 | ||
| @@ -733,7 +741,7 @@ void add_dirty_dir_inode(struct inode *inode) | |||
| 733 | void remove_dirty_dir_inode(struct inode *inode) | 741 | void remove_dirty_dir_inode(struct inode *inode) |
| 734 | { | 742 | { |
| 735 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | 743 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); |
| 736 | struct dir_inode_entry *entry; | 744 | struct inode_entry *entry; |
| 737 | 745 | ||
| 738 | if (!S_ISDIR(inode->i_mode)) | 746 | if (!S_ISDIR(inode->i_mode)) |
| 739 | return; | 747 | return; |
| @@ -763,7 +771,7 @@ void remove_dirty_dir_inode(struct inode *inode) | |||
| 763 | void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) | 771 | void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) |
| 764 | { | 772 | { |
| 765 | struct list_head *head; | 773 | struct list_head *head; |
| 766 | struct dir_inode_entry *entry; | 774 | struct inode_entry *entry; |
| 767 | struct inode *inode; | 775 | struct inode *inode; |
| 768 | retry: | 776 | retry: |
| 769 | if (unlikely(f2fs_cp_error(sbi))) | 777 | if (unlikely(f2fs_cp_error(sbi))) |
| @@ -776,7 +784,7 @@ retry: | |||
| 776 | spin_unlock(&sbi->dir_inode_lock); | 784 | spin_unlock(&sbi->dir_inode_lock); |
| 777 | return; | 785 | return; |
| 778 | } | 786 | } |
| 779 | entry = list_entry(head->next, struct dir_inode_entry, list); | 787 | entry = list_entry(head->next, struct inode_entry, list); |
| 780 | inode = igrab(entry->inode); | 788 | inode = igrab(entry->inode); |
| 781 | spin_unlock(&sbi->dir_inode_lock); | 789 | spin_unlock(&sbi->dir_inode_lock); |
| 782 | if (inode) { | 790 | if (inode) { |
| @@ -922,7 +930,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
| 922 | ckpt->next_free_nid = cpu_to_le32(last_nid); | 930 | ckpt->next_free_nid = cpu_to_le32(last_nid); |
| 923 | 931 | ||
| 924 | /* 2 cp + n data seg summary + orphan inode blocks */ | 932 | /* 2 cp + n data seg summary + orphan inode blocks */ |
| 925 | data_sum_blocks = npages_for_summary_flush(sbi); | 933 | data_sum_blocks = npages_for_summary_flush(sbi, false); |
| 926 | if (data_sum_blocks < NR_CURSEG_DATA_TYPE) | 934 | if (data_sum_blocks < NR_CURSEG_DATA_TYPE) |
| 927 | set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG); | 935 | set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG); |
| 928 | else | 936 | else |
| @@ -932,24 +940,31 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
| 932 | ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks + | 940 | ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks + |
| 933 | orphan_blocks); | 941 | orphan_blocks); |
| 934 | 942 | ||
| 935 | if (cpc->reason == CP_UMOUNT) { | 943 | if (__remain_node_summaries(cpc->reason)) |
| 936 | set_ckpt_flags(ckpt, CP_UMOUNT_FLAG); | ||
| 937 | ckpt->cp_pack_total_block_count = cpu_to_le32(F2FS_CP_PACKS+ | 944 | ckpt->cp_pack_total_block_count = cpu_to_le32(F2FS_CP_PACKS+ |
| 938 | cp_payload_blks + data_sum_blocks + | 945 | cp_payload_blks + data_sum_blocks + |
| 939 | orphan_blocks + NR_CURSEG_NODE_TYPE); | 946 | orphan_blocks + NR_CURSEG_NODE_TYPE); |
| 940 | } else { | 947 | else |
| 941 | clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG); | ||
| 942 | ckpt->cp_pack_total_block_count = cpu_to_le32(F2FS_CP_PACKS + | 948 | ckpt->cp_pack_total_block_count = cpu_to_le32(F2FS_CP_PACKS + |
| 943 | cp_payload_blks + data_sum_blocks + | 949 | cp_payload_blks + data_sum_blocks + |
| 944 | orphan_blocks); | 950 | orphan_blocks); |
| 945 | } | 951 | |
| 952 | if (cpc->reason == CP_UMOUNT) | ||
| 953 | set_ckpt_flags(ckpt, CP_UMOUNT_FLAG); | ||
| 954 | else | ||
| 955 | clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG); | ||
| 956 | |||
| 957 | if (cpc->reason == CP_FASTBOOT) | ||
| 958 | set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG); | ||
| 959 | else | ||
| 960 | clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG); | ||
| 946 | 961 | ||
| 947 | if (orphan_num) | 962 | if (orphan_num) |
| 948 | set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); | 963 | set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); |
| 949 | else | 964 | else |
| 950 | clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); | 965 | clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); |
| 951 | 966 | ||
| 952 | if (sbi->need_fsck) | 967 | if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) |
| 953 | set_ckpt_flags(ckpt, CP_FSCK_FLAG); | 968 | set_ckpt_flags(ckpt, CP_FSCK_FLAG); |
| 954 | 969 | ||
| 955 | /* update SIT/NAT bitmap */ | 970 | /* update SIT/NAT bitmap */ |
| @@ -966,15 +981,14 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
| 966 | /* write out checkpoint buffer at block 0 */ | 981 | /* write out checkpoint buffer at block 0 */ |
| 967 | cp_page = grab_meta_page(sbi, start_blk++); | 982 | cp_page = grab_meta_page(sbi, start_blk++); |
| 968 | kaddr = page_address(cp_page); | 983 | kaddr = page_address(cp_page); |
| 969 | memcpy(kaddr, ckpt, (1 << sbi->log_blocksize)); | 984 | memcpy(kaddr, ckpt, F2FS_BLKSIZE); |
| 970 | set_page_dirty(cp_page); | 985 | set_page_dirty(cp_page); |
| 971 | f2fs_put_page(cp_page, 1); | 986 | f2fs_put_page(cp_page, 1); |
| 972 | 987 | ||
| 973 | for (i = 1; i < 1 + cp_payload_blks; i++) { | 988 | for (i = 1; i < 1 + cp_payload_blks; i++) { |
| 974 | cp_page = grab_meta_page(sbi, start_blk++); | 989 | cp_page = grab_meta_page(sbi, start_blk++); |
| 975 | kaddr = page_address(cp_page); | 990 | kaddr = page_address(cp_page); |
| 976 | memcpy(kaddr, (char *)ckpt + i * F2FS_BLKSIZE, | 991 | memcpy(kaddr, (char *)ckpt + i * F2FS_BLKSIZE, F2FS_BLKSIZE); |
| 977 | (1 << sbi->log_blocksize)); | ||
| 978 | set_page_dirty(cp_page); | 992 | set_page_dirty(cp_page); |
| 979 | f2fs_put_page(cp_page, 1); | 993 | f2fs_put_page(cp_page, 1); |
| 980 | } | 994 | } |
| @@ -986,7 +1000,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
| 986 | 1000 | ||
| 987 | write_data_summaries(sbi, start_blk); | 1001 | write_data_summaries(sbi, start_blk); |
| 988 | start_blk += data_sum_blocks; | 1002 | start_blk += data_sum_blocks; |
| 989 | if (cpc->reason == CP_UMOUNT) { | 1003 | if (__remain_node_summaries(cpc->reason)) { |
| 990 | write_node_summaries(sbi, start_blk); | 1004 | write_node_summaries(sbi, start_blk); |
| 991 | start_blk += NR_CURSEG_NODE_TYPE; | 1005 | start_blk += NR_CURSEG_NODE_TYPE; |
| 992 | } | 1006 | } |
| @@ -994,7 +1008,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
| 994 | /* writeout checkpoint block */ | 1008 | /* writeout checkpoint block */ |
| 995 | cp_page = grab_meta_page(sbi, start_blk); | 1009 | cp_page = grab_meta_page(sbi, start_blk); |
| 996 | kaddr = page_address(cp_page); | 1010 | kaddr = page_address(cp_page); |
| 997 | memcpy(kaddr, ckpt, (1 << sbi->log_blocksize)); | 1011 | memcpy(kaddr, ckpt, F2FS_BLKSIZE); |
| 998 | set_page_dirty(cp_page); | 1012 | set_page_dirty(cp_page); |
| 999 | f2fs_put_page(cp_page, 1); | 1013 | f2fs_put_page(cp_page, 1); |
| 1000 | 1014 | ||
| @@ -1023,7 +1037,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
| 1023 | return; | 1037 | return; |
| 1024 | 1038 | ||
| 1025 | clear_prefree_segments(sbi); | 1039 | clear_prefree_segments(sbi); |
| 1026 | F2FS_RESET_SB_DIRT(sbi); | 1040 | clear_sbi_flag(sbi, SBI_IS_DIRTY); |
| 1027 | } | 1041 | } |
| 1028 | 1042 | ||
| 1029 | /* | 1043 | /* |
| @@ -1038,10 +1052,13 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
| 1038 | 1052 | ||
| 1039 | mutex_lock(&sbi->cp_mutex); | 1053 | mutex_lock(&sbi->cp_mutex); |
| 1040 | 1054 | ||
| 1041 | if (!sbi->s_dirty && cpc->reason != CP_DISCARD) | 1055 | if (!is_sbi_flag_set(sbi, SBI_IS_DIRTY) && |
| 1056 | cpc->reason != CP_DISCARD && cpc->reason != CP_UMOUNT) | ||
| 1042 | goto out; | 1057 | goto out; |
| 1043 | if (unlikely(f2fs_cp_error(sbi))) | 1058 | if (unlikely(f2fs_cp_error(sbi))) |
| 1044 | goto out; | 1059 | goto out; |
| 1060 | if (f2fs_readonly(sbi->sb)) | ||
| 1061 | goto out; | ||
| 1045 | if (block_operations(sbi)) | 1062 | if (block_operations(sbi)) |
| 1046 | goto out; | 1063 | goto out; |
| 1047 | 1064 | ||
| @@ -1102,8 +1119,8 @@ int __init create_checkpoint_caches(void) | |||
| 1102 | sizeof(struct ino_entry)); | 1119 | sizeof(struct ino_entry)); |
| 1103 | if (!ino_entry_slab) | 1120 | if (!ino_entry_slab) |
| 1104 | return -ENOMEM; | 1121 | return -ENOMEM; |
| 1105 | inode_entry_slab = f2fs_kmem_cache_create("f2fs_dirty_dir_entry", | 1122 | inode_entry_slab = f2fs_kmem_cache_create("f2fs_inode_entry", |
| 1106 | sizeof(struct dir_inode_entry)); | 1123 | sizeof(struct inode_entry)); |
| 1107 | if (!inode_entry_slab) { | 1124 | if (!inode_entry_slab) { |
| 1108 | kmem_cache_destroy(ino_entry_slab); | 1125 | kmem_cache_destroy(ino_entry_slab); |
| 1109 | return -ENOMEM; | 1126 | return -ENOMEM; |
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 7ec697b37f19..985ed023a750 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include "f2fs.h" | 22 | #include "f2fs.h" |
| 23 | #include "node.h" | 23 | #include "node.h" |
| 24 | #include "segment.h" | 24 | #include "segment.h" |
| 25 | #include "trace.h" | ||
| 25 | #include <trace/events/f2fs.h> | 26 | #include <trace/events/f2fs.h> |
| 26 | 27 | ||
| 27 | static void f2fs_read_end_io(struct bio *bio, int err) | 28 | static void f2fs_read_end_io(struct bio *bio, int err) |
| @@ -95,11 +96,9 @@ static void __submit_merged_bio(struct f2fs_bio_info *io) | |||
| 95 | return; | 96 | return; |
| 96 | 97 | ||
| 97 | if (is_read_io(fio->rw)) | 98 | if (is_read_io(fio->rw)) |
| 98 | trace_f2fs_submit_read_bio(io->sbi->sb, fio->rw, | 99 | trace_f2fs_submit_read_bio(io->sbi->sb, fio, io->bio); |
| 99 | fio->type, io->bio); | ||
| 100 | else | 100 | else |
| 101 | trace_f2fs_submit_write_bio(io->sbi->sb, fio->rw, | 101 | trace_f2fs_submit_write_bio(io->sbi->sb, fio, io->bio); |
| 102 | fio->type, io->bio); | ||
| 103 | 102 | ||
| 104 | submit_bio(fio->rw, io->bio); | 103 | submit_bio(fio->rw, io->bio); |
| 105 | io->bio = NULL; | 104 | io->bio = NULL; |
| @@ -132,14 +131,15 @@ void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, | |||
| 132 | * Return unlocked page. | 131 | * Return unlocked page. |
| 133 | */ | 132 | */ |
| 134 | int f2fs_submit_page_bio(struct f2fs_sb_info *sbi, struct page *page, | 133 | int f2fs_submit_page_bio(struct f2fs_sb_info *sbi, struct page *page, |
| 135 | block_t blk_addr, int rw) | 134 | struct f2fs_io_info *fio) |
| 136 | { | 135 | { |
| 137 | struct bio *bio; | 136 | struct bio *bio; |
| 138 | 137 | ||
| 139 | trace_f2fs_submit_page_bio(page, blk_addr, rw); | 138 | trace_f2fs_submit_page_bio(page, fio); |
| 139 | f2fs_trace_ios(page, fio, 0); | ||
| 140 | 140 | ||
| 141 | /* Allocate a new bio */ | 141 | /* Allocate a new bio */ |
| 142 | bio = __bio_alloc(sbi, blk_addr, 1, is_read_io(rw)); | 142 | bio = __bio_alloc(sbi, fio->blk_addr, 1, is_read_io(fio->rw)); |
| 143 | 143 | ||
| 144 | if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) { | 144 | if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) { |
| 145 | bio_put(bio); | 145 | bio_put(bio); |
| @@ -147,12 +147,12 @@ int f2fs_submit_page_bio(struct f2fs_sb_info *sbi, struct page *page, | |||
| 147 | return -EFAULT; | 147 | return -EFAULT; |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | submit_bio(rw, bio); | 150 | submit_bio(fio->rw, bio); |
| 151 | return 0; | 151 | return 0; |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | void f2fs_submit_page_mbio(struct f2fs_sb_info *sbi, struct page *page, | 154 | void f2fs_submit_page_mbio(struct f2fs_sb_info *sbi, struct page *page, |
| 155 | block_t blk_addr, struct f2fs_io_info *fio) | 155 | struct f2fs_io_info *fio) |
| 156 | { | 156 | { |
| 157 | enum page_type btype = PAGE_TYPE_OF_BIO(fio->type); | 157 | enum page_type btype = PAGE_TYPE_OF_BIO(fio->type); |
| 158 | struct f2fs_bio_info *io; | 158 | struct f2fs_bio_info *io; |
| @@ -160,21 +160,21 @@ void f2fs_submit_page_mbio(struct f2fs_sb_info *sbi, struct page *page, | |||
| 160 | 160 | ||
| 161 | io = is_read ? &sbi->read_io : &sbi->write_io[btype]; | 161 | io = is_read ? &sbi->read_io : &sbi->write_io[btype]; |
| 162 | 162 | ||
| 163 | verify_block_addr(sbi, blk_addr); | 163 | verify_block_addr(sbi, fio->blk_addr); |
| 164 | 164 | ||
| 165 | down_write(&io->io_rwsem); | 165 | down_write(&io->io_rwsem); |
| 166 | 166 | ||
| 167 | if (!is_read) | 167 | if (!is_read) |
| 168 | inc_page_count(sbi, F2FS_WRITEBACK); | 168 | inc_page_count(sbi, F2FS_WRITEBACK); |
| 169 | 169 | ||
| 170 | if (io->bio && (io->last_block_in_bio != blk_addr - 1 || | 170 | if (io->bio && (io->last_block_in_bio != fio->blk_addr - 1 || |
| 171 | io->fio.rw != fio->rw)) | 171 | io->fio.rw != fio->rw)) |
| 172 | __submit_merged_bio(io); | 172 | __submit_merged_bio(io); |
| 173 | alloc_new: | 173 | alloc_new: |
| 174 | if (io->bio == NULL) { | 174 | if (io->bio == NULL) { |
| 175 | int bio_blocks = MAX_BIO_BLOCKS(sbi); | 175 | int bio_blocks = MAX_BIO_BLOCKS(sbi); |
| 176 | 176 | ||
| 177 | io->bio = __bio_alloc(sbi, blk_addr, bio_blocks, is_read); | 177 | io->bio = __bio_alloc(sbi, fio->blk_addr, bio_blocks, is_read); |
| 178 | io->fio = *fio; | 178 | io->fio = *fio; |
| 179 | } | 179 | } |
| 180 | 180 | ||
| @@ -184,10 +184,11 @@ alloc_new: | |||
| 184 | goto alloc_new; | 184 | goto alloc_new; |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | io->last_block_in_bio = blk_addr; | 187 | io->last_block_in_bio = fio->blk_addr; |
| 188 | f2fs_trace_ios(page, fio, 0); | ||
| 188 | 189 | ||
| 189 | up_write(&io->io_rwsem); | 190 | up_write(&io->io_rwsem); |
| 190 | trace_f2fs_submit_page_mbio(page, fio->rw, fio->type, blk_addr); | 191 | trace_f2fs_submit_page_mbio(page, fio); |
| 191 | } | 192 | } |
| 192 | 193 | ||
| 193 | /* | 194 | /* |
| @@ -196,7 +197,7 @@ alloc_new: | |||
| 196 | * ->node_page | 197 | * ->node_page |
| 197 | * update block addresses in the node page | 198 | * update block addresses in the node page |
| 198 | */ | 199 | */ |
| 199 | static void __set_data_blkaddr(struct dnode_of_data *dn, block_t new_addr) | 200 | static void __set_data_blkaddr(struct dnode_of_data *dn) |
| 200 | { | 201 | { |
| 201 | struct f2fs_node *rn; | 202 | struct f2fs_node *rn; |
| 202 | __le32 *addr_array; | 203 | __le32 *addr_array; |
| @@ -209,7 +210,7 @@ static void __set_data_blkaddr(struct dnode_of_data *dn, block_t new_addr) | |||
| 209 | 210 | ||
| 210 | /* Get physical address of data block */ | 211 | /* Get physical address of data block */ |
| 211 | addr_array = blkaddr_in_node(rn); | 212 | addr_array = blkaddr_in_node(rn); |
| 212 | addr_array[ofs_in_node] = cpu_to_le32(new_addr); | 213 | addr_array[ofs_in_node] = cpu_to_le32(dn->data_blkaddr); |
| 213 | set_page_dirty(node_page); | 214 | set_page_dirty(node_page); |
| 214 | } | 215 | } |
| 215 | 216 | ||
| @@ -224,8 +225,8 @@ int reserve_new_block(struct dnode_of_data *dn) | |||
| 224 | 225 | ||
| 225 | trace_f2fs_reserve_new_block(dn->inode, dn->nid, dn->ofs_in_node); | 226 | trace_f2fs_reserve_new_block(dn->inode, dn->nid, dn->ofs_in_node); |
| 226 | 227 | ||
| 227 | __set_data_blkaddr(dn, NEW_ADDR); | ||
| 228 | dn->data_blkaddr = NEW_ADDR; | 228 | dn->data_blkaddr = NEW_ADDR; |
| 229 | __set_data_blkaddr(dn); | ||
| 229 | mark_inode_dirty(dn->inode); | 230 | mark_inode_dirty(dn->inode); |
| 230 | sync_inode_page(dn); | 231 | sync_inode_page(dn); |
| 231 | return 0; | 232 | return 0; |
| @@ -273,7 +274,7 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs, | |||
| 273 | unsigned int blkbits = inode->i_sb->s_blocksize_bits; | 274 | unsigned int blkbits = inode->i_sb->s_blocksize_bits; |
| 274 | size_t count; | 275 | size_t count; |
| 275 | 276 | ||
| 276 | clear_buffer_new(bh_result); | 277 | set_buffer_new(bh_result); |
| 277 | map_bh(bh_result, inode->i_sb, | 278 | map_bh(bh_result, inode->i_sb, |
| 278 | start_blkaddr + pgofs - start_fofs); | 279 | start_blkaddr + pgofs - start_fofs); |
| 279 | count = end_fofs - pgofs + 1; | 280 | count = end_fofs - pgofs + 1; |
| @@ -290,23 +291,24 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs, | |||
| 290 | return 0; | 291 | return 0; |
| 291 | } | 292 | } |
| 292 | 293 | ||
| 293 | void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn) | 294 | void update_extent_cache(struct dnode_of_data *dn) |
| 294 | { | 295 | { |
| 295 | struct f2fs_inode_info *fi = F2FS_I(dn->inode); | 296 | struct f2fs_inode_info *fi = F2FS_I(dn->inode); |
| 296 | pgoff_t fofs, start_fofs, end_fofs; | 297 | pgoff_t fofs, start_fofs, end_fofs; |
| 297 | block_t start_blkaddr, end_blkaddr; | 298 | block_t start_blkaddr, end_blkaddr; |
| 298 | int need_update = true; | 299 | int need_update = true; |
| 299 | 300 | ||
| 300 | f2fs_bug_on(F2FS_I_SB(dn->inode), blk_addr == NEW_ADDR); | 301 | f2fs_bug_on(F2FS_I_SB(dn->inode), dn->data_blkaddr == NEW_ADDR); |
| 301 | fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) + | ||
| 302 | dn->ofs_in_node; | ||
| 303 | 302 | ||
| 304 | /* Update the page address in the parent node */ | 303 | /* Update the page address in the parent node */ |
| 305 | __set_data_blkaddr(dn, blk_addr); | 304 | __set_data_blkaddr(dn); |
| 306 | 305 | ||
| 307 | if (is_inode_flag_set(fi, FI_NO_EXTENT)) | 306 | if (is_inode_flag_set(fi, FI_NO_EXTENT)) |
| 308 | return; | 307 | return; |
| 309 | 308 | ||
| 309 | fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) + | ||
| 310 | dn->ofs_in_node; | ||
| 311 | |||
| 310 | write_lock(&fi->ext.ext_lock); | 312 | write_lock(&fi->ext.ext_lock); |
| 311 | 313 | ||
| 312 | start_fofs = fi->ext.fofs; | 314 | start_fofs = fi->ext.fofs; |
| @@ -320,16 +322,16 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn) | |||
| 320 | 322 | ||
| 321 | /* Initial extent */ | 323 | /* Initial extent */ |
| 322 | if (fi->ext.len == 0) { | 324 | if (fi->ext.len == 0) { |
| 323 | if (blk_addr != NULL_ADDR) { | 325 | if (dn->data_blkaddr != NULL_ADDR) { |
| 324 | fi->ext.fofs = fofs; | 326 | fi->ext.fofs = fofs; |
| 325 | fi->ext.blk_addr = blk_addr; | 327 | fi->ext.blk_addr = dn->data_blkaddr; |
| 326 | fi->ext.len = 1; | 328 | fi->ext.len = 1; |
| 327 | } | 329 | } |
| 328 | goto end_update; | 330 | goto end_update; |
| 329 | } | 331 | } |
| 330 | 332 | ||
| 331 | /* Front merge */ | 333 | /* Front merge */ |
| 332 | if (fofs == start_fofs - 1 && blk_addr == start_blkaddr - 1) { | 334 | if (fofs == start_fofs - 1 && dn->data_blkaddr == start_blkaddr - 1) { |
| 333 | fi->ext.fofs--; | 335 | fi->ext.fofs--; |
| 334 | fi->ext.blk_addr--; | 336 | fi->ext.blk_addr--; |
| 335 | fi->ext.len++; | 337 | fi->ext.len++; |
| @@ -337,7 +339,7 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn) | |||
| 337 | } | 339 | } |
| 338 | 340 | ||
| 339 | /* Back merge */ | 341 | /* Back merge */ |
| 340 | if (fofs == end_fofs + 1 && blk_addr == end_blkaddr + 1) { | 342 | if (fofs == end_fofs + 1 && dn->data_blkaddr == end_blkaddr + 1) { |
| 341 | fi->ext.len++; | 343 | fi->ext.len++; |
| 342 | goto end_update; | 344 | goto end_update; |
| 343 | } | 345 | } |
| @@ -376,6 +378,10 @@ struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync) | |||
| 376 | struct dnode_of_data dn; | 378 | struct dnode_of_data dn; |
| 377 | struct page *page; | 379 | struct page *page; |
| 378 | int err; | 380 | int err; |
| 381 | struct f2fs_io_info fio = { | ||
| 382 | .type = DATA, | ||
| 383 | .rw = sync ? READ_SYNC : READA, | ||
| 384 | }; | ||
| 379 | 385 | ||
| 380 | page = find_get_page(mapping, index); | 386 | page = find_get_page(mapping, index); |
| 381 | if (page && PageUptodate(page)) | 387 | if (page && PageUptodate(page)) |
| @@ -404,8 +410,8 @@ struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync) | |||
| 404 | return page; | 410 | return page; |
| 405 | } | 411 | } |
| 406 | 412 | ||
| 407 | err = f2fs_submit_page_bio(F2FS_I_SB(inode), page, dn.data_blkaddr, | 413 | fio.blk_addr = dn.data_blkaddr; |
| 408 | sync ? READ_SYNC : READA); | 414 | err = f2fs_submit_page_bio(F2FS_I_SB(inode), page, &fio); |
| 409 | if (err) | 415 | if (err) |
| 410 | return ERR_PTR(err); | 416 | return ERR_PTR(err); |
| 411 | 417 | ||
| @@ -430,7 +436,10 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index) | |||
| 430 | struct dnode_of_data dn; | 436 | struct dnode_of_data dn; |
| 431 | struct page *page; | 437 | struct page *page; |
| 432 | int err; | 438 | int err; |
| 433 | 439 | struct f2fs_io_info fio = { | |
| 440 | .type = DATA, | ||
| 441 | .rw = READ_SYNC, | ||
| 442 | }; | ||
| 434 | repeat: | 443 | repeat: |
| 435 | page = grab_cache_page(mapping, index); | 444 | page = grab_cache_page(mapping, index); |
| 436 | if (!page) | 445 | if (!page) |
| @@ -464,8 +473,8 @@ repeat: | |||
| 464 | return page; | 473 | return page; |
| 465 | } | 474 | } |
| 466 | 475 | ||
| 467 | err = f2fs_submit_page_bio(F2FS_I_SB(inode), page, | 476 | fio.blk_addr = dn.data_blkaddr; |
| 468 | dn.data_blkaddr, READ_SYNC); | 477 | err = f2fs_submit_page_bio(F2FS_I_SB(inode), page, &fio); |
| 469 | if (err) | 478 | if (err) |
| 470 | return ERR_PTR(err); | 479 | return ERR_PTR(err); |
| 471 | 480 | ||
| @@ -515,8 +524,12 @@ repeat: | |||
| 515 | zero_user_segment(page, 0, PAGE_CACHE_SIZE); | 524 | zero_user_segment(page, 0, PAGE_CACHE_SIZE); |
| 516 | SetPageUptodate(page); | 525 | SetPageUptodate(page); |
| 517 | } else { | 526 | } else { |
| 518 | err = f2fs_submit_page_bio(F2FS_I_SB(inode), page, | 527 | struct f2fs_io_info fio = { |
| 519 | dn.data_blkaddr, READ_SYNC); | 528 | .type = DATA, |
| 529 | .rw = READ_SYNC, | ||
| 530 | .blk_addr = dn.data_blkaddr, | ||
| 531 | }; | ||
| 532 | err = f2fs_submit_page_bio(F2FS_I_SB(inode), page, &fio); | ||
| 520 | if (err) | 533 | if (err) |
| 521 | goto put_err; | 534 | goto put_err; |
| 522 | 535 | ||
| @@ -550,30 +563,25 @@ static int __allocate_data_block(struct dnode_of_data *dn) | |||
| 550 | struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); | 563 | struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); |
| 551 | struct f2fs_inode_info *fi = F2FS_I(dn->inode); | 564 | struct f2fs_inode_info *fi = F2FS_I(dn->inode); |
| 552 | struct f2fs_summary sum; | 565 | struct f2fs_summary sum; |
| 553 | block_t new_blkaddr; | ||
| 554 | struct node_info ni; | 566 | struct node_info ni; |
| 567 | int seg = CURSEG_WARM_DATA; | ||
| 555 | pgoff_t fofs; | 568 | pgoff_t fofs; |
| 556 | int type; | ||
| 557 | 569 | ||
| 558 | if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC))) | 570 | if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC))) |
| 559 | return -EPERM; | 571 | return -EPERM; |
| 560 | if (unlikely(!inc_valid_block_count(sbi, dn->inode, 1))) | 572 | if (unlikely(!inc_valid_block_count(sbi, dn->inode, 1))) |
| 561 | return -ENOSPC; | 573 | return -ENOSPC; |
| 562 | 574 | ||
| 563 | __set_data_blkaddr(dn, NEW_ADDR); | ||
| 564 | dn->data_blkaddr = NEW_ADDR; | ||
| 565 | |||
| 566 | get_node_info(sbi, dn->nid, &ni); | 575 | get_node_info(sbi, dn->nid, &ni); |
| 567 | set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); | 576 | set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); |
| 568 | 577 | ||
| 569 | type = CURSEG_WARM_DATA; | 578 | if (dn->ofs_in_node == 0 && dn->inode_page == dn->node_page) |
| 579 | seg = CURSEG_DIRECT_IO; | ||
| 570 | 580 | ||
| 571 | allocate_data_block(sbi, NULL, NULL_ADDR, &new_blkaddr, &sum, type); | 581 | allocate_data_block(sbi, NULL, NULL_ADDR, &dn->data_blkaddr, &sum, seg); |
| 572 | 582 | ||
| 573 | /* direct IO doesn't use extent cache to maximize the performance */ | 583 | /* direct IO doesn't use extent cache to maximize the performance */ |
| 574 | set_inode_flag(F2FS_I(dn->inode), FI_NO_EXTENT); | 584 | __set_data_blkaddr(dn); |
| 575 | update_extent_cache(new_blkaddr, dn); | ||
| 576 | clear_inode_flag(F2FS_I(dn->inode), FI_NO_EXTENT); | ||
| 577 | 585 | ||
| 578 | /* update i_size */ | 586 | /* update i_size */ |
| 579 | fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) + | 587 | fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) + |
| @@ -581,10 +589,59 @@ static int __allocate_data_block(struct dnode_of_data *dn) | |||
| 581 | if (i_size_read(dn->inode) < ((fofs + 1) << PAGE_CACHE_SHIFT)) | 589 | if (i_size_read(dn->inode) < ((fofs + 1) << PAGE_CACHE_SHIFT)) |
| 582 | i_size_write(dn->inode, ((fofs + 1) << PAGE_CACHE_SHIFT)); | 590 | i_size_write(dn->inode, ((fofs + 1) << PAGE_CACHE_SHIFT)); |
| 583 | 591 | ||
| 584 | dn->data_blkaddr = new_blkaddr; | ||
| 585 | return 0; | 592 | return 0; |
| 586 | } | 593 | } |
| 587 | 594 | ||
| 595 | static void __allocate_data_blocks(struct inode *inode, loff_t offset, | ||
| 596 | size_t count) | ||
| 597 | { | ||
| 598 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | ||
| 599 | struct dnode_of_data dn; | ||
| 600 | u64 start = F2FS_BYTES_TO_BLK(offset); | ||
| 601 | u64 len = F2FS_BYTES_TO_BLK(count); | ||
| 602 | bool allocated; | ||
| 603 | u64 end_offset; | ||
| 604 | |||
| 605 | while (len) { | ||
| 606 | f2fs_balance_fs(sbi); | ||
| 607 | f2fs_lock_op(sbi); | ||
| 608 | |||
| 609 | /* When reading holes, we need its node page */ | ||
| 610 | set_new_dnode(&dn, inode, NULL, NULL, 0); | ||
| 611 | if (get_dnode_of_data(&dn, start, ALLOC_NODE)) | ||
| 612 | goto out; | ||
| 613 | |||
| 614 | allocated = false; | ||
| 615 | end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); | ||
| 616 | |||
| 617 | while (dn.ofs_in_node < end_offset && len) { | ||
| 618 | if (dn.data_blkaddr == NULL_ADDR) { | ||
| 619 | if (__allocate_data_block(&dn)) | ||
| 620 | goto sync_out; | ||
| 621 | allocated = true; | ||
| 622 | } | ||
| 623 | len--; | ||
| 624 | start++; | ||
| 625 | dn.ofs_in_node++; | ||
| 626 | } | ||
| 627 | |||
| 628 | if (allocated) | ||
| 629 | sync_inode_page(&dn); | ||
| 630 | |||
| 631 | f2fs_put_dnode(&dn); | ||
| 632 | f2fs_unlock_op(sbi); | ||
| 633 | } | ||
| 634 | return; | ||
| 635 | |||
| 636 | sync_out: | ||
| 637 | if (allocated) | ||
| 638 | sync_inode_page(&dn); | ||
| 639 | f2fs_put_dnode(&dn); | ||
| 640 | out: | ||
| 641 | f2fs_unlock_op(sbi); | ||
| 642 | return; | ||
| 643 | } | ||
| 644 | |||
| 588 | /* | 645 | /* |
| 589 | * get_data_block() now supported readahead/bmap/rw direct_IO with mapped bh. | 646 | * get_data_block() now supported readahead/bmap/rw direct_IO with mapped bh. |
| 590 | * If original data blocks are allocated, then give them to blockdev. | 647 | * If original data blocks are allocated, then give them to blockdev. |
| @@ -610,10 +667,8 @@ static int __get_data_block(struct inode *inode, sector_t iblock, | |||
| 610 | if (check_extent_cache(inode, pgofs, bh_result)) | 667 | if (check_extent_cache(inode, pgofs, bh_result)) |
| 611 | goto out; | 668 | goto out; |
| 612 | 669 | ||
| 613 | if (create) { | 670 | if (create) |
| 614 | f2fs_balance_fs(F2FS_I_SB(inode)); | ||
| 615 | f2fs_lock_op(F2FS_I_SB(inode)); | 671 | f2fs_lock_op(F2FS_I_SB(inode)); |
| 616 | } | ||
| 617 | 672 | ||
| 618 | /* When reading holes, we need its node page */ | 673 | /* When reading holes, we need its node page */ |
| 619 | set_new_dnode(&dn, inode, NULL, NULL, 0); | 674 | set_new_dnode(&dn, inode, NULL, NULL, 0); |
| @@ -627,12 +682,14 @@ static int __get_data_block(struct inode *inode, sector_t iblock, | |||
| 627 | goto put_out; | 682 | goto put_out; |
| 628 | 683 | ||
| 629 | if (dn.data_blkaddr != NULL_ADDR) { | 684 | if (dn.data_blkaddr != NULL_ADDR) { |
| 685 | set_buffer_new(bh_result); | ||
| 630 | map_bh(bh_result, inode->i_sb, dn.data_blkaddr); | 686 | map_bh(bh_result, inode->i_sb, dn.data_blkaddr); |
| 631 | } else if (create) { | 687 | } else if (create) { |
| 632 | err = __allocate_data_block(&dn); | 688 | err = __allocate_data_block(&dn); |
| 633 | if (err) | 689 | if (err) |
| 634 | goto put_out; | 690 | goto put_out; |
| 635 | allocated = true; | 691 | allocated = true; |
| 692 | set_buffer_new(bh_result); | ||
| 636 | map_bh(bh_result, inode->i_sb, dn.data_blkaddr); | 693 | map_bh(bh_result, inode->i_sb, dn.data_blkaddr); |
| 637 | } else { | 694 | } else { |
| 638 | goto put_out; | 695 | goto put_out; |
| @@ -745,7 +802,6 @@ static int f2fs_read_data_pages(struct file *file, | |||
| 745 | int do_write_data_page(struct page *page, struct f2fs_io_info *fio) | 802 | int do_write_data_page(struct page *page, struct f2fs_io_info *fio) |
| 746 | { | 803 | { |
| 747 | struct inode *inode = page->mapping->host; | 804 | struct inode *inode = page->mapping->host; |
| 748 | block_t old_blkaddr, new_blkaddr; | ||
| 749 | struct dnode_of_data dn; | 805 | struct dnode_of_data dn; |
| 750 | int err = 0; | 806 | int err = 0; |
| 751 | 807 | ||
| @@ -754,10 +810,10 @@ int do_write_data_page(struct page *page, struct f2fs_io_info *fio) | |||
| 754 | if (err) | 810 | if (err) |
| 755 | return err; | 811 | return err; |
| 756 | 812 | ||
| 757 | old_blkaddr = dn.data_blkaddr; | 813 | fio->blk_addr = dn.data_blkaddr; |
| 758 | 814 | ||
| 759 | /* This page is already truncated */ | 815 | /* This page is already truncated */ |
| 760 | if (old_blkaddr == NULL_ADDR) | 816 | if (fio->blk_addr == NULL_ADDR) |
| 761 | goto out_writepage; | 817 | goto out_writepage; |
| 762 | 818 | ||
| 763 | set_page_writeback(page); | 819 | set_page_writeback(page); |
| @@ -766,14 +822,14 @@ int do_write_data_page(struct page *page, struct f2fs_io_info *fio) | |||
| 766 | * If current allocation needs SSR, | 822 | * If current allocation needs SSR, |
| 767 | * it had better in-place writes for updated data. | 823 | * it had better in-place writes for updated data. |
| 768 | */ | 824 | */ |
| 769 | if (unlikely(old_blkaddr != NEW_ADDR && | 825 | if (unlikely(fio->blk_addr != NEW_ADDR && |
| 770 | !is_cold_data(page) && | 826 | !is_cold_data(page) && |
| 771 | need_inplace_update(inode))) { | 827 | need_inplace_update(inode))) { |
| 772 | rewrite_data_page(page, old_blkaddr, fio); | 828 | rewrite_data_page(page, fio); |
| 773 | set_inode_flag(F2FS_I(inode), FI_UPDATE_WRITE); | 829 | set_inode_flag(F2FS_I(inode), FI_UPDATE_WRITE); |
| 774 | } else { | 830 | } else { |
| 775 | write_data_page(page, &dn, &new_blkaddr, fio); | 831 | write_data_page(page, &dn, fio); |
| 776 | update_extent_cache(new_blkaddr, &dn); | 832 | update_extent_cache(&dn); |
| 777 | set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE); | 833 | set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE); |
| 778 | } | 834 | } |
| 779 | out_writepage: | 835 | out_writepage: |
| @@ -812,7 +868,12 @@ static int f2fs_write_data_page(struct page *page, | |||
| 812 | 868 | ||
| 813 | zero_user_segment(page, offset, PAGE_CACHE_SIZE); | 869 | zero_user_segment(page, offset, PAGE_CACHE_SIZE); |
| 814 | write: | 870 | write: |
| 815 | if (unlikely(sbi->por_doing)) | 871 | if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) |
| 872 | goto redirty_out; | ||
| 873 | if (f2fs_is_drop_cache(inode)) | ||
| 874 | goto out; | ||
| 875 | if (f2fs_is_volatile_file(inode) && !wbc->for_reclaim && | ||
| 876 | available_free_memory(sbi, BASE_CHECK)) | ||
| 816 | goto redirty_out; | 877 | goto redirty_out; |
| 817 | 878 | ||
| 818 | /* Dentry blocks are controlled by checkpoint */ | 879 | /* Dentry blocks are controlled by checkpoint */ |
| @@ -826,7 +887,6 @@ write: | |||
| 826 | /* we should bypass data pages to proceed the kworkder jobs */ | 887 | /* we should bypass data pages to proceed the kworkder jobs */ |
| 827 | if (unlikely(f2fs_cp_error(sbi))) { | 888 | if (unlikely(f2fs_cp_error(sbi))) { |
| 828 | SetPageError(page); | 889 | SetPageError(page); |
| 829 | unlock_page(page); | ||
| 830 | goto out; | 890 | goto out; |
| 831 | } | 891 | } |
| 832 | 892 | ||
| @@ -1002,8 +1062,12 @@ put_next: | |||
| 1002 | if (dn.data_blkaddr == NEW_ADDR) { | 1062 | if (dn.data_blkaddr == NEW_ADDR) { |
| 1003 | zero_user_segment(page, 0, PAGE_CACHE_SIZE); | 1063 | zero_user_segment(page, 0, PAGE_CACHE_SIZE); |
| 1004 | } else { | 1064 | } else { |
| 1005 | err = f2fs_submit_page_bio(sbi, page, dn.data_blkaddr, | 1065 | struct f2fs_io_info fio = { |
| 1006 | READ_SYNC); | 1066 | .type = DATA, |
| 1067 | .rw = READ_SYNC, | ||
| 1068 | .blk_addr = dn.data_blkaddr, | ||
| 1069 | }; | ||
| 1070 | err = f2fs_submit_page_bio(sbi, page, &fio); | ||
| 1007 | if (err) | 1071 | if (err) |
| 1008 | goto fail; | 1072 | goto fail; |
| 1009 | 1073 | ||
| @@ -1092,6 +1156,9 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, | |||
| 1092 | 1156 | ||
| 1093 | trace_f2fs_direct_IO_enter(inode, offset, count, rw); | 1157 | trace_f2fs_direct_IO_enter(inode, offset, count, rw); |
| 1094 | 1158 | ||
| 1159 | if (rw & WRITE) | ||
| 1160 | __allocate_data_blocks(inode, offset, count); | ||
| 1161 | |||
| 1095 | err = blockdev_direct_IO(rw, iocb, inode, iter, offset, get_data_block); | 1162 | err = blockdev_direct_IO(rw, iocb, inode, iter, offset, get_data_block); |
| 1096 | if (err < 0 && (rw & WRITE)) | 1163 | if (err < 0 && (rw & WRITE)) |
| 1097 | f2fs_write_failed(mapping, offset + count); | 1164 | f2fs_write_failed(mapping, offset + count); |
| @@ -1101,24 +1168,33 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, | |||
| 1101 | return err; | 1168 | return err; |
| 1102 | } | 1169 | } |
| 1103 | 1170 | ||
| 1104 | static void f2fs_invalidate_data_page(struct page *page, unsigned int offset, | 1171 | void f2fs_invalidate_page(struct page *page, unsigned int offset, |
| 1105 | unsigned int length) | 1172 | unsigned int length) |
| 1106 | { | 1173 | { |
| 1107 | struct inode *inode = page->mapping->host; | 1174 | struct inode *inode = page->mapping->host; |
| 1175 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | ||
| 1108 | 1176 | ||
| 1109 | if (offset % PAGE_CACHE_SIZE || length != PAGE_CACHE_SIZE) | 1177 | if (inode->i_ino >= F2FS_ROOT_INO(sbi) && |
| 1178 | (offset % PAGE_CACHE_SIZE || length != PAGE_CACHE_SIZE)) | ||
| 1110 | return; | 1179 | return; |
| 1111 | 1180 | ||
| 1112 | if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) | 1181 | if (PageDirty(page)) { |
| 1113 | invalidate_inmem_page(inode, page); | 1182 | if (inode->i_ino == F2FS_META_INO(sbi)) |
| 1114 | 1183 | dec_page_count(sbi, F2FS_DIRTY_META); | |
| 1115 | if (PageDirty(page)) | 1184 | else if (inode->i_ino == F2FS_NODE_INO(sbi)) |
| 1116 | inode_dec_dirty_pages(inode); | 1185 | dec_page_count(sbi, F2FS_DIRTY_NODES); |
| 1186 | else | ||
| 1187 | inode_dec_dirty_pages(inode); | ||
| 1188 | } | ||
| 1117 | ClearPagePrivate(page); | 1189 | ClearPagePrivate(page); |
| 1118 | } | 1190 | } |
| 1119 | 1191 | ||
| 1120 | static int f2fs_release_data_page(struct page *page, gfp_t wait) | 1192 | int f2fs_release_page(struct page *page, gfp_t wait) |
| 1121 | { | 1193 | { |
| 1194 | /* If this is dirty page, keep PagePrivate */ | ||
| 1195 | if (PageDirty(page)) | ||
| 1196 | return 0; | ||
| 1197 | |||
| 1122 | ClearPagePrivate(page); | 1198 | ClearPagePrivate(page); |
| 1123 | return 1; | 1199 | return 1; |
| 1124 | } | 1200 | } |
| @@ -1132,7 +1208,7 @@ static int f2fs_set_data_page_dirty(struct page *page) | |||
| 1132 | 1208 | ||
| 1133 | SetPageUptodate(page); | 1209 | SetPageUptodate(page); |
| 1134 | 1210 | ||
| 1135 | if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) { | 1211 | if (f2fs_is_atomic_file(inode)) { |
| 1136 | register_inmem_page(inode, page); | 1212 | register_inmem_page(inode, page); |
| 1137 | return 1; | 1213 | return 1; |
| 1138 | } | 1214 | } |
| @@ -1168,8 +1244,8 @@ const struct address_space_operations f2fs_dblock_aops = { | |||
| 1168 | .write_begin = f2fs_write_begin, | 1244 | .write_begin = f2fs_write_begin, |
| 1169 | .write_end = f2fs_write_end, | 1245 | .write_end = f2fs_write_end, |
| 1170 | .set_page_dirty = f2fs_set_data_page_dirty, | 1246 | .set_page_dirty = f2fs_set_data_page_dirty, |
| 1171 | .invalidatepage = f2fs_invalidate_data_page, | 1247 | .invalidatepage = f2fs_invalidate_page, |
| 1172 | .releasepage = f2fs_release_data_page, | 1248 | .releasepage = f2fs_release_page, |
| 1173 | .direct_IO = f2fs_direct_IO, | 1249 | .direct_IO = f2fs_direct_IO, |
| 1174 | .bmap = f2fs_bmap, | 1250 | .bmap = f2fs_bmap, |
| 1175 | }; | 1251 | }; |
diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index 91e8f699ab30..e671373cc8ab 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c | |||
| @@ -40,6 +40,7 @@ static void update_general_status(struct f2fs_sb_info *sbi) | |||
| 40 | si->ndirty_dirs = sbi->n_dirty_dirs; | 40 | si->ndirty_dirs = sbi->n_dirty_dirs; |
| 41 | si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META); | 41 | si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META); |
| 42 | si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES); | 42 | si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES); |
| 43 | si->wb_pages = get_pages(sbi, F2FS_WRITEBACK); | ||
| 43 | si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg; | 44 | si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg; |
| 44 | si->rsvd_segs = reserved_segments(sbi); | 45 | si->rsvd_segs = reserved_segments(sbi); |
| 45 | si->overp_segs = overprovision_segments(sbi); | 46 | si->overp_segs = overprovision_segments(sbi); |
| @@ -57,7 +58,9 @@ static void update_general_status(struct f2fs_sb_info *sbi) | |||
| 57 | si->node_pages = NODE_MAPPING(sbi)->nrpages; | 58 | si->node_pages = NODE_MAPPING(sbi)->nrpages; |
| 58 | si->meta_pages = META_MAPPING(sbi)->nrpages; | 59 | si->meta_pages = META_MAPPING(sbi)->nrpages; |
| 59 | si->nats = NM_I(sbi)->nat_cnt; | 60 | si->nats = NM_I(sbi)->nat_cnt; |
| 60 | si->sits = SIT_I(sbi)->dirty_sentries; | 61 | si->dirty_nats = NM_I(sbi)->dirty_nat_cnt; |
| 62 | si->sits = MAIN_SEGS(sbi); | ||
| 63 | si->dirty_sits = SIT_I(sbi)->dirty_sentries; | ||
| 61 | si->fnids = NM_I(sbi)->fcnt; | 64 | si->fnids = NM_I(sbi)->fcnt; |
| 62 | si->bg_gc = sbi->bg_gc; | 65 | si->bg_gc = sbi->bg_gc; |
| 63 | si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg) | 66 | si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg) |
| @@ -79,6 +82,8 @@ static void update_general_status(struct f2fs_sb_info *sbi) | |||
| 79 | si->segment_count[i] = sbi->segment_count[i]; | 82 | si->segment_count[i] = sbi->segment_count[i]; |
| 80 | si->block_count[i] = sbi->block_count[i]; | 83 | si->block_count[i] = sbi->block_count[i]; |
| 81 | } | 84 | } |
| 85 | |||
| 86 | si->inplace_count = atomic_read(&sbi->inplace_count); | ||
| 82 | } | 87 | } |
| 83 | 88 | ||
| 84 | /* | 89 | /* |
| @@ -137,6 +142,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi) | |||
| 137 | si->base_mem += MAIN_SEGS(sbi) * sizeof(struct seg_entry); | 142 | si->base_mem += MAIN_SEGS(sbi) * sizeof(struct seg_entry); |
| 138 | si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi)); | 143 | si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi)); |
| 139 | si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi); | 144 | si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi); |
| 145 | si->base_mem += SIT_VBLOCK_MAP_SIZE; | ||
| 140 | if (sbi->segs_per_sec > 1) | 146 | if (sbi->segs_per_sec > 1) |
| 141 | si->base_mem += MAIN_SECS(sbi) * sizeof(struct sec_entry); | 147 | si->base_mem += MAIN_SECS(sbi) * sizeof(struct sec_entry); |
| 142 | si->base_mem += __bitmap_size(sbi, SIT_BITMAP); | 148 | si->base_mem += __bitmap_size(sbi, SIT_BITMAP); |
| @@ -159,20 +165,32 @@ static void update_mem_info(struct f2fs_sb_info *sbi) | |||
| 159 | si->base_mem += sizeof(struct f2fs_nm_info); | 165 | si->base_mem += sizeof(struct f2fs_nm_info); |
| 160 | si->base_mem += __bitmap_size(sbi, NAT_BITMAP); | 166 | si->base_mem += __bitmap_size(sbi, NAT_BITMAP); |
| 161 | 167 | ||
| 168 | get_cache: | ||
| 169 | si->cache_mem = 0; | ||
| 170 | |||
| 162 | /* build gc */ | 171 | /* build gc */ |
| 163 | si->base_mem += sizeof(struct f2fs_gc_kthread); | 172 | if (sbi->gc_thread) |
| 173 | si->cache_mem += sizeof(struct f2fs_gc_kthread); | ||
| 174 | |||
| 175 | /* build merge flush thread */ | ||
| 176 | if (SM_I(sbi)->cmd_control_info) | ||
| 177 | si->cache_mem += sizeof(struct flush_cmd_control); | ||
| 164 | 178 | ||
| 165 | get_cache: | ||
| 166 | /* free nids */ | 179 | /* free nids */ |
| 167 | si->cache_mem = NM_I(sbi)->fcnt; | 180 | si->cache_mem += NM_I(sbi)->fcnt * sizeof(struct free_nid); |
| 168 | si->cache_mem += NM_I(sbi)->nat_cnt; | 181 | si->cache_mem += NM_I(sbi)->nat_cnt * sizeof(struct nat_entry); |
| 169 | npages = NODE_MAPPING(sbi)->nrpages; | 182 | si->cache_mem += NM_I(sbi)->dirty_nat_cnt * |
| 170 | si->cache_mem += npages << PAGE_CACHE_SHIFT; | 183 | sizeof(struct nat_entry_set); |
| 171 | npages = META_MAPPING(sbi)->nrpages; | 184 | si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages); |
| 172 | si->cache_mem += npages << PAGE_CACHE_SHIFT; | 185 | si->cache_mem += sbi->n_dirty_dirs * sizeof(struct inode_entry); |
| 173 | si->cache_mem += sbi->n_dirty_dirs * sizeof(struct dir_inode_entry); | ||
| 174 | for (i = 0; i <= UPDATE_INO; i++) | 186 | for (i = 0; i <= UPDATE_INO; i++) |
| 175 | si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry); | 187 | si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry); |
| 188 | |||
| 189 | si->page_mem = 0; | ||
| 190 | npages = NODE_MAPPING(sbi)->nrpages; | ||
| 191 | si->page_mem += npages << PAGE_CACHE_SHIFT; | ||
| 192 | npages = META_MAPPING(sbi)->nrpages; | ||
| 193 | si->page_mem += npages << PAGE_CACHE_SHIFT; | ||
| 176 | } | 194 | } |
| 177 | 195 | ||
| 178 | static int stat_show(struct seq_file *s, void *v) | 196 | static int stat_show(struct seq_file *s, void *v) |
| @@ -250,16 +268,16 @@ static int stat_show(struct seq_file *s, void *v) | |||
| 250 | seq_printf(s, "\nExtent Hit Ratio: %d / %d\n", | 268 | seq_printf(s, "\nExtent Hit Ratio: %d / %d\n", |
| 251 | si->hit_ext, si->total_ext); | 269 | si->hit_ext, si->total_ext); |
| 252 | seq_puts(s, "\nBalancing F2FS Async:\n"); | 270 | seq_puts(s, "\nBalancing F2FS Async:\n"); |
| 253 | seq_printf(s, " - inmem: %4d\n", | 271 | seq_printf(s, " - inmem: %4d, wb: %4d\n", |
| 254 | si->inmem_pages); | 272 | si->inmem_pages, si->wb_pages); |
| 255 | seq_printf(s, " - nodes: %4d in %4d\n", | 273 | seq_printf(s, " - nodes: %4d in %4d\n", |
| 256 | si->ndirty_node, si->node_pages); | 274 | si->ndirty_node, si->node_pages); |
| 257 | seq_printf(s, " - dents: %4d in dirs:%4d\n", | 275 | seq_printf(s, " - dents: %4d in dirs:%4d\n", |
| 258 | si->ndirty_dent, si->ndirty_dirs); | 276 | si->ndirty_dent, si->ndirty_dirs); |
| 259 | seq_printf(s, " - meta: %4d in %4d\n", | 277 | seq_printf(s, " - meta: %4d in %4d\n", |
| 260 | si->ndirty_meta, si->meta_pages); | 278 | si->ndirty_meta, si->meta_pages); |
| 261 | seq_printf(s, " - NATs: %9d\n - SITs: %9d\n", | 279 | seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n", |
| 262 | si->nats, si->sits); | 280 | si->dirty_nats, si->nats, si->dirty_sits, si->sits); |
| 263 | seq_printf(s, " - free_nids: %9d\n", | 281 | seq_printf(s, " - free_nids: %9d\n", |
| 264 | si->fnids); | 282 | si->fnids); |
| 265 | seq_puts(s, "\nDistribution of User Blocks:"); | 283 | seq_puts(s, "\nDistribution of User Blocks:"); |
| @@ -277,6 +295,7 @@ static int stat_show(struct seq_file *s, void *v) | |||
| 277 | for (j = 0; j < si->util_free; j++) | 295 | for (j = 0; j < si->util_free; j++) |
| 278 | seq_putc(s, '-'); | 296 | seq_putc(s, '-'); |
| 279 | seq_puts(s, "]\n\n"); | 297 | seq_puts(s, "]\n\n"); |
| 298 | seq_printf(s, "IPU: %u blocks\n", si->inplace_count); | ||
| 280 | seq_printf(s, "SSR: %u blocks in %u segments\n", | 299 | seq_printf(s, "SSR: %u blocks in %u segments\n", |
| 281 | si->block_count[SSR], si->segment_count[SSR]); | 300 | si->block_count[SSR], si->segment_count[SSR]); |
| 282 | seq_printf(s, "LFS: %u blocks in %u segments\n", | 301 | seq_printf(s, "LFS: %u blocks in %u segments\n", |
| @@ -289,9 +308,14 @@ static int stat_show(struct seq_file *s, void *v) | |||
| 289 | 308 | ||
| 290 | /* memory footprint */ | 309 | /* memory footprint */ |
| 291 | update_mem_info(si->sbi); | 310 | update_mem_info(si->sbi); |
| 292 | seq_printf(s, "\nMemory: %u KB = static: %u + cached: %u\n", | 311 | seq_printf(s, "\nMemory: %u KB\n", |
| 293 | (si->base_mem + si->cache_mem) >> 10, | 312 | (si->base_mem + si->cache_mem + si->page_mem) >> 10); |
| 294 | si->base_mem >> 10, si->cache_mem >> 10); | 313 | seq_printf(s, " - static: %u KB\n", |
| 314 | si->base_mem >> 10); | ||
| 315 | seq_printf(s, " - cached: %u KB\n", | ||
| 316 | si->cache_mem >> 10); | ||
| 317 | seq_printf(s, " - paged : %u KB\n", | ||
| 318 | si->page_mem >> 10); | ||
| 295 | } | 319 | } |
| 296 | mutex_unlock(&f2fs_stat_mutex); | 320 | mutex_unlock(&f2fs_stat_mutex); |
| 297 | return 0; | 321 | return 0; |
| @@ -331,6 +355,7 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) | |||
| 331 | 355 | ||
| 332 | atomic_set(&sbi->inline_inode, 0); | 356 | atomic_set(&sbi->inline_inode, 0); |
| 333 | atomic_set(&sbi->inline_dir, 0); | 357 | atomic_set(&sbi->inline_dir, 0); |
| 358 | atomic_set(&sbi->inplace_count, 0); | ||
| 334 | 359 | ||
| 335 | mutex_lock(&f2fs_stat_mutex); | 360 | mutex_lock(&f2fs_stat_mutex); |
| 336 | list_add_tail(&si->stat_list, &f2fs_stat_list); | 361 | list_add_tail(&si->stat_list, &f2fs_stat_list); |
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index b1a7d5737cd0..b74097a7f6d9 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c | |||
| @@ -286,8 +286,7 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, | |||
| 286 | f2fs_wait_on_page_writeback(page, type); | 286 | f2fs_wait_on_page_writeback(page, type); |
| 287 | de->ino = cpu_to_le32(inode->i_ino); | 287 | de->ino = cpu_to_le32(inode->i_ino); |
| 288 | set_de_type(de, inode); | 288 | set_de_type(de, inode); |
| 289 | if (!f2fs_has_inline_dentry(dir)) | 289 | f2fs_dentry_kunmap(dir, page); |
| 290 | kunmap(page); | ||
| 291 | set_page_dirty(page); | 290 | set_page_dirty(page); |
| 292 | dir->i_mtime = dir->i_ctime = CURRENT_TIME; | 291 | dir->i_mtime = dir->i_ctime = CURRENT_TIME; |
| 293 | mark_inode_dirty(dir); | 292 | mark_inode_dirty(dir); |
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index ec58bb2373fc..7fa3313ab0e2 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
| @@ -28,7 +28,7 @@ | |||
| 28 | do { \ | 28 | do { \ |
| 29 | if (unlikely(condition)) { \ | 29 | if (unlikely(condition)) { \ |
| 30 | WARN_ON(1); \ | 30 | WARN_ON(1); \ |
| 31 | sbi->need_fsck = true; \ | 31 | set_sbi_flag(sbi, SBI_NEED_FSCK); \ |
| 32 | } \ | 32 | } \ |
| 33 | } while (0) | 33 | } while (0) |
| 34 | #define f2fs_down_write(x, y) down_write(x) | 34 | #define f2fs_down_write(x, y) down_write(x) |
| @@ -100,10 +100,15 @@ enum { | |||
| 100 | 100 | ||
| 101 | enum { | 101 | enum { |
| 102 | CP_UMOUNT, | 102 | CP_UMOUNT, |
| 103 | CP_FASTBOOT, | ||
| 103 | CP_SYNC, | 104 | CP_SYNC, |
| 104 | CP_DISCARD, | 105 | CP_DISCARD, |
| 105 | }; | 106 | }; |
| 106 | 107 | ||
| 108 | #define DEF_BATCHED_TRIM_SECTIONS 32 | ||
| 109 | #define BATCHED_TRIM_SEGMENTS(sbi) \ | ||
| 110 | (SM_I(sbi)->trim_sections * (sbi)->segs_per_sec) | ||
| 111 | |||
| 107 | struct cp_control { | 112 | struct cp_control { |
| 108 | int reason; | 113 | int reason; |
| 109 | __u64 trim_start; | 114 | __u64 trim_start; |
| @@ -136,8 +141,14 @@ struct ino_entry { | |||
| 136 | nid_t ino; /* inode number */ | 141 | nid_t ino; /* inode number */ |
| 137 | }; | 142 | }; |
| 138 | 143 | ||
| 139 | /* for the list of directory inodes */ | 144 | /* |
| 140 | struct dir_inode_entry { | 145 | * for the list of directory inodes or gc inodes. |
| 146 | * NOTE: there are two slab users for this structure, if we add/modify/delete | ||
| 147 | * fields in structure for one of slab users, it may affect fields or size of | ||
| 148 | * other one, in this condition, it's better to split both of slab and related | ||
| 149 | * data structure. | ||
| 150 | */ | ||
| 151 | struct inode_entry { | ||
| 141 | struct list_head list; /* list head */ | 152 | struct list_head list; /* list head */ |
| 142 | struct inode *inode; /* vfs inode pointer */ | 153 | struct inode *inode; /* vfs inode pointer */ |
| 143 | }; | 154 | }; |
| @@ -196,11 +207,14 @@ static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size, | |||
| 196 | */ | 207 | */ |
| 197 | #define F2FS_IOC_GETFLAGS FS_IOC_GETFLAGS | 208 | #define F2FS_IOC_GETFLAGS FS_IOC_GETFLAGS |
| 198 | #define F2FS_IOC_SETFLAGS FS_IOC_SETFLAGS | 209 | #define F2FS_IOC_SETFLAGS FS_IOC_SETFLAGS |
| 210 | #define F2FS_IOC_GETVERSION FS_IOC_GETVERSION | ||
| 199 | 211 | ||
| 200 | #define F2FS_IOCTL_MAGIC 0xf5 | 212 | #define F2FS_IOCTL_MAGIC 0xf5 |
| 201 | #define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1) | 213 | #define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1) |
| 202 | #define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2) | 214 | #define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2) |
| 203 | #define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3) | 215 | #define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3) |
| 216 | #define F2FS_IOC_RELEASE_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 4) | ||
| 217 | #define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5) | ||
| 204 | 218 | ||
| 205 | #if defined(__KERNEL__) && defined(CONFIG_COMPAT) | 219 | #if defined(__KERNEL__) && defined(CONFIG_COMPAT) |
| 206 | /* | 220 | /* |
| @@ -295,7 +309,7 @@ struct f2fs_inode_info { | |||
| 295 | nid_t i_xattr_nid; /* node id that contains xattrs */ | 309 | nid_t i_xattr_nid; /* node id that contains xattrs */ |
| 296 | unsigned long long xattr_ver; /* cp version of xattr modification */ | 310 | unsigned long long xattr_ver; /* cp version of xattr modification */ |
| 297 | struct extent_info ext; /* in-memory extent cache entry */ | 311 | struct extent_info ext; /* in-memory extent cache entry */ |
| 298 | struct dir_inode_entry *dirty_dir; /* the pointer of dirty dir */ | 312 | struct inode_entry *dirty_dir; /* the pointer of dirty dir */ |
| 299 | 313 | ||
| 300 | struct radix_tree_root inmem_root; /* radix tree for inmem pages */ | 314 | struct radix_tree_root inmem_root; /* radix tree for inmem pages */ |
| 301 | struct list_head inmem_pages; /* inmemory pages managed by f2fs */ | 315 | struct list_head inmem_pages; /* inmemory pages managed by f2fs */ |
| @@ -398,7 +412,8 @@ enum { | |||
| 398 | CURSEG_HOT_NODE, /* direct node blocks of directory files */ | 412 | CURSEG_HOT_NODE, /* direct node blocks of directory files */ |
| 399 | CURSEG_WARM_NODE, /* direct node blocks of normal files */ | 413 | CURSEG_WARM_NODE, /* direct node blocks of normal files */ |
| 400 | CURSEG_COLD_NODE, /* indirect node blocks */ | 414 | CURSEG_COLD_NODE, /* indirect node blocks */ |
| 401 | NO_CHECK_TYPE | 415 | NO_CHECK_TYPE, |
| 416 | CURSEG_DIRECT_IO, /* to use for the direct IO path */ | ||
| 402 | }; | 417 | }; |
| 403 | 418 | ||
| 404 | struct flush_cmd { | 419 | struct flush_cmd { |
| @@ -437,6 +452,9 @@ struct f2fs_sm_info { | |||
| 437 | int nr_discards; /* # of discards in the list */ | 452 | int nr_discards; /* # of discards in the list */ |
| 438 | int max_discards; /* max. discards to be issued */ | 453 | int max_discards; /* max. discards to be issued */ |
| 439 | 454 | ||
| 455 | /* for batched trimming */ | ||
| 456 | unsigned int trim_sections; /* # of sections to trim */ | ||
| 457 | |||
| 440 | struct list_head sit_entry_set; /* sit entry set list */ | 458 | struct list_head sit_entry_set; /* sit entry set list */ |
| 441 | 459 | ||
| 442 | unsigned int ipu_policy; /* in-place-update policy */ | 460 | unsigned int ipu_policy; /* in-place-update policy */ |
| @@ -489,6 +507,7 @@ enum page_type { | |||
| 489 | struct f2fs_io_info { | 507 | struct f2fs_io_info { |
| 490 | enum page_type type; /* contains DATA/NODE/META/META_FLUSH */ | 508 | enum page_type type; /* contains DATA/NODE/META/META_FLUSH */ |
| 491 | int rw; /* contains R/RS/W/WS with REQ_META/REQ_PRIO */ | 509 | int rw; /* contains R/RS/W/WS with REQ_META/REQ_PRIO */ |
| 510 | block_t blk_addr; /* block address to be written */ | ||
| 492 | }; | 511 | }; |
| 493 | 512 | ||
| 494 | #define is_read_io(rw) (((rw) & 1) == READ) | 513 | #define is_read_io(rw) (((rw) & 1) == READ) |
| @@ -508,13 +527,20 @@ struct inode_management { | |||
| 508 | unsigned long ino_num; /* number of entries */ | 527 | unsigned long ino_num; /* number of entries */ |
| 509 | }; | 528 | }; |
| 510 | 529 | ||
| 530 | /* For s_flag in struct f2fs_sb_info */ | ||
| 531 | enum { | ||
| 532 | SBI_IS_DIRTY, /* dirty flag for checkpoint */ | ||
| 533 | SBI_IS_CLOSE, /* specify unmounting */ | ||
| 534 | SBI_NEED_FSCK, /* need fsck.f2fs to fix */ | ||
| 535 | SBI_POR_DOING, /* recovery is doing or not */ | ||
| 536 | }; | ||
| 537 | |||
| 511 | struct f2fs_sb_info { | 538 | struct f2fs_sb_info { |
| 512 | struct super_block *sb; /* pointer to VFS super block */ | 539 | struct super_block *sb; /* pointer to VFS super block */ |
| 513 | struct proc_dir_entry *s_proc; /* proc entry */ | 540 | struct proc_dir_entry *s_proc; /* proc entry */ |
| 514 | struct buffer_head *raw_super_buf; /* buffer head of raw sb */ | 541 | struct buffer_head *raw_super_buf; /* buffer head of raw sb */ |
| 515 | struct f2fs_super_block *raw_super; /* raw super block pointer */ | 542 | struct f2fs_super_block *raw_super; /* raw super block pointer */ |
| 516 | int s_dirty; /* dirty flag for checkpoint */ | 543 | int s_flag; /* flags for sbi */ |
| 517 | bool need_fsck; /* need fsck.f2fs to fix */ | ||
| 518 | 544 | ||
| 519 | /* for node-related operations */ | 545 | /* for node-related operations */ |
| 520 | struct f2fs_nm_info *nm_info; /* node manager */ | 546 | struct f2fs_nm_info *nm_info; /* node manager */ |
| @@ -534,7 +560,6 @@ struct f2fs_sb_info { | |||
| 534 | struct rw_semaphore cp_rwsem; /* blocking FS operations */ | 560 | struct rw_semaphore cp_rwsem; /* blocking FS operations */ |
| 535 | struct rw_semaphore node_write; /* locking node writes */ | 561 | struct rw_semaphore node_write; /* locking node writes */ |
| 536 | struct mutex writepages; /* mutex for writepages() */ | 562 | struct mutex writepages; /* mutex for writepages() */ |
| 537 | bool por_doing; /* recovery is doing or not */ | ||
| 538 | wait_queue_head_t cp_wait; | 563 | wait_queue_head_t cp_wait; |
| 539 | 564 | ||
| 540 | struct inode_management im[MAX_INO_ENTRY]; /* manage inode cache */ | 565 | struct inode_management im[MAX_INO_ENTRY]; /* manage inode cache */ |
| @@ -589,6 +614,7 @@ struct f2fs_sb_info { | |||
| 589 | struct f2fs_stat_info *stat_info; /* FS status information */ | 614 | struct f2fs_stat_info *stat_info; /* FS status information */ |
| 590 | unsigned int segment_count[2]; /* # of allocated segments */ | 615 | unsigned int segment_count[2]; /* # of allocated segments */ |
| 591 | unsigned int block_count[2]; /* # of allocated blocks */ | 616 | unsigned int block_count[2]; /* # of allocated blocks */ |
| 617 | atomic_t inplace_count; /* # of inplace update */ | ||
| 592 | int total_hit_ext, read_hit_ext; /* extent cache hit ratio */ | 618 | int total_hit_ext, read_hit_ext; /* extent cache hit ratio */ |
| 593 | atomic_t inline_inode; /* # of inline_data inodes */ | 619 | atomic_t inline_inode; /* # of inline_data inodes */ |
| 594 | atomic_t inline_dir; /* # of inline_dentry inodes */ | 620 | atomic_t inline_dir; /* # of inline_dentry inodes */ |
| @@ -686,14 +712,19 @@ static inline struct address_space *NODE_MAPPING(struct f2fs_sb_info *sbi) | |||
| 686 | return sbi->node_inode->i_mapping; | 712 | return sbi->node_inode->i_mapping; |
| 687 | } | 713 | } |
| 688 | 714 | ||
| 689 | static inline void F2FS_SET_SB_DIRT(struct f2fs_sb_info *sbi) | 715 | static inline bool is_sbi_flag_set(struct f2fs_sb_info *sbi, unsigned int type) |
| 690 | { | 716 | { |
| 691 | sbi->s_dirty = 1; | 717 | return sbi->s_flag & (0x01 << type); |
| 692 | } | 718 | } |
| 693 | 719 | ||
| 694 | static inline void F2FS_RESET_SB_DIRT(struct f2fs_sb_info *sbi) | 720 | static inline void set_sbi_flag(struct f2fs_sb_info *sbi, unsigned int type) |
| 695 | { | 721 | { |
| 696 | sbi->s_dirty = 0; | 722 | sbi->s_flag |= (0x01 << type); |
| 723 | } | ||
| 724 | |||
| 725 | static inline void clear_sbi_flag(struct f2fs_sb_info *sbi, unsigned int type) | ||
| 726 | { | ||
| 727 | sbi->s_flag &= ~(0x01 << type); | ||
| 697 | } | 728 | } |
| 698 | 729 | ||
| 699 | static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp) | 730 | static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp) |
| @@ -741,6 +772,28 @@ static inline void f2fs_unlock_all(struct f2fs_sb_info *sbi) | |||
| 741 | up_write(&sbi->cp_rwsem); | 772 | up_write(&sbi->cp_rwsem); |
| 742 | } | 773 | } |
| 743 | 774 | ||
| 775 | static inline int __get_cp_reason(struct f2fs_sb_info *sbi) | ||
| 776 | { | ||
| 777 | int reason = CP_SYNC; | ||
| 778 | |||
| 779 | if (test_opt(sbi, FASTBOOT)) | ||
| 780 | reason = CP_FASTBOOT; | ||
| 781 | if (is_sbi_flag_set(sbi, SBI_IS_CLOSE)) | ||
| 782 | reason = CP_UMOUNT; | ||
| 783 | return reason; | ||
| 784 | } | ||
| 785 | |||
| 786 | static inline bool __remain_node_summaries(int reason) | ||
| 787 | { | ||
| 788 | return (reason == CP_UMOUNT || reason == CP_FASTBOOT); | ||
| 789 | } | ||
| 790 | |||
| 791 | static inline bool __exist_node_summaries(struct f2fs_sb_info *sbi) | ||
| 792 | { | ||
| 793 | return (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG) || | ||
| 794 | is_set_ckpt_flags(F2FS_CKPT(sbi), CP_FASTBOOT_FLAG)); | ||
| 795 | } | ||
| 796 | |||
| 744 | /* | 797 | /* |
| 745 | * Check whether the given nid is within node id range. | 798 | * Check whether the given nid is within node id range. |
| 746 | */ | 799 | */ |
| @@ -805,7 +858,7 @@ static inline void dec_valid_block_count(struct f2fs_sb_info *sbi, | |||
| 805 | static inline void inc_page_count(struct f2fs_sb_info *sbi, int count_type) | 858 | static inline void inc_page_count(struct f2fs_sb_info *sbi, int count_type) |
| 806 | { | 859 | { |
| 807 | atomic_inc(&sbi->nr_pages[count_type]); | 860 | atomic_inc(&sbi->nr_pages[count_type]); |
| 808 | F2FS_SET_SB_DIRT(sbi); | 861 | set_sbi_flag(sbi, SBI_IS_DIRTY); |
| 809 | } | 862 | } |
| 810 | 863 | ||
| 811 | static inline void inode_inc_dirty_pages(struct inode *inode) | 864 | static inline void inode_inc_dirty_pages(struct inode *inode) |
| @@ -1113,6 +1166,7 @@ enum { | |||
| 1113 | FI_NEED_IPU, /* used for ipu per file */ | 1166 | FI_NEED_IPU, /* used for ipu per file */ |
| 1114 | FI_ATOMIC_FILE, /* indicate atomic file */ | 1167 | FI_ATOMIC_FILE, /* indicate atomic file */ |
| 1115 | FI_VOLATILE_FILE, /* indicate volatile file */ | 1168 | FI_VOLATILE_FILE, /* indicate volatile file */ |
| 1169 | FI_DROP_CACHE, /* drop dirty page cache */ | ||
| 1116 | FI_DATA_EXIST, /* indicate data exists */ | 1170 | FI_DATA_EXIST, /* indicate data exists */ |
| 1117 | }; | 1171 | }; |
| 1118 | 1172 | ||
| @@ -1220,6 +1274,11 @@ static inline bool f2fs_is_volatile_file(struct inode *inode) | |||
| 1220 | return is_inode_flag_set(F2FS_I(inode), FI_VOLATILE_FILE); | 1274 | return is_inode_flag_set(F2FS_I(inode), FI_VOLATILE_FILE); |
| 1221 | } | 1275 | } |
| 1222 | 1276 | ||
| 1277 | static inline bool f2fs_is_drop_cache(struct inode *inode) | ||
| 1278 | { | ||
| 1279 | return is_inode_flag_set(F2FS_I(inode), FI_DROP_CACHE); | ||
| 1280 | } | ||
| 1281 | |||
| 1223 | static inline void *inline_data_addr(struct page *page) | 1282 | static inline void *inline_data_addr(struct page *page) |
| 1224 | { | 1283 | { |
| 1225 | struct f2fs_inode *ri = F2FS_INODE(page); | 1284 | struct f2fs_inode *ri = F2FS_INODE(page); |
| @@ -1389,7 +1448,6 @@ void destroy_node_manager_caches(void); | |||
| 1389 | * segment.c | 1448 | * segment.c |
| 1390 | */ | 1449 | */ |
| 1391 | void register_inmem_page(struct inode *, struct page *); | 1450 | void register_inmem_page(struct inode *, struct page *); |
| 1392 | void invalidate_inmem_page(struct inode *, struct page *); | ||
| 1393 | void commit_inmem_pages(struct inode *, bool); | 1451 | void commit_inmem_pages(struct inode *, bool); |
| 1394 | void f2fs_balance_fs(struct f2fs_sb_info *); | 1452 | void f2fs_balance_fs(struct f2fs_sb_info *); |
| 1395 | void f2fs_balance_fs_bg(struct f2fs_sb_info *); | 1453 | void f2fs_balance_fs_bg(struct f2fs_sb_info *); |
| @@ -1401,16 +1459,16 @@ void refresh_sit_entry(struct f2fs_sb_info *, block_t, block_t); | |||
| 1401 | void clear_prefree_segments(struct f2fs_sb_info *); | 1459 | void clear_prefree_segments(struct f2fs_sb_info *); |
| 1402 | void release_discard_addrs(struct f2fs_sb_info *); | 1460 | void release_discard_addrs(struct f2fs_sb_info *); |
| 1403 | void discard_next_dnode(struct f2fs_sb_info *, block_t); | 1461 | void discard_next_dnode(struct f2fs_sb_info *, block_t); |
| 1404 | int npages_for_summary_flush(struct f2fs_sb_info *); | 1462 | int npages_for_summary_flush(struct f2fs_sb_info *, bool); |
| 1405 | void allocate_new_segments(struct f2fs_sb_info *); | 1463 | void allocate_new_segments(struct f2fs_sb_info *); |
| 1406 | int f2fs_trim_fs(struct f2fs_sb_info *, struct fstrim_range *); | 1464 | int f2fs_trim_fs(struct f2fs_sb_info *, struct fstrim_range *); |
| 1407 | struct page *get_sum_page(struct f2fs_sb_info *, unsigned int); | 1465 | struct page *get_sum_page(struct f2fs_sb_info *, unsigned int); |
| 1408 | void write_meta_page(struct f2fs_sb_info *, struct page *); | 1466 | void write_meta_page(struct f2fs_sb_info *, struct page *); |
| 1409 | void write_node_page(struct f2fs_sb_info *, struct page *, | 1467 | void write_node_page(struct f2fs_sb_info *, struct page *, |
| 1410 | struct f2fs_io_info *, unsigned int, block_t, block_t *); | 1468 | unsigned int, struct f2fs_io_info *); |
| 1411 | void write_data_page(struct page *, struct dnode_of_data *, block_t *, | 1469 | void write_data_page(struct page *, struct dnode_of_data *, |
| 1412 | struct f2fs_io_info *); | 1470 | struct f2fs_io_info *); |
| 1413 | void rewrite_data_page(struct page *, block_t, struct f2fs_io_info *); | 1471 | void rewrite_data_page(struct page *, struct f2fs_io_info *); |
| 1414 | void recover_data_page(struct f2fs_sb_info *, struct page *, | 1472 | void recover_data_page(struct f2fs_sb_info *, struct page *, |
| 1415 | struct f2fs_summary *, block_t, block_t); | 1473 | struct f2fs_summary *, block_t, block_t); |
| 1416 | void allocate_data_block(struct f2fs_sb_info *, struct page *, | 1474 | void allocate_data_block(struct f2fs_sb_info *, struct page *, |
| @@ -1457,17 +1515,20 @@ void destroy_checkpoint_caches(void); | |||
| 1457 | * data.c | 1515 | * data.c |
| 1458 | */ | 1516 | */ |
| 1459 | void f2fs_submit_merged_bio(struct f2fs_sb_info *, enum page_type, int); | 1517 | void f2fs_submit_merged_bio(struct f2fs_sb_info *, enum page_type, int); |
| 1460 | int f2fs_submit_page_bio(struct f2fs_sb_info *, struct page *, block_t, int); | 1518 | int f2fs_submit_page_bio(struct f2fs_sb_info *, struct page *, |
| 1461 | void f2fs_submit_page_mbio(struct f2fs_sb_info *, struct page *, block_t, | 1519 | struct f2fs_io_info *); |
| 1520 | void f2fs_submit_page_mbio(struct f2fs_sb_info *, struct page *, | ||
| 1462 | struct f2fs_io_info *); | 1521 | struct f2fs_io_info *); |
| 1463 | int reserve_new_block(struct dnode_of_data *); | 1522 | int reserve_new_block(struct dnode_of_data *); |
| 1464 | int f2fs_reserve_block(struct dnode_of_data *, pgoff_t); | 1523 | int f2fs_reserve_block(struct dnode_of_data *, pgoff_t); |
| 1465 | void update_extent_cache(block_t, struct dnode_of_data *); | 1524 | void update_extent_cache(struct dnode_of_data *); |
| 1466 | struct page *find_data_page(struct inode *, pgoff_t, bool); | 1525 | struct page *find_data_page(struct inode *, pgoff_t, bool); |
| 1467 | struct page *get_lock_data_page(struct inode *, pgoff_t); | 1526 | struct page *get_lock_data_page(struct inode *, pgoff_t); |
| 1468 | struct page *get_new_data_page(struct inode *, struct page *, pgoff_t, bool); | 1527 | struct page *get_new_data_page(struct inode *, struct page *, pgoff_t, bool); |
| 1469 | int do_write_data_page(struct page *, struct f2fs_io_info *); | 1528 | int do_write_data_page(struct page *, struct f2fs_io_info *); |
| 1470 | int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *, u64, u64); | 1529 | int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *, u64, u64); |
| 1530 | void f2fs_invalidate_page(struct page *, unsigned int, unsigned int); | ||
| 1531 | int f2fs_release_page(struct page *, gfp_t); | ||
| 1471 | 1532 | ||
| 1472 | /* | 1533 | /* |
| 1473 | * gc.c | 1534 | * gc.c |
| @@ -1477,8 +1538,6 @@ void stop_gc_thread(struct f2fs_sb_info *); | |||
| 1477 | block_t start_bidx_of_node(unsigned int, struct f2fs_inode_info *); | 1538 | block_t start_bidx_of_node(unsigned int, struct f2fs_inode_info *); |
| 1478 | int f2fs_gc(struct f2fs_sb_info *); | 1539 | int f2fs_gc(struct f2fs_sb_info *); |
| 1479 | void build_gc_manager(struct f2fs_sb_info *); | 1540 | void build_gc_manager(struct f2fs_sb_info *); |
| 1480 | int __init create_gc_caches(void); | ||
| 1481 | void destroy_gc_caches(void); | ||
| 1482 | 1541 | ||
| 1483 | /* | 1542 | /* |
| 1484 | * recovery.c | 1543 | * recovery.c |
| @@ -1497,9 +1556,9 @@ struct f2fs_stat_info { | |||
| 1497 | int main_area_segs, main_area_sections, main_area_zones; | 1556 | int main_area_segs, main_area_sections, main_area_zones; |
| 1498 | int hit_ext, total_ext; | 1557 | int hit_ext, total_ext; |
| 1499 | int ndirty_node, ndirty_dent, ndirty_dirs, ndirty_meta; | 1558 | int ndirty_node, ndirty_dent, ndirty_dirs, ndirty_meta; |
| 1500 | int nats, sits, fnids; | 1559 | int nats, dirty_nats, sits, dirty_sits, fnids; |
| 1501 | int total_count, utilization; | 1560 | int total_count, utilization; |
| 1502 | int bg_gc, inline_inode, inline_dir, inmem_pages; | 1561 | int bg_gc, inline_inode, inline_dir, inmem_pages, wb_pages; |
| 1503 | unsigned int valid_count, valid_node_count, valid_inode_count; | 1562 | unsigned int valid_count, valid_node_count, valid_inode_count; |
| 1504 | unsigned int bimodal, avg_vblocks; | 1563 | unsigned int bimodal, avg_vblocks; |
| 1505 | int util_free, util_valid, util_invalid; | 1564 | int util_free, util_valid, util_invalid; |
| @@ -1514,7 +1573,8 @@ struct f2fs_stat_info { | |||
| 1514 | 1573 | ||
| 1515 | unsigned int segment_count[2]; | 1574 | unsigned int segment_count[2]; |
| 1516 | unsigned int block_count[2]; | 1575 | unsigned int block_count[2]; |
| 1517 | unsigned base_mem, cache_mem; | 1576 | unsigned int inplace_count; |
| 1577 | unsigned base_mem, cache_mem, page_mem; | ||
| 1518 | }; | 1578 | }; |
| 1519 | 1579 | ||
| 1520 | static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) | 1580 | static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) |
| @@ -1553,7 +1613,8 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) | |||
| 1553 | ((sbi)->segment_count[(curseg)->alloc_type]++) | 1613 | ((sbi)->segment_count[(curseg)->alloc_type]++) |
| 1554 | #define stat_inc_block_count(sbi, curseg) \ | 1614 | #define stat_inc_block_count(sbi, curseg) \ |
| 1555 | ((sbi)->block_count[(curseg)->alloc_type]++) | 1615 | ((sbi)->block_count[(curseg)->alloc_type]++) |
| 1556 | 1616 | #define stat_inc_inplace_blocks(sbi) \ | |
| 1617 | (atomic_inc(&(sbi)->inplace_count)) | ||
| 1557 | #define stat_inc_seg_count(sbi, type) \ | 1618 | #define stat_inc_seg_count(sbi, type) \ |
| 1558 | do { \ | 1619 | do { \ |
| 1559 | struct f2fs_stat_info *si = F2FS_STAT(sbi); \ | 1620 | struct f2fs_stat_info *si = F2FS_STAT(sbi); \ |
| @@ -1599,6 +1660,7 @@ void f2fs_destroy_root_stats(void); | |||
| 1599 | #define stat_dec_inline_dir(inode) | 1660 | #define stat_dec_inline_dir(inode) |
| 1600 | #define stat_inc_seg_type(sbi, curseg) | 1661 | #define stat_inc_seg_type(sbi, curseg) |
| 1601 | #define stat_inc_block_count(sbi, curseg) | 1662 | #define stat_inc_block_count(sbi, curseg) |
| 1663 | #define stat_inc_inplace_blocks(sbi) | ||
| 1602 | #define stat_inc_seg_count(si, type) | 1664 | #define stat_inc_seg_count(si, type) |
| 1603 | #define stat_inc_tot_blk_count(si, blks) | 1665 | #define stat_inc_tot_blk_count(si, blks) |
| 1604 | #define stat_inc_data_blk_count(si, blks) | 1666 | #define stat_inc_data_blk_count(si, blks) |
| @@ -1619,6 +1681,7 @@ extern const struct address_space_operations f2fs_meta_aops; | |||
| 1619 | extern const struct inode_operations f2fs_dir_inode_operations; | 1681 | extern const struct inode_operations f2fs_dir_inode_operations; |
| 1620 | extern const struct inode_operations f2fs_symlink_inode_operations; | 1682 | extern const struct inode_operations f2fs_symlink_inode_operations; |
| 1621 | extern const struct inode_operations f2fs_special_inode_operations; | 1683 | extern const struct inode_operations f2fs_special_inode_operations; |
| 1684 | extern struct kmem_cache *inode_entry_slab; | ||
| 1622 | 1685 | ||
| 1623 | /* | 1686 | /* |
| 1624 | * inline.c | 1687 | * inline.c |
| @@ -1629,7 +1692,6 @@ int f2fs_read_inline_data(struct inode *, struct page *); | |||
| 1629 | int f2fs_convert_inline_page(struct dnode_of_data *, struct page *); | 1692 | int f2fs_convert_inline_page(struct dnode_of_data *, struct page *); |
| 1630 | int f2fs_convert_inline_inode(struct inode *); | 1693 | int f2fs_convert_inline_inode(struct inode *); |
| 1631 | int f2fs_write_inline_data(struct inode *, struct page *); | 1694 | int f2fs_write_inline_data(struct inode *, struct page *); |
| 1632 | void truncate_inline_data(struct page *, u64); | ||
| 1633 | bool recover_inline_data(struct inode *, struct page *); | 1695 | bool recover_inline_data(struct inode *, struct page *); |
| 1634 | struct f2fs_dir_entry *find_in_inline_dir(struct inode *, struct qstr *, | 1696 | struct f2fs_dir_entry *find_in_inline_dir(struct inode *, struct qstr *, |
| 1635 | struct page **); | 1697 | struct page **); |
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 5674ba13102b..98dac27bc3f7 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include "segment.h" | 26 | #include "segment.h" |
| 27 | #include "xattr.h" | 27 | #include "xattr.h" |
| 28 | #include "acl.h" | 28 | #include "acl.h" |
| 29 | #include "trace.h" | ||
| 29 | #include <trace/events/f2fs.h> | 30 | #include <trace/events/f2fs.h> |
| 30 | 31 | ||
| 31 | static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, | 32 | static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, |
| @@ -245,6 +246,10 @@ go_write: | |||
| 245 | sync_nodes: | 246 | sync_nodes: |
| 246 | sync_node_pages(sbi, ino, &wbc); | 247 | sync_node_pages(sbi, ino, &wbc); |
| 247 | 248 | ||
| 249 | /* if cp_error was enabled, we should avoid infinite loop */ | ||
| 250 | if (unlikely(f2fs_cp_error(sbi))) | ||
| 251 | goto out; | ||
| 252 | |||
| 248 | if (need_inode_block_update(sbi, ino)) { | 253 | if (need_inode_block_update(sbi, ino)) { |
| 249 | mark_inode_dirty_sync(inode); | 254 | mark_inode_dirty_sync(inode); |
| 250 | f2fs_write_inode(inode, NULL); | 255 | f2fs_write_inode(inode, NULL); |
| @@ -264,6 +269,7 @@ flush_out: | |||
| 264 | ret = f2fs_issue_flush(sbi); | 269 | ret = f2fs_issue_flush(sbi); |
| 265 | out: | 270 | out: |
| 266 | trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret); | 271 | trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret); |
| 272 | f2fs_trace_ios(NULL, NULL, 1); | ||
| 267 | return ret; | 273 | return ret; |
| 268 | } | 274 | } |
| 269 | 275 | ||
| @@ -350,7 +356,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence) | |||
| 350 | /* find data/hole in dnode block */ | 356 | /* find data/hole in dnode block */ |
| 351 | for (; dn.ofs_in_node < end_offset; | 357 | for (; dn.ofs_in_node < end_offset; |
| 352 | dn.ofs_in_node++, pgofs++, | 358 | dn.ofs_in_node++, pgofs++, |
| 353 | data_ofs = pgofs << PAGE_CACHE_SHIFT) { | 359 | data_ofs = (loff_t)pgofs << PAGE_CACHE_SHIFT) { |
| 354 | block_t blkaddr; | 360 | block_t blkaddr; |
| 355 | blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node); | 361 | blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node); |
| 356 | 362 | ||
| @@ -426,7 +432,8 @@ int truncate_data_blocks_range(struct dnode_of_data *dn, int count) | |||
| 426 | if (blkaddr == NULL_ADDR) | 432 | if (blkaddr == NULL_ADDR) |
| 427 | continue; | 433 | continue; |
| 428 | 434 | ||
| 429 | update_extent_cache(NULL_ADDR, dn); | 435 | dn->data_blkaddr = NULL_ADDR; |
| 436 | update_extent_cache(dn); | ||
| 430 | invalidate_blocks(sbi, blkaddr); | 437 | invalidate_blocks(sbi, blkaddr); |
| 431 | nr_free++; | 438 | nr_free++; |
| 432 | } | 439 | } |
| @@ -483,8 +490,7 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock) | |||
| 483 | 490 | ||
| 484 | trace_f2fs_truncate_blocks_enter(inode, from); | 491 | trace_f2fs_truncate_blocks_enter(inode, from); |
| 485 | 492 | ||
| 486 | free_from = (pgoff_t) | 493 | free_from = (pgoff_t)F2FS_BYTES_TO_BLK(from + blocksize - 1); |
| 487 | ((from + blocksize - 1) >> (sbi->log_blocksize)); | ||
| 488 | 494 | ||
| 489 | if (lock) | 495 | if (lock) |
| 490 | f2fs_lock_op(sbi); | 496 | f2fs_lock_op(sbi); |
| @@ -835,6 +841,19 @@ static long f2fs_fallocate(struct file *file, int mode, | |||
| 835 | return ret; | 841 | return ret; |
| 836 | } | 842 | } |
| 837 | 843 | ||
| 844 | static int f2fs_release_file(struct inode *inode, struct file *filp) | ||
| 845 | { | ||
| 846 | /* some remained atomic pages should discarded */ | ||
| 847 | if (f2fs_is_atomic_file(inode)) | ||
| 848 | commit_inmem_pages(inode, true); | ||
| 849 | if (f2fs_is_volatile_file(inode)) { | ||
| 850 | set_inode_flag(F2FS_I(inode), FI_DROP_CACHE); | ||
| 851 | filemap_fdatawrite(inode->i_mapping); | ||
| 852 | clear_inode_flag(F2FS_I(inode), FI_DROP_CACHE); | ||
| 853 | } | ||
| 854 | return 0; | ||
| 855 | } | ||
| 856 | |||
| 838 | #define F2FS_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL)) | 857 | #define F2FS_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL)) |
| 839 | #define F2FS_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL) | 858 | #define F2FS_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL) |
| 840 | 859 | ||
| @@ -905,29 +924,30 @@ out: | |||
| 905 | return ret; | 924 | return ret; |
| 906 | } | 925 | } |
| 907 | 926 | ||
| 927 | static int f2fs_ioc_getversion(struct file *filp, unsigned long arg) | ||
| 928 | { | ||
| 929 | struct inode *inode = file_inode(filp); | ||
| 930 | |||
| 931 | return put_user(inode->i_generation, (int __user *)arg); | ||
| 932 | } | ||
| 933 | |||
| 908 | static int f2fs_ioc_start_atomic_write(struct file *filp) | 934 | static int f2fs_ioc_start_atomic_write(struct file *filp) |
| 909 | { | 935 | { |
| 910 | struct inode *inode = file_inode(filp); | 936 | struct inode *inode = file_inode(filp); |
| 911 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | ||
| 912 | 937 | ||
| 913 | if (!inode_owner_or_capable(inode)) | 938 | if (!inode_owner_or_capable(inode)) |
| 914 | return -EACCES; | 939 | return -EACCES; |
| 915 | 940 | ||
| 916 | f2fs_balance_fs(sbi); | 941 | f2fs_balance_fs(F2FS_I_SB(inode)); |
| 942 | |||
| 943 | if (f2fs_is_atomic_file(inode)) | ||
| 944 | return 0; | ||
| 917 | 945 | ||
| 918 | set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE); | 946 | set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE); |
| 919 | 947 | ||
| 920 | return f2fs_convert_inline_inode(inode); | 948 | return f2fs_convert_inline_inode(inode); |
| 921 | } | 949 | } |
| 922 | 950 | ||
| 923 | static int f2fs_release_file(struct inode *inode, struct file *filp) | ||
| 924 | { | ||
| 925 | /* some remained atomic pages should discarded */ | ||
| 926 | if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) | ||
| 927 | commit_inmem_pages(inode, true); | ||
| 928 | return 0; | ||
| 929 | } | ||
| 930 | |||
| 931 | static int f2fs_ioc_commit_atomic_write(struct file *filp) | 951 | static int f2fs_ioc_commit_atomic_write(struct file *filp) |
| 932 | { | 952 | { |
| 933 | struct inode *inode = file_inode(filp); | 953 | struct inode *inode = file_inode(filp); |
| @@ -948,6 +968,7 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp) | |||
| 948 | 968 | ||
| 949 | ret = f2fs_sync_file(filp, 0, LONG_MAX, 0); | 969 | ret = f2fs_sync_file(filp, 0, LONG_MAX, 0); |
| 950 | mnt_drop_write_file(filp); | 970 | mnt_drop_write_file(filp); |
| 971 | clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE); | ||
| 951 | return ret; | 972 | return ret; |
| 952 | } | 973 | } |
| 953 | 974 | ||
| @@ -958,11 +979,56 @@ static int f2fs_ioc_start_volatile_write(struct file *filp) | |||
| 958 | if (!inode_owner_or_capable(inode)) | 979 | if (!inode_owner_or_capable(inode)) |
| 959 | return -EACCES; | 980 | return -EACCES; |
| 960 | 981 | ||
| 982 | if (f2fs_is_volatile_file(inode)) | ||
| 983 | return 0; | ||
| 984 | |||
| 961 | set_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE); | 985 | set_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE); |
| 962 | 986 | ||
| 963 | return f2fs_convert_inline_inode(inode); | 987 | return f2fs_convert_inline_inode(inode); |
| 964 | } | 988 | } |
| 965 | 989 | ||
| 990 | static int f2fs_ioc_release_volatile_write(struct file *filp) | ||
| 991 | { | ||
| 992 | struct inode *inode = file_inode(filp); | ||
| 993 | |||
| 994 | if (!inode_owner_or_capable(inode)) | ||
| 995 | return -EACCES; | ||
| 996 | |||
| 997 | if (!f2fs_is_volatile_file(inode)) | ||
| 998 | return 0; | ||
| 999 | |||
| 1000 | punch_hole(inode, 0, F2FS_BLKSIZE); | ||
| 1001 | return 0; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | static int f2fs_ioc_abort_volatile_write(struct file *filp) | ||
| 1005 | { | ||
| 1006 | struct inode *inode = file_inode(filp); | ||
| 1007 | int ret; | ||
| 1008 | |||
| 1009 | if (!inode_owner_or_capable(inode)) | ||
| 1010 | return -EACCES; | ||
| 1011 | |||
| 1012 | ret = mnt_want_write_file(filp); | ||
| 1013 | if (ret) | ||
| 1014 | return ret; | ||
| 1015 | |||
| 1016 | f2fs_balance_fs(F2FS_I_SB(inode)); | ||
| 1017 | |||
| 1018 | if (f2fs_is_atomic_file(inode)) { | ||
| 1019 | commit_inmem_pages(inode, false); | ||
| 1020 | clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE); | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | if (f2fs_is_volatile_file(inode)) { | ||
| 1024 | clear_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE); | ||
| 1025 | filemap_fdatawrite(inode->i_mapping); | ||
| 1026 | set_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE); | ||
| 1027 | } | ||
| 1028 | mnt_drop_write_file(filp); | ||
| 1029 | return ret; | ||
| 1030 | } | ||
| 1031 | |||
| 966 | static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg) | 1032 | static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg) |
| 967 | { | 1033 | { |
| 968 | struct inode *inode = file_inode(filp); | 1034 | struct inode *inode = file_inode(filp); |
| @@ -1000,12 +1066,18 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
| 1000 | return f2fs_ioc_getflags(filp, arg); | 1066 | return f2fs_ioc_getflags(filp, arg); |
| 1001 | case F2FS_IOC_SETFLAGS: | 1067 | case F2FS_IOC_SETFLAGS: |
| 1002 | return f2fs_ioc_setflags(filp, arg); | 1068 | return f2fs_ioc_setflags(filp, arg); |
| 1069 | case F2FS_IOC_GETVERSION: | ||
| 1070 | return f2fs_ioc_getversion(filp, arg); | ||
| 1003 | case F2FS_IOC_START_ATOMIC_WRITE: | 1071 | case F2FS_IOC_START_ATOMIC_WRITE: |
| 1004 | return f2fs_ioc_start_atomic_write(filp); | 1072 | return f2fs_ioc_start_atomic_write(filp); |
| 1005 | case F2FS_IOC_COMMIT_ATOMIC_WRITE: | 1073 | case F2FS_IOC_COMMIT_ATOMIC_WRITE: |
| 1006 | return f2fs_ioc_commit_atomic_write(filp); | 1074 | return f2fs_ioc_commit_atomic_write(filp); |
| 1007 | case F2FS_IOC_START_VOLATILE_WRITE: | 1075 | case F2FS_IOC_START_VOLATILE_WRITE: |
| 1008 | return f2fs_ioc_start_volatile_write(filp); | 1076 | return f2fs_ioc_start_volatile_write(filp); |
| 1077 | case F2FS_IOC_RELEASE_VOLATILE_WRITE: | ||
| 1078 | return f2fs_ioc_release_volatile_write(filp); | ||
| 1079 | case F2FS_IOC_ABORT_VOLATILE_WRITE: | ||
| 1080 | return f2fs_ioc_abort_volatile_write(filp); | ||
| 1009 | case FITRIM: | 1081 | case FITRIM: |
| 1010 | return f2fs_ioc_fitrim(filp, arg); | 1082 | return f2fs_ioc_fitrim(filp, arg); |
| 1011 | default: | 1083 | default: |
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index eec0933a4819..76adbc3641f1 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c | |||
| @@ -24,8 +24,6 @@ | |||
| 24 | #include "gc.h" | 24 | #include "gc.h" |
| 25 | #include <trace/events/f2fs.h> | 25 | #include <trace/events/f2fs.h> |
| 26 | 26 | ||
| 27 | static struct kmem_cache *winode_slab; | ||
| 28 | |||
| 29 | static int gc_thread_func(void *data) | 27 | static int gc_thread_func(void *data) |
| 30 | { | 28 | { |
| 31 | struct f2fs_sb_info *sbi = data; | 29 | struct f2fs_sb_info *sbi = data; |
| @@ -46,7 +44,7 @@ static int gc_thread_func(void *data) | |||
| 46 | break; | 44 | break; |
| 47 | 45 | ||
| 48 | if (sbi->sb->s_writers.frozen >= SB_FREEZE_WRITE) { | 46 | if (sbi->sb->s_writers.frozen >= SB_FREEZE_WRITE) { |
| 49 | wait_ms = increase_sleep_time(gc_th, wait_ms); | 47 | increase_sleep_time(gc_th, &wait_ms); |
| 50 | continue; | 48 | continue; |
| 51 | } | 49 | } |
| 52 | 50 | ||
| @@ -67,15 +65,15 @@ static int gc_thread_func(void *data) | |||
| 67 | continue; | 65 | continue; |
| 68 | 66 | ||
| 69 | if (!is_idle(sbi)) { | 67 | if (!is_idle(sbi)) { |
| 70 | wait_ms = increase_sleep_time(gc_th, wait_ms); | 68 | increase_sleep_time(gc_th, &wait_ms); |
| 71 | mutex_unlock(&sbi->gc_mutex); | 69 | mutex_unlock(&sbi->gc_mutex); |
| 72 | continue; | 70 | continue; |
| 73 | } | 71 | } |
| 74 | 72 | ||
| 75 | if (has_enough_invalid_blocks(sbi)) | 73 | if (has_enough_invalid_blocks(sbi)) |
| 76 | wait_ms = decrease_sleep_time(gc_th, wait_ms); | 74 | decrease_sleep_time(gc_th, &wait_ms); |
| 77 | else | 75 | else |
| 78 | wait_ms = increase_sleep_time(gc_th, wait_ms); | 76 | increase_sleep_time(gc_th, &wait_ms); |
| 79 | 77 | ||
| 80 | stat_inc_bggc_count(sbi); | 78 | stat_inc_bggc_count(sbi); |
| 81 | 79 | ||
| @@ -356,13 +354,10 @@ static void add_gc_inode(struct gc_inode_list *gc_list, struct inode *inode) | |||
| 356 | iput(inode); | 354 | iput(inode); |
| 357 | return; | 355 | return; |
| 358 | } | 356 | } |
| 359 | new_ie = f2fs_kmem_cache_alloc(winode_slab, GFP_NOFS); | 357 | new_ie = f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS); |
| 360 | new_ie->inode = inode; | 358 | new_ie->inode = inode; |
| 361 | retry: | 359 | |
| 362 | if (radix_tree_insert(&gc_list->iroot, inode->i_ino, new_ie)) { | 360 | f2fs_radix_tree_insert(&gc_list->iroot, inode->i_ino, new_ie); |
| 363 | cond_resched(); | ||
| 364 | goto retry; | ||
| 365 | } | ||
| 366 | list_add_tail(&new_ie->list, &gc_list->ilist); | 361 | list_add_tail(&new_ie->list, &gc_list->ilist); |
| 367 | } | 362 | } |
| 368 | 363 | ||
| @@ -373,7 +368,7 @@ static void put_gc_inode(struct gc_inode_list *gc_list) | |||
| 373 | radix_tree_delete(&gc_list->iroot, ie->inode->i_ino); | 368 | radix_tree_delete(&gc_list->iroot, ie->inode->i_ino); |
| 374 | iput(ie->inode); | 369 | iput(ie->inode); |
| 375 | list_del(&ie->list); | 370 | list_del(&ie->list); |
| 376 | kmem_cache_free(winode_slab, ie); | 371 | kmem_cache_free(inode_entry_slab, ie); |
| 377 | } | 372 | } |
| 378 | } | 373 | } |
| 379 | 374 | ||
| @@ -703,8 +698,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi) | |||
| 703 | .iroot = RADIX_TREE_INIT(GFP_NOFS), | 698 | .iroot = RADIX_TREE_INIT(GFP_NOFS), |
| 704 | }; | 699 | }; |
| 705 | 700 | ||
| 706 | cpc.reason = test_opt(sbi, FASTBOOT) ? CP_UMOUNT : CP_SYNC; | 701 | cpc.reason = __get_cp_reason(sbi); |
| 707 | |||
| 708 | gc_more: | 702 | gc_more: |
| 709 | if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE))) | 703 | if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE))) |
| 710 | goto stop; | 704 | goto stop; |
| @@ -750,17 +744,3 @@ void build_gc_manager(struct f2fs_sb_info *sbi) | |||
| 750 | { | 744 | { |
| 751 | DIRTY_I(sbi)->v_ops = &default_v_ops; | 745 | DIRTY_I(sbi)->v_ops = &default_v_ops; |
| 752 | } | 746 | } |
| 753 | |||
| 754 | int __init create_gc_caches(void) | ||
| 755 | { | ||
| 756 | winode_slab = f2fs_kmem_cache_create("f2fs_gc_inodes", | ||
| 757 | sizeof(struct inode_entry)); | ||
| 758 | if (!winode_slab) | ||
| 759 | return -ENOMEM; | ||
| 760 | return 0; | ||
| 761 | } | ||
| 762 | |||
| 763 | void destroy_gc_caches(void) | ||
| 764 | { | ||
| 765 | kmem_cache_destroy(winode_slab); | ||
| 766 | } | ||
diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h index 6ff7ad38463e..b4a65be9f7d3 100644 --- a/fs/f2fs/gc.h +++ b/fs/f2fs/gc.h | |||
| @@ -35,11 +35,6 @@ struct f2fs_gc_kthread { | |||
| 35 | unsigned int gc_idle; | 35 | unsigned int gc_idle; |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | struct inode_entry { | ||
| 39 | struct list_head list; | ||
| 40 | struct inode *inode; | ||
| 41 | }; | ||
| 42 | |||
| 43 | struct gc_inode_list { | 38 | struct gc_inode_list { |
| 44 | struct list_head ilist; | 39 | struct list_head ilist; |
| 45 | struct radix_tree_root iroot; | 40 | struct radix_tree_root iroot; |
| @@ -69,26 +64,26 @@ static inline block_t limit_free_user_blocks(struct f2fs_sb_info *sbi) | |||
| 69 | return (long)(reclaimable_user_blocks * LIMIT_FREE_BLOCK) / 100; | 64 | return (long)(reclaimable_user_blocks * LIMIT_FREE_BLOCK) / 100; |
| 70 | } | 65 | } |
| 71 | 66 | ||
| 72 | static inline long increase_sleep_time(struct f2fs_gc_kthread *gc_th, long wait) | 67 | static inline void increase_sleep_time(struct f2fs_gc_kthread *gc_th, |
| 68 | long *wait) | ||
| 73 | { | 69 | { |
| 74 | if (wait == gc_th->no_gc_sleep_time) | 70 | if (*wait == gc_th->no_gc_sleep_time) |
| 75 | return wait; | 71 | return; |
| 76 | 72 | ||
| 77 | wait += gc_th->min_sleep_time; | 73 | *wait += gc_th->min_sleep_time; |
| 78 | if (wait > gc_th->max_sleep_time) | 74 | if (*wait > gc_th->max_sleep_time) |
| 79 | wait = gc_th->max_sleep_time; | 75 | *wait = gc_th->max_sleep_time; |
| 80 | return wait; | ||
| 81 | } | 76 | } |
| 82 | 77 | ||
| 83 | static inline long decrease_sleep_time(struct f2fs_gc_kthread *gc_th, long wait) | 78 | static inline void decrease_sleep_time(struct f2fs_gc_kthread *gc_th, |
| 79 | long *wait) | ||
| 84 | { | 80 | { |
| 85 | if (wait == gc_th->no_gc_sleep_time) | 81 | if (*wait == gc_th->no_gc_sleep_time) |
| 86 | wait = gc_th->max_sleep_time; | 82 | *wait = gc_th->max_sleep_time; |
| 87 | 83 | ||
| 88 | wait -= gc_th->min_sleep_time; | 84 | *wait -= gc_th->min_sleep_time; |
| 89 | if (wait <= gc_th->min_sleep_time) | 85 | if (*wait <= gc_th->min_sleep_time) |
| 90 | wait = gc_th->min_sleep_time; | 86 | *wait = gc_th->min_sleep_time; |
| 91 | return wait; | ||
| 92 | } | 87 | } |
| 93 | 88 | ||
| 94 | static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi) | 89 | static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi) |
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index f2d3c581e776..1484c00133cd 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c | |||
| @@ -50,6 +50,12 @@ void read_inline_data(struct page *page, struct page *ipage) | |||
| 50 | SetPageUptodate(page); | 50 | SetPageUptodate(page); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | static void truncate_inline_data(struct page *ipage) | ||
| 54 | { | ||
| 55 | f2fs_wait_on_page_writeback(ipage, NODE); | ||
| 56 | memset(inline_data_addr(ipage), 0, MAX_INLINE_DATA); | ||
| 57 | } | ||
| 58 | |||
| 53 | int f2fs_read_inline_data(struct inode *inode, struct page *page) | 59 | int f2fs_read_inline_data(struct inode *inode, struct page *page) |
| 54 | { | 60 | { |
| 55 | struct page *ipage; | 61 | struct page *ipage; |
| @@ -79,7 +85,6 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page) | |||
| 79 | int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) | 85 | int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) |
| 80 | { | 86 | { |
| 81 | void *src_addr, *dst_addr; | 87 | void *src_addr, *dst_addr; |
| 82 | block_t new_blk_addr; | ||
| 83 | struct f2fs_io_info fio = { | 88 | struct f2fs_io_info fio = { |
| 84 | .type = DATA, | 89 | .type = DATA, |
| 85 | .rw = WRITE_SYNC | REQ_PRIO, | 90 | .rw = WRITE_SYNC | REQ_PRIO, |
| @@ -115,9 +120,9 @@ no_update: | |||
| 115 | 120 | ||
| 116 | /* write data page to try to make data consistent */ | 121 | /* write data page to try to make data consistent */ |
| 117 | set_page_writeback(page); | 122 | set_page_writeback(page); |
| 118 | 123 | fio.blk_addr = dn->data_blkaddr; | |
| 119 | write_data_page(page, dn, &new_blk_addr, &fio); | 124 | write_data_page(page, dn, &fio); |
| 120 | update_extent_cache(new_blk_addr, dn); | 125 | update_extent_cache(dn); |
| 121 | f2fs_wait_on_page_writeback(page, DATA); | 126 | f2fs_wait_on_page_writeback(page, DATA); |
| 122 | if (dirty) | 127 | if (dirty) |
| 123 | inode_dec_dirty_pages(dn->inode); | 128 | inode_dec_dirty_pages(dn->inode); |
| @@ -126,7 +131,7 @@ no_update: | |||
| 126 | set_inode_flag(F2FS_I(dn->inode), FI_APPEND_WRITE); | 131 | set_inode_flag(F2FS_I(dn->inode), FI_APPEND_WRITE); |
| 127 | 132 | ||
| 128 | /* clear inline data and flag after data writeback */ | 133 | /* clear inline data and flag after data writeback */ |
| 129 | truncate_inline_data(dn->inode_page, 0); | 134 | truncate_inline_data(dn->inode_page); |
| 130 | clear_out: | 135 | clear_out: |
| 131 | stat_dec_inline_inode(dn->inode); | 136 | stat_dec_inline_inode(dn->inode); |
| 132 | f2fs_clear_inline_inode(dn->inode); | 137 | f2fs_clear_inline_inode(dn->inode); |
| @@ -199,19 +204,6 @@ int f2fs_write_inline_data(struct inode *inode, struct page *page) | |||
| 199 | return 0; | 204 | return 0; |
| 200 | } | 205 | } |
| 201 | 206 | ||
| 202 | void truncate_inline_data(struct page *ipage, u64 from) | ||
| 203 | { | ||
| 204 | void *addr; | ||
| 205 | |||
| 206 | if (from >= MAX_INLINE_DATA) | ||
| 207 | return; | ||
| 208 | |||
| 209 | f2fs_wait_on_page_writeback(ipage, NODE); | ||
| 210 | |||
| 211 | addr = inline_data_addr(ipage); | ||
| 212 | memset(addr + from, 0, MAX_INLINE_DATA - from); | ||
| 213 | } | ||
| 214 | |||
| 215 | bool recover_inline_data(struct inode *inode, struct page *npage) | 207 | bool recover_inline_data(struct inode *inode, struct page *npage) |
| 216 | { | 208 | { |
| 217 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | 209 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); |
| @@ -253,7 +245,7 @@ process_inline: | |||
| 253 | if (f2fs_has_inline_data(inode)) { | 245 | if (f2fs_has_inline_data(inode)) { |
| 254 | ipage = get_node_page(sbi, inode->i_ino); | 246 | ipage = get_node_page(sbi, inode->i_ino); |
| 255 | f2fs_bug_on(sbi, IS_ERR(ipage)); | 247 | f2fs_bug_on(sbi, IS_ERR(ipage)); |
| 256 | truncate_inline_data(ipage, 0); | 248 | truncate_inline_data(ipage); |
| 257 | f2fs_clear_inline_inode(inode); | 249 | f2fs_clear_inline_inode(inode); |
| 258 | update_inode(inode, ipage); | 250 | update_inode(inode, ipage); |
| 259 | f2fs_put_page(ipage, 1); | 251 | f2fs_put_page(ipage, 1); |
| @@ -371,7 +363,7 @@ static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, | |||
| 371 | set_page_dirty(page); | 363 | set_page_dirty(page); |
| 372 | 364 | ||
| 373 | /* clear inline dir and flag after data writeback */ | 365 | /* clear inline dir and flag after data writeback */ |
| 374 | truncate_inline_data(ipage, 0); | 366 | truncate_inline_data(ipage); |
| 375 | 367 | ||
| 376 | stat_dec_inline_dir(dir); | 368 | stat_dec_inline_dir(dir); |
| 377 | clear_inode_flag(F2FS_I(dir), FI_INLINE_DENTRY); | 369 | clear_inode_flag(F2FS_I(dir), FI_INLINE_DENTRY); |
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 196cc7843aaf..2d002e3738a7 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c | |||
| @@ -67,29 +67,23 @@ static void __set_inode_rdev(struct inode *inode, struct f2fs_inode *ri) | |||
| 67 | } | 67 | } |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | static int __recover_inline_status(struct inode *inode, struct page *ipage) | 70 | static void __recover_inline_status(struct inode *inode, struct page *ipage) |
| 71 | { | 71 | { |
| 72 | void *inline_data = inline_data_addr(ipage); | 72 | void *inline_data = inline_data_addr(ipage); |
| 73 | struct f2fs_inode *ri; | 73 | __le32 *start = inline_data; |
| 74 | void *zbuf; | 74 | __le32 *end = start + MAX_INLINE_DATA / sizeof(__le32); |
| 75 | 75 | ||
| 76 | zbuf = kzalloc(MAX_INLINE_DATA, GFP_NOFS); | 76 | while (start < end) { |
| 77 | if (!zbuf) | 77 | if (*start++) { |
| 78 | return -ENOMEM; | 78 | f2fs_wait_on_page_writeback(ipage, NODE); |
| 79 | 79 | ||
| 80 | if (!memcmp(zbuf, inline_data, MAX_INLINE_DATA)) { | 80 | set_inode_flag(F2FS_I(inode), FI_DATA_EXIST); |
| 81 | kfree(zbuf); | 81 | set_raw_inline(F2FS_I(inode), F2FS_INODE(ipage)); |
| 82 | return 0; | 82 | set_page_dirty(ipage); |
| 83 | return; | ||
| 84 | } | ||
| 83 | } | 85 | } |
| 84 | kfree(zbuf); | 86 | return; |
| 85 | |||
| 86 | f2fs_wait_on_page_writeback(ipage, NODE); | ||
| 87 | set_inode_flag(F2FS_I(inode), FI_DATA_EXIST); | ||
| 88 | |||
| 89 | ri = F2FS_INODE(ipage); | ||
| 90 | set_raw_inline(F2FS_I(inode), ri); | ||
| 91 | set_page_dirty(ipage); | ||
| 92 | return 0; | ||
| 93 | } | 87 | } |
| 94 | 88 | ||
| 95 | static int do_read_inode(struct inode *inode) | 89 | static int do_read_inode(struct inode *inode) |
| @@ -98,7 +92,6 @@ static int do_read_inode(struct inode *inode) | |||
| 98 | struct f2fs_inode_info *fi = F2FS_I(inode); | 92 | struct f2fs_inode_info *fi = F2FS_I(inode); |
| 99 | struct page *node_page; | 93 | struct page *node_page; |
| 100 | struct f2fs_inode *ri; | 94 | struct f2fs_inode *ri; |
| 101 | int err = 0; | ||
| 102 | 95 | ||
| 103 | /* Check if ino is within scope */ | 96 | /* Check if ino is within scope */ |
| 104 | if (check_nid_range(sbi, inode->i_ino)) { | 97 | if (check_nid_range(sbi, inode->i_ino)) { |
| @@ -142,7 +135,7 @@ static int do_read_inode(struct inode *inode) | |||
| 142 | 135 | ||
| 143 | /* check data exist */ | 136 | /* check data exist */ |
| 144 | if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode)) | 137 | if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode)) |
| 145 | err = __recover_inline_status(inode, node_page); | 138 | __recover_inline_status(inode, node_page); |
| 146 | 139 | ||
| 147 | /* get rdev by using inline_info */ | 140 | /* get rdev by using inline_info */ |
| 148 | __get_inode_rdev(inode, ri); | 141 | __get_inode_rdev(inode, ri); |
| @@ -152,7 +145,7 @@ static int do_read_inode(struct inode *inode) | |||
| 152 | stat_inc_inline_inode(inode); | 145 | stat_inc_inline_inode(inode); |
| 153 | stat_inc_inline_dir(inode); | 146 | stat_inc_inline_dir(inode); |
| 154 | 147 | ||
| 155 | return err; | 148 | return 0; |
| 156 | } | 149 | } |
| 157 | 150 | ||
| 158 | struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) | 151 | struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) |
| @@ -304,7 +297,7 @@ void f2fs_evict_inode(struct inode *inode) | |||
| 304 | nid_t xnid = F2FS_I(inode)->i_xattr_nid; | 297 | nid_t xnid = F2FS_I(inode)->i_xattr_nid; |
| 305 | 298 | ||
| 306 | /* some remained atomic pages should discarded */ | 299 | /* some remained atomic pages should discarded */ |
| 307 | if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) | 300 | if (f2fs_is_atomic_file(inode)) |
| 308 | commit_inmem_pages(inode, true); | 301 | commit_inmem_pages(inode, true); |
| 309 | 302 | ||
| 310 | trace_f2fs_evict_inode(inode); | 303 | trace_f2fs_evict_inode(inode); |
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 547a2deeb1ac..e79639a9787a 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c | |||
| @@ -299,7 +299,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
| 299 | inode->i_op = &f2fs_dir_inode_operations; | 299 | inode->i_op = &f2fs_dir_inode_operations; |
| 300 | inode->i_fop = &f2fs_dir_operations; | 300 | inode->i_fop = &f2fs_dir_operations; |
| 301 | inode->i_mapping->a_ops = &f2fs_dblock_aops; | 301 | inode->i_mapping->a_ops = &f2fs_dblock_aops; |
| 302 | mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO); | 302 | mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO); |
| 303 | 303 | ||
| 304 | set_inode_flag(F2FS_I(inode), FI_INC_LINK); | 304 | set_inode_flag(F2FS_I(inode), FI_INC_LINK); |
| 305 | f2fs_lock_op(sbi); | 305 | f2fs_lock_op(sbi); |
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index f83326ca32ef..97bd9d3db882 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include "f2fs.h" | 19 | #include "f2fs.h" |
| 20 | #include "node.h" | 20 | #include "node.h" |
| 21 | #include "segment.h" | 21 | #include "segment.h" |
| 22 | #include "trace.h" | ||
| 22 | #include <trace/events/f2fs.h> | 23 | #include <trace/events/f2fs.h> |
| 23 | 24 | ||
| 24 | #define on_build_free_nids(nmi) mutex_is_locked(&nm_i->build_lock) | 25 | #define on_build_free_nids(nmi) mutex_is_locked(&nm_i->build_lock) |
| @@ -57,12 +58,13 @@ bool available_free_memory(struct f2fs_sb_info *sbi, int type) | |||
| 57 | } else if (type == INO_ENTRIES) { | 58 | } else if (type == INO_ENTRIES) { |
| 58 | int i; | 59 | int i; |
| 59 | 60 | ||
| 60 | if (sbi->sb->s_bdi->dirty_exceeded) | ||
| 61 | return false; | ||
| 62 | for (i = 0; i <= UPDATE_INO; i++) | 61 | for (i = 0; i <= UPDATE_INO; i++) |
| 63 | mem_size += (sbi->im[i].ino_num * | 62 | mem_size += (sbi->im[i].ino_num * |
| 64 | sizeof(struct ino_entry)) >> PAGE_CACHE_SHIFT; | 63 | sizeof(struct ino_entry)) >> PAGE_CACHE_SHIFT; |
| 65 | res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1); | 64 | res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1); |
| 65 | } else { | ||
| 66 | if (sbi->sb->s_bdi->dirty_exceeded) | ||
| 67 | return false; | ||
| 66 | } | 68 | } |
| 67 | return res; | 69 | return res; |
| 68 | } | 70 | } |
| @@ -268,7 +270,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni, | |||
| 268 | e = __lookup_nat_cache(nm_i, ni->nid); | 270 | e = __lookup_nat_cache(nm_i, ni->nid); |
| 269 | if (!e) { | 271 | if (!e) { |
| 270 | e = grab_nat_entry(nm_i, ni->nid); | 272 | e = grab_nat_entry(nm_i, ni->nid); |
| 271 | e->ni = *ni; | 273 | copy_node_info(&e->ni, ni); |
| 272 | f2fs_bug_on(sbi, ni->blk_addr == NEW_ADDR); | 274 | f2fs_bug_on(sbi, ni->blk_addr == NEW_ADDR); |
| 273 | } else if (new_blkaddr == NEW_ADDR) { | 275 | } else if (new_blkaddr == NEW_ADDR) { |
| 274 | /* | 276 | /* |
| @@ -276,7 +278,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni, | |||
| 276 | * previous nat entry can be remained in nat cache. | 278 | * previous nat entry can be remained in nat cache. |
| 277 | * So, reinitialize it with new information. | 279 | * So, reinitialize it with new information. |
| 278 | */ | 280 | */ |
| 279 | e->ni = *ni; | 281 | copy_node_info(&e->ni, ni); |
| 280 | f2fs_bug_on(sbi, ni->blk_addr != NULL_ADDR); | 282 | f2fs_bug_on(sbi, ni->blk_addr != NULL_ADDR); |
| 281 | } | 283 | } |
| 282 | 284 | ||
| @@ -346,7 +348,6 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) | |||
| 346 | struct nat_entry *e; | 348 | struct nat_entry *e; |
| 347 | int i; | 349 | int i; |
| 348 | 350 | ||
| 349 | memset(&ne, 0, sizeof(struct f2fs_nat_entry)); | ||
| 350 | ni->nid = nid; | 351 | ni->nid = nid; |
| 351 | 352 | ||
| 352 | /* Check nat cache */ | 353 | /* Check nat cache */ |
| @@ -361,6 +362,8 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) | |||
| 361 | if (e) | 362 | if (e) |
| 362 | return; | 363 | return; |
| 363 | 364 | ||
| 365 | memset(&ne, 0, sizeof(struct f2fs_nat_entry)); | ||
| 366 | |||
| 364 | /* Check current segment summary */ | 367 | /* Check current segment summary */ |
| 365 | mutex_lock(&curseg->curseg_mutex); | 368 | mutex_lock(&curseg->curseg_mutex); |
| 366 | i = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 0); | 369 | i = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 0); |
| @@ -471,7 +474,7 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode) | |||
| 471 | { | 474 | { |
| 472 | struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); | 475 | struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); |
| 473 | struct page *npage[4]; | 476 | struct page *npage[4]; |
| 474 | struct page *parent; | 477 | struct page *parent = NULL; |
| 475 | int offset[4]; | 478 | int offset[4]; |
| 476 | unsigned int noffset[4]; | 479 | unsigned int noffset[4]; |
| 477 | nid_t nids[4]; | 480 | nid_t nids[4]; |
| @@ -488,6 +491,14 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode) | |||
| 488 | if (IS_ERR(npage[0])) | 491 | if (IS_ERR(npage[0])) |
| 489 | return PTR_ERR(npage[0]); | 492 | return PTR_ERR(npage[0]); |
| 490 | } | 493 | } |
| 494 | |||
| 495 | /* if inline_data is set, should not report any block indices */ | ||
| 496 | if (f2fs_has_inline_data(dn->inode) && index) { | ||
| 497 | err = -EINVAL; | ||
| 498 | f2fs_put_page(npage[0], 1); | ||
| 499 | goto release_out; | ||
| 500 | } | ||
| 501 | |||
| 491 | parent = npage[0]; | 502 | parent = npage[0]; |
| 492 | if (level != 0) | 503 | if (level != 0) |
| 493 | nids[1] = get_nid(parent, offset[0], true); | 504 | nids[1] = get_nid(parent, offset[0], true); |
| @@ -585,7 +596,7 @@ static void truncate_node(struct dnode_of_data *dn) | |||
| 585 | } | 596 | } |
| 586 | invalidate: | 597 | invalidate: |
| 587 | clear_node_page_dirty(dn->node_page); | 598 | clear_node_page_dirty(dn->node_page); |
| 588 | F2FS_SET_SB_DIRT(sbi); | 599 | set_sbi_flag(sbi, SBI_IS_DIRTY); |
| 589 | 600 | ||
| 590 | f2fs_put_page(dn->node_page, 1); | 601 | f2fs_put_page(dn->node_page, 1); |
| 591 | 602 | ||
| @@ -976,6 +987,10 @@ static int read_node_page(struct page *page, int rw) | |||
| 976 | { | 987 | { |
| 977 | struct f2fs_sb_info *sbi = F2FS_P_SB(page); | 988 | struct f2fs_sb_info *sbi = F2FS_P_SB(page); |
| 978 | struct node_info ni; | 989 | struct node_info ni; |
| 990 | struct f2fs_io_info fio = { | ||
| 991 | .type = NODE, | ||
| 992 | .rw = rw, | ||
| 993 | }; | ||
| 979 | 994 | ||
| 980 | get_node_info(sbi, page->index, &ni); | 995 | get_node_info(sbi, page->index, &ni); |
| 981 | 996 | ||
| @@ -987,7 +1002,8 @@ static int read_node_page(struct page *page, int rw) | |||
| 987 | if (PageUptodate(page)) | 1002 | if (PageUptodate(page)) |
| 988 | return LOCKED_PAGE; | 1003 | return LOCKED_PAGE; |
| 989 | 1004 | ||
| 990 | return f2fs_submit_page_bio(sbi, page, ni.blk_addr, rw); | 1005 | fio.blk_addr = ni.blk_addr; |
| 1006 | return f2fs_submit_page_bio(sbi, page, &fio); | ||
| 991 | } | 1007 | } |
| 992 | 1008 | ||
| 993 | /* | 1009 | /* |
| @@ -1028,11 +1044,11 @@ repeat: | |||
| 1028 | err = read_node_page(page, READ_SYNC); | 1044 | err = read_node_page(page, READ_SYNC); |
| 1029 | if (err < 0) | 1045 | if (err < 0) |
| 1030 | return ERR_PTR(err); | 1046 | return ERR_PTR(err); |
| 1031 | else if (err == LOCKED_PAGE) | 1047 | else if (err != LOCKED_PAGE) |
| 1032 | goto got_it; | 1048 | lock_page(page); |
| 1033 | 1049 | ||
| 1034 | lock_page(page); | ||
| 1035 | if (unlikely(!PageUptodate(page) || nid != nid_of_node(page))) { | 1050 | if (unlikely(!PageUptodate(page) || nid != nid_of_node(page))) { |
| 1051 | ClearPageUptodate(page); | ||
| 1036 | f2fs_put_page(page, 1); | 1052 | f2fs_put_page(page, 1); |
| 1037 | return ERR_PTR(-EIO); | 1053 | return ERR_PTR(-EIO); |
| 1038 | } | 1054 | } |
| @@ -1040,7 +1056,6 @@ repeat: | |||
| 1040 | f2fs_put_page(page, 1); | 1056 | f2fs_put_page(page, 1); |
| 1041 | goto repeat; | 1057 | goto repeat; |
| 1042 | } | 1058 | } |
| 1043 | got_it: | ||
| 1044 | return page; | 1059 | return page; |
| 1045 | } | 1060 | } |
| 1046 | 1061 | ||
| @@ -1268,7 +1283,6 @@ static int f2fs_write_node_page(struct page *page, | |||
| 1268 | { | 1283 | { |
| 1269 | struct f2fs_sb_info *sbi = F2FS_P_SB(page); | 1284 | struct f2fs_sb_info *sbi = F2FS_P_SB(page); |
| 1270 | nid_t nid; | 1285 | nid_t nid; |
| 1271 | block_t new_addr; | ||
| 1272 | struct node_info ni; | 1286 | struct node_info ni; |
| 1273 | struct f2fs_io_info fio = { | 1287 | struct f2fs_io_info fio = { |
| 1274 | .type = NODE, | 1288 | .type = NODE, |
| @@ -1277,7 +1291,7 @@ static int f2fs_write_node_page(struct page *page, | |||
| 1277 | 1291 | ||
| 1278 | trace_f2fs_writepage(page, NODE); | 1292 | trace_f2fs_writepage(page, NODE); |
| 1279 | 1293 | ||
| 1280 | if (unlikely(sbi->por_doing)) | 1294 | if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) |
| 1281 | goto redirty_out; | 1295 | goto redirty_out; |
| 1282 | if (unlikely(f2fs_cp_error(sbi))) | 1296 | if (unlikely(f2fs_cp_error(sbi))) |
| 1283 | goto redirty_out; | 1297 | goto redirty_out; |
| @@ -1303,9 +1317,11 @@ static int f2fs_write_node_page(struct page *page, | |||
| 1303 | } else { | 1317 | } else { |
| 1304 | down_read(&sbi->node_write); | 1318 | down_read(&sbi->node_write); |
| 1305 | } | 1319 | } |
| 1320 | |||
| 1306 | set_page_writeback(page); | 1321 | set_page_writeback(page); |
| 1307 | write_node_page(sbi, page, &fio, nid, ni.blk_addr, &new_addr); | 1322 | fio.blk_addr = ni.blk_addr; |
| 1308 | set_node_addr(sbi, &ni, new_addr, is_fsync_dnode(page)); | 1323 | write_node_page(sbi, page, nid, &fio); |
| 1324 | set_node_addr(sbi, &ni, fio.blk_addr, is_fsync_dnode(page)); | ||
| 1309 | dec_page_count(sbi, F2FS_DIRTY_NODES); | 1325 | dec_page_count(sbi, F2FS_DIRTY_NODES); |
| 1310 | up_read(&sbi->node_write); | 1326 | up_read(&sbi->node_write); |
| 1311 | unlock_page(page); | 1327 | unlock_page(page); |
| @@ -1355,26 +1371,12 @@ static int f2fs_set_node_page_dirty(struct page *page) | |||
| 1355 | __set_page_dirty_nobuffers(page); | 1371 | __set_page_dirty_nobuffers(page); |
| 1356 | inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_NODES); | 1372 | inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_NODES); |
| 1357 | SetPagePrivate(page); | 1373 | SetPagePrivate(page); |
| 1374 | f2fs_trace_pid(page); | ||
| 1358 | return 1; | 1375 | return 1; |
| 1359 | } | 1376 | } |
| 1360 | return 0; | 1377 | return 0; |
| 1361 | } | 1378 | } |
| 1362 | 1379 | ||
| 1363 | static void f2fs_invalidate_node_page(struct page *page, unsigned int offset, | ||
| 1364 | unsigned int length) | ||
| 1365 | { | ||
| 1366 | struct inode *inode = page->mapping->host; | ||
| 1367 | if (PageDirty(page)) | ||
| 1368 | dec_page_count(F2FS_I_SB(inode), F2FS_DIRTY_NODES); | ||
| 1369 | ClearPagePrivate(page); | ||
| 1370 | } | ||
| 1371 | |||
| 1372 | static int f2fs_release_node_page(struct page *page, gfp_t wait) | ||
| 1373 | { | ||
| 1374 | ClearPagePrivate(page); | ||
| 1375 | return 1; | ||
| 1376 | } | ||
| 1377 | |||
| 1378 | /* | 1380 | /* |
| 1379 | * Structure of the f2fs node operations | 1381 | * Structure of the f2fs node operations |
| 1380 | */ | 1382 | */ |
| @@ -1382,8 +1384,8 @@ const struct address_space_operations f2fs_node_aops = { | |||
| 1382 | .writepage = f2fs_write_node_page, | 1384 | .writepage = f2fs_write_node_page, |
| 1383 | .writepages = f2fs_write_node_pages, | 1385 | .writepages = f2fs_write_node_pages, |
| 1384 | .set_page_dirty = f2fs_set_node_page_dirty, | 1386 | .set_page_dirty = f2fs_set_node_page_dirty, |
| 1385 | .invalidatepage = f2fs_invalidate_node_page, | 1387 | .invalidatepage = f2fs_invalidate_page, |
| 1386 | .releasepage = f2fs_release_node_page, | 1388 | .releasepage = f2fs_release_page, |
| 1387 | }; | 1389 | }; |
| 1388 | 1390 | ||
| 1389 | static struct free_nid *__lookup_free_nid_list(struct f2fs_nm_info *nm_i, | 1391 | static struct free_nid *__lookup_free_nid_list(struct f2fs_nm_info *nm_i, |
| @@ -1726,80 +1728,41 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) | |||
| 1726 | return 0; | 1728 | return 0; |
| 1727 | } | 1729 | } |
| 1728 | 1730 | ||
| 1729 | /* | ||
| 1730 | * ra_sum_pages() merge contiguous pages into one bio and submit. | ||
| 1731 | * these pre-read pages are allocated in bd_inode's mapping tree. | ||
| 1732 | */ | ||
| 1733 | static int ra_sum_pages(struct f2fs_sb_info *sbi, struct page **pages, | ||
| 1734 | int start, int nrpages) | ||
| 1735 | { | ||
| 1736 | struct inode *inode = sbi->sb->s_bdev->bd_inode; | ||
| 1737 | struct address_space *mapping = inode->i_mapping; | ||
| 1738 | int i, page_idx = start; | ||
| 1739 | struct f2fs_io_info fio = { | ||
| 1740 | .type = META, | ||
| 1741 | .rw = READ_SYNC | REQ_META | REQ_PRIO | ||
| 1742 | }; | ||
| 1743 | |||
| 1744 | for (i = 0; page_idx < start + nrpages; page_idx++, i++) { | ||
| 1745 | /* alloc page in bd_inode for reading node summary info */ | ||
| 1746 | pages[i] = grab_cache_page(mapping, page_idx); | ||
| 1747 | if (!pages[i]) | ||
| 1748 | break; | ||
| 1749 | f2fs_submit_page_mbio(sbi, pages[i], page_idx, &fio); | ||
| 1750 | } | ||
| 1751 | |||
| 1752 | f2fs_submit_merged_bio(sbi, META, READ); | ||
| 1753 | return i; | ||
| 1754 | } | ||
| 1755 | |||
| 1756 | int restore_node_summary(struct f2fs_sb_info *sbi, | 1731 | int restore_node_summary(struct f2fs_sb_info *sbi, |
| 1757 | unsigned int segno, struct f2fs_summary_block *sum) | 1732 | unsigned int segno, struct f2fs_summary_block *sum) |
| 1758 | { | 1733 | { |
| 1759 | struct f2fs_node *rn; | 1734 | struct f2fs_node *rn; |
| 1760 | struct f2fs_summary *sum_entry; | 1735 | struct f2fs_summary *sum_entry; |
| 1761 | struct inode *inode = sbi->sb->s_bdev->bd_inode; | ||
| 1762 | block_t addr; | 1736 | block_t addr; |
| 1763 | int bio_blocks = MAX_BIO_BLOCKS(sbi); | 1737 | int bio_blocks = MAX_BIO_BLOCKS(sbi); |
| 1764 | struct page *pages[bio_blocks]; | 1738 | int i, idx, last_offset, nrpages; |
| 1765 | int i, idx, last_offset, nrpages, err = 0; | ||
| 1766 | 1739 | ||
| 1767 | /* scan the node segment */ | 1740 | /* scan the node segment */ |
| 1768 | last_offset = sbi->blocks_per_seg; | 1741 | last_offset = sbi->blocks_per_seg; |
| 1769 | addr = START_BLOCK(sbi, segno); | 1742 | addr = START_BLOCK(sbi, segno); |
| 1770 | sum_entry = &sum->entries[0]; | 1743 | sum_entry = &sum->entries[0]; |
| 1771 | 1744 | ||
| 1772 | for (i = 0; !err && i < last_offset; i += nrpages, addr += nrpages) { | 1745 | for (i = 0; i < last_offset; i += nrpages, addr += nrpages) { |
| 1773 | nrpages = min(last_offset - i, bio_blocks); | 1746 | nrpages = min(last_offset - i, bio_blocks); |
| 1774 | 1747 | ||
| 1775 | /* readahead node pages */ | 1748 | /* readahead node pages */ |
| 1776 | nrpages = ra_sum_pages(sbi, pages, addr, nrpages); | 1749 | ra_meta_pages(sbi, addr, nrpages, META_POR); |
| 1777 | if (!nrpages) | ||
| 1778 | return -ENOMEM; | ||
| 1779 | 1750 | ||
| 1780 | for (idx = 0; idx < nrpages; idx++) { | 1751 | for (idx = addr; idx < addr + nrpages; idx++) { |
| 1781 | if (err) | 1752 | struct page *page = get_meta_page(sbi, idx); |
| 1782 | goto skip; | ||
| 1783 | 1753 | ||
| 1784 | lock_page(pages[idx]); | 1754 | rn = F2FS_NODE(page); |
| 1785 | if (unlikely(!PageUptodate(pages[idx]))) { | 1755 | sum_entry->nid = rn->footer.nid; |
| 1786 | err = -EIO; | 1756 | sum_entry->version = 0; |
| 1787 | } else { | 1757 | sum_entry->ofs_in_node = 0; |
| 1788 | rn = F2FS_NODE(pages[idx]); | 1758 | sum_entry++; |
| 1789 | sum_entry->nid = rn->footer.nid; | 1759 | f2fs_put_page(page, 1); |
| 1790 | sum_entry->version = 0; | ||
| 1791 | sum_entry->ofs_in_node = 0; | ||
| 1792 | sum_entry++; | ||
| 1793 | } | ||
| 1794 | unlock_page(pages[idx]); | ||
| 1795 | skip: | ||
| 1796 | page_cache_release(pages[idx]); | ||
| 1797 | } | 1760 | } |
| 1798 | 1761 | ||
| 1799 | invalidate_mapping_pages(inode->i_mapping, addr, | 1762 | invalidate_mapping_pages(META_MAPPING(sbi), addr, |
| 1800 | addr + nrpages); | 1763 | addr + nrpages); |
| 1801 | } | 1764 | } |
| 1802 | return err; | 1765 | return 0; |
| 1803 | } | 1766 | } |
| 1804 | 1767 | ||
| 1805 | static void remove_nats_in_journal(struct f2fs_sb_info *sbi) | 1768 | static void remove_nats_in_journal(struct f2fs_sb_info *sbi) |
| @@ -1923,7 +1886,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi) | |||
| 1923 | struct f2fs_nm_info *nm_i = NM_I(sbi); | 1886 | struct f2fs_nm_info *nm_i = NM_I(sbi); |
| 1924 | struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); | 1887 | struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); |
| 1925 | struct f2fs_summary_block *sum = curseg->sum_blk; | 1888 | struct f2fs_summary_block *sum = curseg->sum_blk; |
| 1926 | struct nat_entry_set *setvec[NATVEC_SIZE]; | 1889 | struct nat_entry_set *setvec[SETVEC_SIZE]; |
| 1927 | struct nat_entry_set *set, *tmp; | 1890 | struct nat_entry_set *set, *tmp; |
| 1928 | unsigned int found; | 1891 | unsigned int found; |
| 1929 | nid_t set_idx = 0; | 1892 | nid_t set_idx = 0; |
| @@ -1940,7 +1903,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi) | |||
| 1940 | remove_nats_in_journal(sbi); | 1903 | remove_nats_in_journal(sbi); |
| 1941 | 1904 | ||
| 1942 | while ((found = __gang_lookup_nat_set(nm_i, | 1905 | while ((found = __gang_lookup_nat_set(nm_i, |
| 1943 | set_idx, NATVEC_SIZE, setvec))) { | 1906 | set_idx, SETVEC_SIZE, setvec))) { |
| 1944 | unsigned idx; | 1907 | unsigned idx; |
| 1945 | set_idx = setvec[found - 1]->set + 1; | 1908 | set_idx = setvec[found - 1]->set + 1; |
| 1946 | for (idx = 0; idx < found; idx++) | 1909 | for (idx = 0; idx < found; idx++) |
| @@ -2020,6 +1983,7 @@ void destroy_node_manager(struct f2fs_sb_info *sbi) | |||
| 2020 | struct f2fs_nm_info *nm_i = NM_I(sbi); | 1983 | struct f2fs_nm_info *nm_i = NM_I(sbi); |
| 2021 | struct free_nid *i, *next_i; | 1984 | struct free_nid *i, *next_i; |
| 2022 | struct nat_entry *natvec[NATVEC_SIZE]; | 1985 | struct nat_entry *natvec[NATVEC_SIZE]; |
| 1986 | struct nat_entry_set *setvec[SETVEC_SIZE]; | ||
| 2023 | nid_t nid = 0; | 1987 | nid_t nid = 0; |
| 2024 | unsigned int found; | 1988 | unsigned int found; |
| 2025 | 1989 | ||
| @@ -2044,11 +2008,27 @@ void destroy_node_manager(struct f2fs_sb_info *sbi) | |||
| 2044 | while ((found = __gang_lookup_nat_cache(nm_i, | 2008 | while ((found = __gang_lookup_nat_cache(nm_i, |
| 2045 | nid, NATVEC_SIZE, natvec))) { | 2009 | nid, NATVEC_SIZE, natvec))) { |
| 2046 | unsigned idx; | 2010 | unsigned idx; |
| 2011 | |||
| 2047 | nid = nat_get_nid(natvec[found - 1]) + 1; | 2012 | nid = nat_get_nid(natvec[found - 1]) + 1; |
| 2048 | for (idx = 0; idx < found; idx++) | 2013 | for (idx = 0; idx < found; idx++) |
| 2049 | __del_from_nat_cache(nm_i, natvec[idx]); | 2014 | __del_from_nat_cache(nm_i, natvec[idx]); |
| 2050 | } | 2015 | } |
| 2051 | f2fs_bug_on(sbi, nm_i->nat_cnt); | 2016 | f2fs_bug_on(sbi, nm_i->nat_cnt); |
| 2017 | |||
| 2018 | /* destroy nat set cache */ | ||
| 2019 | nid = 0; | ||
| 2020 | while ((found = __gang_lookup_nat_set(nm_i, | ||
| 2021 | nid, SETVEC_SIZE, setvec))) { | ||
| 2022 | unsigned idx; | ||
| 2023 | |||
| 2024 | nid = setvec[found - 1]->set + 1; | ||
| 2025 | for (idx = 0; idx < found; idx++) { | ||
| 2026 | /* entry_cnt is not zero, when cp_error was occurred */ | ||
| 2027 | f2fs_bug_on(sbi, !list_empty(&setvec[idx]->entry_list)); | ||
| 2028 | radix_tree_delete(&nm_i->nat_set_root, setvec[idx]->set); | ||
| 2029 | kmem_cache_free(nat_entry_set_slab, setvec[idx]); | ||
| 2030 | } | ||
| 2031 | } | ||
| 2052 | up_write(&nm_i->nat_tree_lock); | 2032 | up_write(&nm_i->nat_tree_lock); |
| 2053 | 2033 | ||
| 2054 | kfree(nm_i->nat_bitmap); | 2034 | kfree(nm_i->nat_bitmap); |
diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index d10b6448a671..f405bbf2435a 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h | |||
| @@ -25,10 +25,19 @@ | |||
| 25 | 25 | ||
| 26 | /* vector size for gang look-up from nat cache that consists of radix tree */ | 26 | /* vector size for gang look-up from nat cache that consists of radix tree */ |
| 27 | #define NATVEC_SIZE 64 | 27 | #define NATVEC_SIZE 64 |
| 28 | #define SETVEC_SIZE 32 | ||
| 28 | 29 | ||
| 29 | /* return value for read_node_page */ | 30 | /* return value for read_node_page */ |
| 30 | #define LOCKED_PAGE 1 | 31 | #define LOCKED_PAGE 1 |
| 31 | 32 | ||
| 33 | /* For flag in struct node_info */ | ||
| 34 | enum { | ||
| 35 | IS_CHECKPOINTED, /* is it checkpointed before? */ | ||
| 36 | HAS_FSYNCED_INODE, /* is the inode fsynced before? */ | ||
| 37 | HAS_LAST_FSYNC, /* has the latest node fsync mark? */ | ||
| 38 | IS_DIRTY, /* this nat entry is dirty? */ | ||
| 39 | }; | ||
| 40 | |||
| 32 | /* | 41 | /* |
| 33 | * For node information | 42 | * For node information |
| 34 | */ | 43 | */ |
| @@ -37,18 +46,11 @@ struct node_info { | |||
| 37 | nid_t ino; /* inode number of the node's owner */ | 46 | nid_t ino; /* inode number of the node's owner */ |
| 38 | block_t blk_addr; /* block address of the node */ | 47 | block_t blk_addr; /* block address of the node */ |
| 39 | unsigned char version; /* version of the node */ | 48 | unsigned char version; /* version of the node */ |
| 40 | }; | 49 | unsigned char flag; /* for node information bits */ |
| 41 | |||
| 42 | enum { | ||
| 43 | IS_CHECKPOINTED, /* is it checkpointed before? */ | ||
| 44 | HAS_FSYNCED_INODE, /* is the inode fsynced before? */ | ||
| 45 | HAS_LAST_FSYNC, /* has the latest node fsync mark? */ | ||
| 46 | IS_DIRTY, /* this nat entry is dirty? */ | ||
| 47 | }; | 50 | }; |
| 48 | 51 | ||
| 49 | struct nat_entry { | 52 | struct nat_entry { |
| 50 | struct list_head list; /* for clean or dirty nat list */ | 53 | struct list_head list; /* for clean or dirty nat list */ |
| 51 | unsigned char flag; /* for node information bits */ | ||
| 52 | struct node_info ni; /* in-memory node information */ | 54 | struct node_info ni; /* in-memory node information */ |
| 53 | }; | 55 | }; |
| 54 | 56 | ||
| @@ -63,20 +65,30 @@ struct nat_entry { | |||
| 63 | 65 | ||
| 64 | #define inc_node_version(version) (++version) | 66 | #define inc_node_version(version) (++version) |
| 65 | 67 | ||
| 68 | static inline void copy_node_info(struct node_info *dst, | ||
| 69 | struct node_info *src) | ||
| 70 | { | ||
| 71 | dst->nid = src->nid; | ||
| 72 | dst->ino = src->ino; | ||
| 73 | dst->blk_addr = src->blk_addr; | ||
| 74 | dst->version = src->version; | ||
| 75 | /* should not copy flag here */ | ||
| 76 | } | ||
| 77 | |||
| 66 | static inline void set_nat_flag(struct nat_entry *ne, | 78 | static inline void set_nat_flag(struct nat_entry *ne, |
| 67 | unsigned int type, bool set) | 79 | unsigned int type, bool set) |
| 68 | { | 80 | { |
| 69 | unsigned char mask = 0x01 << type; | 81 | unsigned char mask = 0x01 << type; |
| 70 | if (set) | 82 | if (set) |
| 71 | ne->flag |= mask; | 83 | ne->ni.flag |= mask; |
| 72 | else | 84 | else |
| 73 | ne->flag &= ~mask; | 85 | ne->ni.flag &= ~mask; |
| 74 | } | 86 | } |
| 75 | 87 | ||
| 76 | static inline bool get_nat_flag(struct nat_entry *ne, unsigned int type) | 88 | static inline bool get_nat_flag(struct nat_entry *ne, unsigned int type) |
| 77 | { | 89 | { |
| 78 | unsigned char mask = 0x01 << type; | 90 | unsigned char mask = 0x01 << type; |
| 79 | return ne->flag & mask; | 91 | return ne->ni.flag & mask; |
| 80 | } | 92 | } |
| 81 | 93 | ||
| 82 | static inline void nat_reset_flag(struct nat_entry *ne) | 94 | static inline void nat_reset_flag(struct nat_entry *ne) |
| @@ -108,6 +120,7 @@ enum mem_type { | |||
| 108 | NAT_ENTRIES, /* indicates the cached nat entry */ | 120 | NAT_ENTRIES, /* indicates the cached nat entry */ |
| 109 | DIRTY_DENTS, /* indicates dirty dentry pages */ | 121 | DIRTY_DENTS, /* indicates dirty dentry pages */ |
| 110 | INO_ENTRIES, /* indicates inode entries */ | 122 | INO_ENTRIES, /* indicates inode entries */ |
| 123 | BASE_CHECK, /* check kernel status */ | ||
| 111 | }; | 124 | }; |
| 112 | 125 | ||
| 113 | struct nat_entry_set { | 126 | struct nat_entry_set { |
| @@ -200,11 +213,19 @@ static inline void fill_node_footer(struct page *page, nid_t nid, | |||
| 200 | nid_t ino, unsigned int ofs, bool reset) | 213 | nid_t ino, unsigned int ofs, bool reset) |
| 201 | { | 214 | { |
| 202 | struct f2fs_node *rn = F2FS_NODE(page); | 215 | struct f2fs_node *rn = F2FS_NODE(page); |
| 216 | unsigned int old_flag = 0; | ||
| 217 | |||
| 203 | if (reset) | 218 | if (reset) |
| 204 | memset(rn, 0, sizeof(*rn)); | 219 | memset(rn, 0, sizeof(*rn)); |
| 220 | else | ||
| 221 | old_flag = le32_to_cpu(rn->footer.flag); | ||
| 222 | |||
| 205 | rn->footer.nid = cpu_to_le32(nid); | 223 | rn->footer.nid = cpu_to_le32(nid); |
| 206 | rn->footer.ino = cpu_to_le32(ino); | 224 | rn->footer.ino = cpu_to_le32(ino); |
| 207 | rn->footer.flag = cpu_to_le32(ofs << OFFSET_BIT_SHIFT); | 225 | |
| 226 | /* should remain old flag bits such as COLD_BIT_SHIFT */ | ||
| 227 | rn->footer.flag = cpu_to_le32((ofs << OFFSET_BIT_SHIFT) | | ||
| 228 | (old_flag & OFFSET_BIT_MASK)); | ||
| 208 | } | 229 | } |
| 209 | 230 | ||
| 210 | static inline void copy_node_footer(struct page *dst, struct page *src) | 231 | static inline void copy_node_footer(struct page *dst, struct page *src) |
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 9160a37e1c7a..41afb9534bbd 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c | |||
| @@ -346,6 +346,10 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, | |||
| 346 | if (IS_INODE(page)) { | 346 | if (IS_INODE(page)) { |
| 347 | recover_inline_xattr(inode, page); | 347 | recover_inline_xattr(inode, page); |
| 348 | } else if (f2fs_has_xattr_block(ofs_of_node(page))) { | 348 | } else if (f2fs_has_xattr_block(ofs_of_node(page))) { |
| 349 | /* | ||
| 350 | * Deprecated; xattr blocks should be found from cold log. | ||
| 351 | * But, we should remain this for backward compatibility. | ||
| 352 | */ | ||
| 349 | recover_xattr_data(inode, page, blkaddr); | 353 | recover_xattr_data(inode, page, blkaddr); |
| 350 | goto out; | 354 | goto out; |
| 351 | } | 355 | } |
| @@ -396,7 +400,8 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, | |||
| 396 | 400 | ||
| 397 | /* write dummy data page */ | 401 | /* write dummy data page */ |
| 398 | recover_data_page(sbi, NULL, &sum, src, dest); | 402 | recover_data_page(sbi, NULL, &sum, src, dest); |
| 399 | update_extent_cache(dest, &dn); | 403 | dn.data_blkaddr = dest; |
| 404 | update_extent_cache(&dn); | ||
| 400 | recovered++; | 405 | recovered++; |
| 401 | } | 406 | } |
| 402 | dn.ofs_in_node++; | 407 | dn.ofs_in_node++; |
| @@ -503,7 +508,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) | |||
| 503 | INIT_LIST_HEAD(&inode_list); | 508 | INIT_LIST_HEAD(&inode_list); |
| 504 | 509 | ||
| 505 | /* step #1: find fsynced inode numbers */ | 510 | /* step #1: find fsynced inode numbers */ |
| 506 | sbi->por_doing = true; | 511 | set_sbi_flag(sbi, SBI_POR_DOING); |
| 507 | 512 | ||
| 508 | /* prevent checkpoint */ | 513 | /* prevent checkpoint */ |
| 509 | mutex_lock(&sbi->cp_mutex); | 514 | mutex_lock(&sbi->cp_mutex); |
| @@ -536,7 +541,7 @@ out: | |||
| 536 | truncate_inode_pages_final(META_MAPPING(sbi)); | 541 | truncate_inode_pages_final(META_MAPPING(sbi)); |
| 537 | } | 542 | } |
| 538 | 543 | ||
| 539 | sbi->por_doing = false; | 544 | clear_sbi_flag(sbi, SBI_POR_DOING); |
| 540 | if (err) { | 545 | if (err) { |
| 541 | discard_next_dnode(sbi, blkaddr); | 546 | discard_next_dnode(sbi, blkaddr); |
| 542 | 547 | ||
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 42607a679923..daee4ab913da 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include "f2fs.h" | 20 | #include "f2fs.h" |
| 21 | #include "segment.h" | 21 | #include "segment.h" |
| 22 | #include "node.h" | 22 | #include "node.h" |
| 23 | #include "trace.h" | ||
| 23 | #include <trace/events/f2fs.h> | 24 | #include <trace/events/f2fs.h> |
| 24 | 25 | ||
| 25 | #define __reverse_ffz(x) __reverse_ffs(~(x)) | 26 | #define __reverse_ffz(x) __reverse_ffs(~(x)) |
| @@ -181,6 +182,7 @@ void register_inmem_page(struct inode *inode, struct page *page) | |||
| 181 | int err; | 182 | int err; |
| 182 | 183 | ||
| 183 | SetPagePrivate(page); | 184 | SetPagePrivate(page); |
| 185 | f2fs_trace_pid(page); | ||
| 184 | 186 | ||
| 185 | new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS); | 187 | new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS); |
| 186 | 188 | ||
| @@ -205,23 +207,6 @@ retry: | |||
| 205 | mutex_unlock(&fi->inmem_lock); | 207 | mutex_unlock(&fi->inmem_lock); |
| 206 | } | 208 | } |
| 207 | 209 | ||
| 208 | void invalidate_inmem_page(struct inode *inode, struct page *page) | ||
| 209 | { | ||
| 210 | struct f2fs_inode_info *fi = F2FS_I(inode); | ||
| 211 | struct inmem_pages *cur; | ||
| 212 | |||
| 213 | mutex_lock(&fi->inmem_lock); | ||
| 214 | cur = radix_tree_lookup(&fi->inmem_root, page->index); | ||
| 215 | if (cur) { | ||
| 216 | radix_tree_delete(&fi->inmem_root, cur->page->index); | ||
| 217 | f2fs_put_page(cur->page, 0); | ||
| 218 | list_del(&cur->list); | ||
| 219 | kmem_cache_free(inmem_entry_slab, cur); | ||
| 220 | dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES); | ||
| 221 | } | ||
| 222 | mutex_unlock(&fi->inmem_lock); | ||
| 223 | } | ||
| 224 | |||
| 225 | void commit_inmem_pages(struct inode *inode, bool abort) | 210 | void commit_inmem_pages(struct inode *inode, bool abort) |
| 226 | { | 211 | { |
| 227 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); | 212 | struct f2fs_sb_info *sbi = F2FS_I_SB(inode); |
| @@ -230,7 +215,7 @@ void commit_inmem_pages(struct inode *inode, bool abort) | |||
| 230 | bool submit_bio = false; | 215 | bool submit_bio = false; |
| 231 | struct f2fs_io_info fio = { | 216 | struct f2fs_io_info fio = { |
| 232 | .type = DATA, | 217 | .type = DATA, |
| 233 | .rw = WRITE_SYNC, | 218 | .rw = WRITE_SYNC | REQ_PRIO, |
| 234 | }; | 219 | }; |
| 235 | 220 | ||
| 236 | /* | 221 | /* |
| @@ -240,33 +225,38 @@ void commit_inmem_pages(struct inode *inode, bool abort) | |||
| 240 | * Otherwise, f2fs_gc in f2fs_balance_fs can wait forever until this | 225 | * Otherwise, f2fs_gc in f2fs_balance_fs can wait forever until this |
| 241 | * inode becomes free by iget_locked in f2fs_iget. | 226 | * inode becomes free by iget_locked in f2fs_iget. |
| 242 | */ | 227 | */ |
| 243 | if (!abort) | 228 | if (!abort) { |
| 244 | f2fs_balance_fs(sbi); | 229 | f2fs_balance_fs(sbi); |
| 245 | 230 | f2fs_lock_op(sbi); | |
| 246 | f2fs_lock_op(sbi); | 231 | } |
| 247 | 232 | ||
| 248 | mutex_lock(&fi->inmem_lock); | 233 | mutex_lock(&fi->inmem_lock); |
| 249 | list_for_each_entry_safe(cur, tmp, &fi->inmem_pages, list) { | 234 | list_for_each_entry_safe(cur, tmp, &fi->inmem_pages, list) { |
| 250 | lock_page(cur->page); | 235 | if (!abort) { |
| 251 | if (!abort && cur->page->mapping == inode->i_mapping) { | 236 | lock_page(cur->page); |
| 252 | f2fs_wait_on_page_writeback(cur->page, DATA); | 237 | if (cur->page->mapping == inode->i_mapping) { |
| 253 | if (clear_page_dirty_for_io(cur->page)) | 238 | f2fs_wait_on_page_writeback(cur->page, DATA); |
| 254 | inode_dec_dirty_pages(inode); | 239 | if (clear_page_dirty_for_io(cur->page)) |
| 255 | do_write_data_page(cur->page, &fio); | 240 | inode_dec_dirty_pages(inode); |
| 256 | submit_bio = true; | 241 | do_write_data_page(cur->page, &fio); |
| 242 | submit_bio = true; | ||
| 243 | } | ||
| 244 | f2fs_put_page(cur->page, 1); | ||
| 245 | } else { | ||
| 246 | put_page(cur->page); | ||
| 257 | } | 247 | } |
| 258 | radix_tree_delete(&fi->inmem_root, cur->page->index); | 248 | radix_tree_delete(&fi->inmem_root, cur->page->index); |
| 259 | f2fs_put_page(cur->page, 1); | ||
| 260 | list_del(&cur->list); | 249 | list_del(&cur->list); |
| 261 | kmem_cache_free(inmem_entry_slab, cur); | 250 | kmem_cache_free(inmem_entry_slab, cur); |
| 262 | dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES); | 251 | dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES); |
| 263 | } | 252 | } |
| 264 | if (submit_bio) | ||
| 265 | f2fs_submit_merged_bio(sbi, DATA, WRITE); | ||
| 266 | mutex_unlock(&fi->inmem_lock); | 253 | mutex_unlock(&fi->inmem_lock); |
| 267 | 254 | ||
| 268 | filemap_fdatawait_range(inode->i_mapping, 0, LLONG_MAX); | 255 | if (!abort) { |
| 269 | f2fs_unlock_op(sbi); | 256 | f2fs_unlock_op(sbi); |
| 257 | if (submit_bio) | ||
| 258 | f2fs_submit_merged_bio(sbi, DATA, WRITE); | ||
| 259 | } | ||
| 270 | } | 260 | } |
| 271 | 261 | ||
| 272 | /* | 262 | /* |
| @@ -290,7 +280,7 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) | |||
| 290 | /* check the # of cached NAT entries and prefree segments */ | 280 | /* check the # of cached NAT entries and prefree segments */ |
| 291 | if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK) || | 281 | if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK) || |
| 292 | excess_prefree_segs(sbi) || | 282 | excess_prefree_segs(sbi) || |
| 293 | available_free_memory(sbi, INO_ENTRIES)) | 283 | !available_free_memory(sbi, INO_ENTRIES)) |
| 294 | f2fs_sync_fs(sbi->sb, true); | 284 | f2fs_sync_fs(sbi->sb, true); |
| 295 | } | 285 | } |
| 296 | 286 | ||
| @@ -515,12 +505,13 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
| 515 | struct seg_entry *se = get_seg_entry(sbi, cpc->trim_start); | 505 | struct seg_entry *se = get_seg_entry(sbi, cpc->trim_start); |
| 516 | unsigned long *cur_map = (unsigned long *)se->cur_valid_map; | 506 | unsigned long *cur_map = (unsigned long *)se->cur_valid_map; |
| 517 | unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; | 507 | unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; |
| 518 | unsigned long dmap[entries]; | 508 | unsigned long *dmap = SIT_I(sbi)->tmp_map; |
| 519 | unsigned int start = 0, end = -1; | 509 | unsigned int start = 0, end = -1; |
| 520 | bool force = (cpc->reason == CP_DISCARD); | 510 | bool force = (cpc->reason == CP_DISCARD); |
| 521 | int i; | 511 | int i; |
| 522 | 512 | ||
| 523 | if (!force && !test_opt(sbi, DISCARD)) | 513 | if (!force && (!test_opt(sbi, DISCARD) || |
| 514 | SM_I(sbi)->nr_discards >= SM_I(sbi)->max_discards)) | ||
| 524 | return; | 515 | return; |
| 525 | 516 | ||
| 526 | if (force && !se->valid_blocks) { | 517 | if (force && !se->valid_blocks) { |
| @@ -548,7 +539,8 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
| 548 | 539 | ||
| 549 | /* SIT_VBLOCK_MAP_SIZE should be multiple of sizeof(unsigned long) */ | 540 | /* SIT_VBLOCK_MAP_SIZE should be multiple of sizeof(unsigned long) */ |
| 550 | for (i = 0; i < entries; i++) | 541 | for (i = 0; i < entries; i++) |
| 551 | dmap[i] = ~(cur_map[i] | ckpt_map[i]); | 542 | dmap[i] = force ? ~ckpt_map[i] : |
| 543 | (cur_map[i] ^ ckpt_map[i]) & ckpt_map[i]; | ||
| 552 | 544 | ||
| 553 | while (force || SM_I(sbi)->nr_discards <= SM_I(sbi)->max_discards) { | 545 | while (force || SM_I(sbi)->nr_discards <= SM_I(sbi)->max_discards) { |
| 554 | start = __find_rev_next_bit(dmap, max_blocks, end + 1); | 546 | start = __find_rev_next_bit(dmap, max_blocks, end + 1); |
| @@ -735,7 +727,7 @@ static void __add_sum_entry(struct f2fs_sb_info *sbi, int type, | |||
| 735 | /* | 727 | /* |
| 736 | * Calculate the number of current summary pages for writing | 728 | * Calculate the number of current summary pages for writing |
| 737 | */ | 729 | */ |
| 738 | int npages_for_summary_flush(struct f2fs_sb_info *sbi) | 730 | int npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra) |
| 739 | { | 731 | { |
| 740 | int valid_sum_count = 0; | 732 | int valid_sum_count = 0; |
| 741 | int i, sum_in_page; | 733 | int i, sum_in_page; |
| @@ -743,8 +735,13 @@ int npages_for_summary_flush(struct f2fs_sb_info *sbi) | |||
| 743 | for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { | 735 | for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { |
| 744 | if (sbi->ckpt->alloc_type[i] == SSR) | 736 | if (sbi->ckpt->alloc_type[i] == SSR) |
| 745 | valid_sum_count += sbi->blocks_per_seg; | 737 | valid_sum_count += sbi->blocks_per_seg; |
| 746 | else | 738 | else { |
| 747 | valid_sum_count += curseg_blkoff(sbi, i); | 739 | if (for_ra) |
| 740 | valid_sum_count += le16_to_cpu( | ||
| 741 | F2FS_CKPT(sbi)->cur_data_blkoff[i]); | ||
| 742 | else | ||
| 743 | valid_sum_count += curseg_blkoff(sbi, i); | ||
| 744 | } | ||
| 748 | } | 745 | } |
| 749 | 746 | ||
| 750 | sum_in_page = (PAGE_CACHE_SIZE - 2 * SUM_JOURNAL_SIZE - | 747 | sum_in_page = (PAGE_CACHE_SIZE - 2 * SUM_JOURNAL_SIZE - |
| @@ -803,7 +800,7 @@ static void get_new_segment(struct f2fs_sb_info *sbi, | |||
| 803 | int go_left = 0; | 800 | int go_left = 0; |
| 804 | int i; | 801 | int i; |
| 805 | 802 | ||
| 806 | write_lock(&free_i->segmap_lock); | 803 | spin_lock(&free_i->segmap_lock); |
| 807 | 804 | ||
| 808 | if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) { | 805 | if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) { |
| 809 | segno = find_next_zero_bit(free_i->free_segmap, | 806 | segno = find_next_zero_bit(free_i->free_segmap, |
| @@ -876,7 +873,7 @@ got_it: | |||
| 876 | f2fs_bug_on(sbi, test_bit(segno, free_i->free_segmap)); | 873 | f2fs_bug_on(sbi, test_bit(segno, free_i->free_segmap)); |
| 877 | __set_inuse(sbi, segno); | 874 | __set_inuse(sbi, segno); |
| 878 | *newseg = segno; | 875 | *newseg = segno; |
| 879 | write_unlock(&free_i->segmap_lock); | 876 | spin_unlock(&free_i->segmap_lock); |
| 880 | } | 877 | } |
| 881 | 878 | ||
| 882 | static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified) | 879 | static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified) |
| @@ -927,7 +924,7 @@ static void __next_free_blkoff(struct f2fs_sb_info *sbi, | |||
| 927 | { | 924 | { |
| 928 | struct seg_entry *se = get_seg_entry(sbi, seg->segno); | 925 | struct seg_entry *se = get_seg_entry(sbi, seg->segno); |
| 929 | int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); | 926 | int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); |
| 930 | unsigned long target_map[entries]; | 927 | unsigned long *target_map = SIT_I(sbi)->tmp_map; |
| 931 | unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; | 928 | unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; |
| 932 | unsigned long *cur_map = (unsigned long *)se->cur_valid_map; | 929 | unsigned long *cur_map = (unsigned long *)se->cur_valid_map; |
| 933 | int i, pos; | 930 | int i, pos; |
| @@ -1027,18 +1024,22 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi, | |||
| 1027 | stat_inc_seg_type(sbi, curseg); | 1024 | stat_inc_seg_type(sbi, curseg); |
| 1028 | } | 1025 | } |
| 1029 | 1026 | ||
| 1027 | static void __allocate_new_segments(struct f2fs_sb_info *sbi, int type) | ||
| 1028 | { | ||
| 1029 | struct curseg_info *curseg = CURSEG_I(sbi, type); | ||
| 1030 | unsigned int old_segno; | ||
| 1031 | |||
| 1032 | old_segno = curseg->segno; | ||
| 1033 | SIT_I(sbi)->s_ops->allocate_segment(sbi, type, true); | ||
| 1034 | locate_dirty_segment(sbi, old_segno); | ||
| 1035 | } | ||
| 1036 | |||
| 1030 | void allocate_new_segments(struct f2fs_sb_info *sbi) | 1037 | void allocate_new_segments(struct f2fs_sb_info *sbi) |
| 1031 | { | 1038 | { |
| 1032 | struct curseg_info *curseg; | ||
| 1033 | unsigned int old_curseg; | ||
| 1034 | int i; | 1039 | int i; |
| 1035 | 1040 | ||
| 1036 | for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { | 1041 | for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) |
| 1037 | curseg = CURSEG_I(sbi, i); | 1042 | __allocate_new_segments(sbi, i); |
| 1038 | old_curseg = curseg->segno; | ||
| 1039 | SIT_I(sbi)->s_ops->allocate_segment(sbi, i, true); | ||
| 1040 | locate_dirty_segment(sbi, old_curseg); | ||
| 1041 | } | ||
| 1042 | } | 1043 | } |
| 1043 | 1044 | ||
| 1044 | static const struct segment_allocation default_salloc_ops = { | 1045 | static const struct segment_allocation default_salloc_ops = { |
| @@ -1047,8 +1048,8 @@ static const struct segment_allocation default_salloc_ops = { | |||
| 1047 | 1048 | ||
| 1048 | int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) | 1049 | int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) |
| 1049 | { | 1050 | { |
| 1050 | __u64 start = range->start >> sbi->log_blocksize; | 1051 | __u64 start = F2FS_BYTES_TO_BLK(range->start); |
| 1051 | __u64 end = start + (range->len >> sbi->log_blocksize) - 1; | 1052 | __u64 end = start + F2FS_BYTES_TO_BLK(range->len) - 1; |
| 1052 | unsigned int start_segno, end_segno; | 1053 | unsigned int start_segno, end_segno; |
| 1053 | struct cp_control cpc; | 1054 | struct cp_control cpc; |
| 1054 | 1055 | ||
| @@ -1065,16 +1066,21 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) | |||
| 1065 | end_segno = (end >= MAX_BLKADDR(sbi)) ? MAIN_SEGS(sbi) - 1 : | 1066 | end_segno = (end >= MAX_BLKADDR(sbi)) ? MAIN_SEGS(sbi) - 1 : |
| 1066 | GET_SEGNO(sbi, end); | 1067 | GET_SEGNO(sbi, end); |
| 1067 | cpc.reason = CP_DISCARD; | 1068 | cpc.reason = CP_DISCARD; |
| 1068 | cpc.trim_start = start_segno; | 1069 | cpc.trim_minlen = F2FS_BYTES_TO_BLK(range->minlen); |
| 1069 | cpc.trim_end = end_segno; | ||
| 1070 | cpc.trim_minlen = range->minlen >> sbi->log_blocksize; | ||
| 1071 | 1070 | ||
| 1072 | /* do checkpoint to issue discard commands safely */ | 1071 | /* do checkpoint to issue discard commands safely */ |
| 1073 | mutex_lock(&sbi->gc_mutex); | 1072 | for (; start_segno <= end_segno; start_segno = cpc.trim_end + 1) { |
| 1074 | write_checkpoint(sbi, &cpc); | 1073 | cpc.trim_start = start_segno; |
| 1075 | mutex_unlock(&sbi->gc_mutex); | 1074 | cpc.trim_end = min_t(unsigned int, rounddown(start_segno + |
| 1075 | BATCHED_TRIM_SEGMENTS(sbi), | ||
| 1076 | sbi->segs_per_sec) - 1, end_segno); | ||
| 1077 | |||
| 1078 | mutex_lock(&sbi->gc_mutex); | ||
| 1079 | write_checkpoint(sbi, &cpc); | ||
| 1080 | mutex_unlock(&sbi->gc_mutex); | ||
| 1081 | } | ||
| 1076 | out: | 1082 | out: |
| 1077 | range->len = cpc.trimmed << sbi->log_blocksize; | 1083 | range->len = F2FS_BLK_TO_BYTES(cpc.trimmed); |
| 1078 | return 0; | 1084 | return 0; |
| 1079 | } | 1085 | } |
| 1080 | 1086 | ||
| @@ -1151,11 +1157,18 @@ void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, | |||
| 1151 | { | 1157 | { |
| 1152 | struct sit_info *sit_i = SIT_I(sbi); | 1158 | struct sit_info *sit_i = SIT_I(sbi); |
| 1153 | struct curseg_info *curseg; | 1159 | struct curseg_info *curseg; |
| 1160 | bool direct_io = (type == CURSEG_DIRECT_IO); | ||
| 1161 | |||
| 1162 | type = direct_io ? CURSEG_WARM_DATA : type; | ||
| 1154 | 1163 | ||
| 1155 | curseg = CURSEG_I(sbi, type); | 1164 | curseg = CURSEG_I(sbi, type); |
| 1156 | 1165 | ||
| 1157 | mutex_lock(&curseg->curseg_mutex); | 1166 | mutex_lock(&curseg->curseg_mutex); |
| 1158 | 1167 | ||
| 1168 | /* direct_io'ed data is aligned to the segment for better performance */ | ||
| 1169 | if (direct_io && curseg->next_blkoff) | ||
| 1170 | __allocate_new_segments(sbi, type); | ||
| 1171 | |||
| 1159 | *new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); | 1172 | *new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); |
| 1160 | 1173 | ||
| 1161 | /* | 1174 | /* |
| @@ -1187,39 +1200,39 @@ void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, | |||
| 1187 | } | 1200 | } |
| 1188 | 1201 | ||
| 1189 | static void do_write_page(struct f2fs_sb_info *sbi, struct page *page, | 1202 | static void do_write_page(struct f2fs_sb_info *sbi, struct page *page, |
| 1190 | block_t old_blkaddr, block_t *new_blkaddr, | 1203 | struct f2fs_summary *sum, |
| 1191 | struct f2fs_summary *sum, struct f2fs_io_info *fio) | 1204 | struct f2fs_io_info *fio) |
| 1192 | { | 1205 | { |
| 1193 | int type = __get_segment_type(page, fio->type); | 1206 | int type = __get_segment_type(page, fio->type); |
| 1194 | 1207 | ||
| 1195 | allocate_data_block(sbi, page, old_blkaddr, new_blkaddr, sum, type); | 1208 | allocate_data_block(sbi, page, fio->blk_addr, &fio->blk_addr, sum, type); |
| 1196 | 1209 | ||
| 1197 | /* writeout dirty page into bdev */ | 1210 | /* writeout dirty page into bdev */ |
| 1198 | f2fs_submit_page_mbio(sbi, page, *new_blkaddr, fio); | 1211 | f2fs_submit_page_mbio(sbi, page, fio); |
| 1199 | } | 1212 | } |
| 1200 | 1213 | ||
| 1201 | void write_meta_page(struct f2fs_sb_info *sbi, struct page *page) | 1214 | void write_meta_page(struct f2fs_sb_info *sbi, struct page *page) |
| 1202 | { | 1215 | { |
| 1203 | struct f2fs_io_info fio = { | 1216 | struct f2fs_io_info fio = { |
| 1204 | .type = META, | 1217 | .type = META, |
| 1205 | .rw = WRITE_SYNC | REQ_META | REQ_PRIO | 1218 | .rw = WRITE_SYNC | REQ_META | REQ_PRIO, |
| 1219 | .blk_addr = page->index, | ||
| 1206 | }; | 1220 | }; |
| 1207 | 1221 | ||
| 1208 | set_page_writeback(page); | 1222 | set_page_writeback(page); |
| 1209 | f2fs_submit_page_mbio(sbi, page, page->index, &fio); | 1223 | f2fs_submit_page_mbio(sbi, page, &fio); |
| 1210 | } | 1224 | } |
| 1211 | 1225 | ||
| 1212 | void write_node_page(struct f2fs_sb_info *sbi, struct page *page, | 1226 | void write_node_page(struct f2fs_sb_info *sbi, struct page *page, |
| 1213 | struct f2fs_io_info *fio, | 1227 | unsigned int nid, struct f2fs_io_info *fio) |
| 1214 | unsigned int nid, block_t old_blkaddr, block_t *new_blkaddr) | ||
| 1215 | { | 1228 | { |
| 1216 | struct f2fs_summary sum; | 1229 | struct f2fs_summary sum; |
| 1217 | set_summary(&sum, nid, 0, 0); | 1230 | set_summary(&sum, nid, 0, 0); |
| 1218 | do_write_page(sbi, page, old_blkaddr, new_blkaddr, &sum, fio); | 1231 | do_write_page(sbi, page, &sum, fio); |
| 1219 | } | 1232 | } |
| 1220 | 1233 | ||
| 1221 | void write_data_page(struct page *page, struct dnode_of_data *dn, | 1234 | void write_data_page(struct page *page, struct dnode_of_data *dn, |
| 1222 | block_t *new_blkaddr, struct f2fs_io_info *fio) | 1235 | struct f2fs_io_info *fio) |
| 1223 | { | 1236 | { |
| 1224 | struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); | 1237 | struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); |
| 1225 | struct f2fs_summary sum; | 1238 | struct f2fs_summary sum; |
| @@ -1228,14 +1241,14 @@ void write_data_page(struct page *page, struct dnode_of_data *dn, | |||
| 1228 | f2fs_bug_on(sbi, dn->data_blkaddr == NULL_ADDR); | 1241 | f2fs_bug_on(sbi, dn->data_blkaddr == NULL_ADDR); |
| 1229 | get_node_info(sbi, dn->nid, &ni); | 1242 | get_node_info(sbi, dn->nid, &ni); |
| 1230 | set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); | 1243 | set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); |
| 1231 | 1244 | do_write_page(sbi, page, &sum, fio); | |
| 1232 | do_write_page(sbi, page, dn->data_blkaddr, new_blkaddr, &sum, fio); | 1245 | dn->data_blkaddr = fio->blk_addr; |
| 1233 | } | 1246 | } |
| 1234 | 1247 | ||
| 1235 | void rewrite_data_page(struct page *page, block_t old_blkaddr, | 1248 | void rewrite_data_page(struct page *page, struct f2fs_io_info *fio) |
| 1236 | struct f2fs_io_info *fio) | ||
| 1237 | { | 1249 | { |
| 1238 | f2fs_submit_page_mbio(F2FS_P_SB(page), page, old_blkaddr, fio); | 1250 | stat_inc_inplace_blocks(F2FS_P_SB(page)); |
| 1251 | f2fs_submit_page_mbio(F2FS_P_SB(page), page, fio); | ||
| 1239 | } | 1252 | } |
| 1240 | 1253 | ||
| 1241 | void recover_data_page(struct f2fs_sb_info *sbi, | 1254 | void recover_data_page(struct f2fs_sb_info *sbi, |
| @@ -1393,7 +1406,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) | |||
| 1393 | segno = le32_to_cpu(ckpt->cur_data_segno[type]); | 1406 | segno = le32_to_cpu(ckpt->cur_data_segno[type]); |
| 1394 | blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type - | 1407 | blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type - |
| 1395 | CURSEG_HOT_DATA]); | 1408 | CURSEG_HOT_DATA]); |
| 1396 | if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) | 1409 | if (__exist_node_summaries(sbi)) |
| 1397 | blk_addr = sum_blk_addr(sbi, NR_CURSEG_TYPE, type); | 1410 | blk_addr = sum_blk_addr(sbi, NR_CURSEG_TYPE, type); |
| 1398 | else | 1411 | else |
| 1399 | blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type); | 1412 | blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type); |
| @@ -1402,7 +1415,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) | |||
| 1402 | CURSEG_HOT_NODE]); | 1415 | CURSEG_HOT_NODE]); |
| 1403 | blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type - | 1416 | blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type - |
| 1404 | CURSEG_HOT_NODE]); | 1417 | CURSEG_HOT_NODE]); |
| 1405 | if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) | 1418 | if (__exist_node_summaries(sbi)) |
| 1406 | blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, | 1419 | blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, |
| 1407 | type - CURSEG_HOT_NODE); | 1420 | type - CURSEG_HOT_NODE); |
| 1408 | else | 1421 | else |
| @@ -1413,7 +1426,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) | |||
| 1413 | sum = (struct f2fs_summary_block *)page_address(new); | 1426 | sum = (struct f2fs_summary_block *)page_address(new); |
| 1414 | 1427 | ||
| 1415 | if (IS_NODESEG(type)) { | 1428 | if (IS_NODESEG(type)) { |
| 1416 | if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) { | 1429 | if (__exist_node_summaries(sbi)) { |
| 1417 | struct f2fs_summary *ns = &sum->entries[0]; | 1430 | struct f2fs_summary *ns = &sum->entries[0]; |
| 1418 | int i; | 1431 | int i; |
| 1419 | for (i = 0; i < sbi->blocks_per_seg; i++, ns++) { | 1432 | for (i = 0; i < sbi->blocks_per_seg; i++, ns++) { |
| @@ -1450,12 +1463,22 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi) | |||
| 1450 | int err; | 1463 | int err; |
| 1451 | 1464 | ||
| 1452 | if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) { | 1465 | if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) { |
| 1466 | int npages = npages_for_summary_flush(sbi, true); | ||
| 1467 | |||
| 1468 | if (npages >= 2) | ||
| 1469 | ra_meta_pages(sbi, start_sum_block(sbi), npages, | ||
| 1470 | META_CP); | ||
| 1471 | |||
| 1453 | /* restore for compacted data summary */ | 1472 | /* restore for compacted data summary */ |
| 1454 | if (read_compacted_summaries(sbi)) | 1473 | if (read_compacted_summaries(sbi)) |
| 1455 | return -EINVAL; | 1474 | return -EINVAL; |
| 1456 | type = CURSEG_HOT_NODE; | 1475 | type = CURSEG_HOT_NODE; |
| 1457 | } | 1476 | } |
| 1458 | 1477 | ||
| 1478 | if (__exist_node_summaries(sbi)) | ||
| 1479 | ra_meta_pages(sbi, sum_blk_addr(sbi, NR_CURSEG_TYPE, type), | ||
| 1480 | NR_CURSEG_TYPE - type, META_CP); | ||
| 1481 | |||
| 1459 | for (; type <= CURSEG_COLD_NODE; type++) { | 1482 | for (; type <= CURSEG_COLD_NODE; type++) { |
| 1460 | err = read_normal_summaries(sbi, type); | 1483 | err = read_normal_summaries(sbi, type); |
| 1461 | if (err) | 1484 | if (err) |
| @@ -1549,8 +1572,7 @@ void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk) | |||
| 1549 | 1572 | ||
| 1550 | void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk) | 1573 | void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk) |
| 1551 | { | 1574 | { |
| 1552 | if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG)) | 1575 | write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); |
| 1553 | write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); | ||
| 1554 | } | 1576 | } |
| 1555 | 1577 | ||
| 1556 | int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type, | 1578 | int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type, |
| @@ -1754,7 +1776,7 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
| 1754 | se = get_seg_entry(sbi, segno); | 1776 | se = get_seg_entry(sbi, segno); |
| 1755 | 1777 | ||
| 1756 | /* add discard candidates */ | 1778 | /* add discard candidates */ |
| 1757 | if (SM_I(sbi)->nr_discards < SM_I(sbi)->max_discards) { | 1779 | if (cpc->reason != CP_DISCARD) { |
| 1758 | cpc->trim_start = segno; | 1780 | cpc->trim_start = segno; |
| 1759 | add_discard_addrs(sbi, cpc); | 1781 | add_discard_addrs(sbi, cpc); |
| 1760 | } | 1782 | } |
| @@ -1833,6 +1855,10 @@ static int build_sit_info(struct f2fs_sb_info *sbi) | |||
| 1833 | return -ENOMEM; | 1855 | return -ENOMEM; |
| 1834 | } | 1856 | } |
| 1835 | 1857 | ||
| 1858 | sit_i->tmp_map = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); | ||
| 1859 | if (!sit_i->tmp_map) | ||
| 1860 | return -ENOMEM; | ||
| 1861 | |||
| 1836 | if (sbi->segs_per_sec > 1) { | 1862 | if (sbi->segs_per_sec > 1) { |
| 1837 | sit_i->sec_entries = vzalloc(MAIN_SECS(sbi) * | 1863 | sit_i->sec_entries = vzalloc(MAIN_SECS(sbi) * |
| 1838 | sizeof(struct sec_entry)); | 1864 | sizeof(struct sec_entry)); |
| @@ -1897,7 +1923,7 @@ static int build_free_segmap(struct f2fs_sb_info *sbi) | |||
| 1897 | free_i->start_segno = GET_SEGNO_FROM_SEG0(sbi, MAIN_BLKADDR(sbi)); | 1923 | free_i->start_segno = GET_SEGNO_FROM_SEG0(sbi, MAIN_BLKADDR(sbi)); |
| 1898 | free_i->free_segments = 0; | 1924 | free_i->free_segments = 0; |
| 1899 | free_i->free_sections = 0; | 1925 | free_i->free_sections = 0; |
| 1900 | rwlock_init(&free_i->segmap_lock); | 1926 | spin_lock_init(&free_i->segmap_lock); |
| 1901 | return 0; | 1927 | return 0; |
| 1902 | } | 1928 | } |
| 1903 | 1929 | ||
| @@ -2110,6 +2136,8 @@ int build_segment_manager(struct f2fs_sb_info *sbi) | |||
| 2110 | sm_info->nr_discards = 0; | 2136 | sm_info->nr_discards = 0; |
| 2111 | sm_info->max_discards = 0; | 2137 | sm_info->max_discards = 0; |
| 2112 | 2138 | ||
| 2139 | sm_info->trim_sections = DEF_BATCHED_TRIM_SECTIONS; | ||
| 2140 | |||
| 2113 | INIT_LIST_HEAD(&sm_info->sit_entry_set); | 2141 | INIT_LIST_HEAD(&sm_info->sit_entry_set); |
| 2114 | 2142 | ||
| 2115 | if (test_opt(sbi, FLUSH_MERGE) && !f2fs_readonly(sbi->sb)) { | 2143 | if (test_opt(sbi, FLUSH_MERGE) && !f2fs_readonly(sbi->sb)) { |
| @@ -2212,6 +2240,8 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi) | |||
| 2212 | kfree(sit_i->sentries[start].ckpt_valid_map); | 2240 | kfree(sit_i->sentries[start].ckpt_valid_map); |
| 2213 | } | 2241 | } |
| 2214 | } | 2242 | } |
| 2243 | kfree(sit_i->tmp_map); | ||
| 2244 | |||
| 2215 | vfree(sit_i->sentries); | 2245 | vfree(sit_i->sentries); |
| 2216 | vfree(sit_i->sec_entries); | 2246 | vfree(sit_i->sec_entries); |
| 2217 | kfree(sit_i->dirty_sentries_bitmap); | 2247 | kfree(sit_i->dirty_sentries_bitmap); |
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 7f327c0ba4e3..7fd35111cf62 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h | |||
| @@ -189,6 +189,7 @@ struct sit_info { | |||
| 189 | char *sit_bitmap; /* SIT bitmap pointer */ | 189 | char *sit_bitmap; /* SIT bitmap pointer */ |
| 190 | unsigned int bitmap_size; /* SIT bitmap size */ | 190 | unsigned int bitmap_size; /* SIT bitmap size */ |
| 191 | 191 | ||
| 192 | unsigned long *tmp_map; /* bitmap for temporal use */ | ||
| 192 | unsigned long *dirty_sentries_bitmap; /* bitmap for dirty sentries */ | 193 | unsigned long *dirty_sentries_bitmap; /* bitmap for dirty sentries */ |
| 193 | unsigned int dirty_sentries; /* # of dirty sentries */ | 194 | unsigned int dirty_sentries; /* # of dirty sentries */ |
| 194 | unsigned int sents_per_block; /* # of SIT entries per block */ | 195 | unsigned int sents_per_block; /* # of SIT entries per block */ |
| @@ -207,7 +208,7 @@ struct free_segmap_info { | |||
| 207 | unsigned int start_segno; /* start segment number logically */ | 208 | unsigned int start_segno; /* start segment number logically */ |
| 208 | unsigned int free_segments; /* # of free segments */ | 209 | unsigned int free_segments; /* # of free segments */ |
| 209 | unsigned int free_sections; /* # of free sections */ | 210 | unsigned int free_sections; /* # of free sections */ |
| 210 | rwlock_t segmap_lock; /* free segmap lock */ | 211 | spinlock_t segmap_lock; /* free segmap lock */ |
| 211 | unsigned long *free_segmap; /* free segment bitmap */ | 212 | unsigned long *free_segmap; /* free segment bitmap */ |
| 212 | unsigned long *free_secmap; /* free section bitmap */ | 213 | unsigned long *free_secmap; /* free section bitmap */ |
| 213 | }; | 214 | }; |
| @@ -318,9 +319,9 @@ static inline unsigned int find_next_inuse(struct free_segmap_info *free_i, | |||
| 318 | unsigned int max, unsigned int segno) | 319 | unsigned int max, unsigned int segno) |
| 319 | { | 320 | { |
| 320 | unsigned int ret; | 321 | unsigned int ret; |
| 321 | read_lock(&free_i->segmap_lock); | 322 | spin_lock(&free_i->segmap_lock); |
| 322 | ret = find_next_bit(free_i->free_segmap, max, segno); | 323 | ret = find_next_bit(free_i->free_segmap, max, segno); |
| 323 | read_unlock(&free_i->segmap_lock); | 324 | spin_unlock(&free_i->segmap_lock); |
| 324 | return ret; | 325 | return ret; |
| 325 | } | 326 | } |
| 326 | 327 | ||
| @@ -331,7 +332,7 @@ static inline void __set_free(struct f2fs_sb_info *sbi, unsigned int segno) | |||
| 331 | unsigned int start_segno = secno * sbi->segs_per_sec; | 332 | unsigned int start_segno = secno * sbi->segs_per_sec; |
| 332 | unsigned int next; | 333 | unsigned int next; |
| 333 | 334 | ||
| 334 | write_lock(&free_i->segmap_lock); | 335 | spin_lock(&free_i->segmap_lock); |
| 335 | clear_bit(segno, free_i->free_segmap); | 336 | clear_bit(segno, free_i->free_segmap); |
| 336 | free_i->free_segments++; | 337 | free_i->free_segments++; |
| 337 | 338 | ||
| @@ -340,7 +341,7 @@ static inline void __set_free(struct f2fs_sb_info *sbi, unsigned int segno) | |||
| 340 | clear_bit(secno, free_i->free_secmap); | 341 | clear_bit(secno, free_i->free_secmap); |
| 341 | free_i->free_sections++; | 342 | free_i->free_sections++; |
| 342 | } | 343 | } |
| 343 | write_unlock(&free_i->segmap_lock); | 344 | spin_unlock(&free_i->segmap_lock); |
| 344 | } | 345 | } |
| 345 | 346 | ||
| 346 | static inline void __set_inuse(struct f2fs_sb_info *sbi, | 347 | static inline void __set_inuse(struct f2fs_sb_info *sbi, |
| @@ -362,7 +363,7 @@ static inline void __set_test_and_free(struct f2fs_sb_info *sbi, | |||
| 362 | unsigned int start_segno = secno * sbi->segs_per_sec; | 363 | unsigned int start_segno = secno * sbi->segs_per_sec; |
| 363 | unsigned int next; | 364 | unsigned int next; |
| 364 | 365 | ||
| 365 | write_lock(&free_i->segmap_lock); | 366 | spin_lock(&free_i->segmap_lock); |
| 366 | if (test_and_clear_bit(segno, free_i->free_segmap)) { | 367 | if (test_and_clear_bit(segno, free_i->free_segmap)) { |
| 367 | free_i->free_segments++; | 368 | free_i->free_segments++; |
| 368 | 369 | ||
| @@ -373,7 +374,7 @@ static inline void __set_test_and_free(struct f2fs_sb_info *sbi, | |||
| 373 | free_i->free_sections++; | 374 | free_i->free_sections++; |
| 374 | } | 375 | } |
| 375 | } | 376 | } |
| 376 | write_unlock(&free_i->segmap_lock); | 377 | spin_unlock(&free_i->segmap_lock); |
| 377 | } | 378 | } |
| 378 | 379 | ||
| 379 | static inline void __set_test_and_inuse(struct f2fs_sb_info *sbi, | 380 | static inline void __set_test_and_inuse(struct f2fs_sb_info *sbi, |
| @@ -381,13 +382,13 @@ static inline void __set_test_and_inuse(struct f2fs_sb_info *sbi, | |||
| 381 | { | 382 | { |
| 382 | struct free_segmap_info *free_i = FREE_I(sbi); | 383 | struct free_segmap_info *free_i = FREE_I(sbi); |
| 383 | unsigned int secno = segno / sbi->segs_per_sec; | 384 | unsigned int secno = segno / sbi->segs_per_sec; |
| 384 | write_lock(&free_i->segmap_lock); | 385 | spin_lock(&free_i->segmap_lock); |
| 385 | if (!test_and_set_bit(segno, free_i->free_segmap)) { | 386 | if (!test_and_set_bit(segno, free_i->free_segmap)) { |
| 386 | free_i->free_segments--; | 387 | free_i->free_segments--; |
| 387 | if (!test_and_set_bit(secno, free_i->free_secmap)) | 388 | if (!test_and_set_bit(secno, free_i->free_secmap)) |
| 388 | free_i->free_sections--; | 389 | free_i->free_sections--; |
| 389 | } | 390 | } |
| 390 | write_unlock(&free_i->segmap_lock); | 391 | spin_unlock(&free_i->segmap_lock); |
| 391 | } | 392 | } |
| 392 | 393 | ||
| 393 | static inline void get_sit_bitmap(struct f2fs_sb_info *sbi, | 394 | static inline void get_sit_bitmap(struct f2fs_sb_info *sbi, |
| @@ -460,7 +461,7 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed) | |||
| 460 | int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES); | 461 | int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES); |
| 461 | int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); | 462 | int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); |
| 462 | 463 | ||
| 463 | if (unlikely(sbi->por_doing)) | 464 | if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) |
| 464 | return false; | 465 | return false; |
| 465 | 466 | ||
| 466 | return (free_sections(sbi) + freed) <= (node_secs + 2 * dent_secs + | 467 | return (free_sections(sbi) + freed) <= (node_secs + 2 * dent_secs + |
| @@ -599,13 +600,13 @@ static inline void check_block_count(struct f2fs_sb_info *sbi, | |||
| 599 | static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) | 600 | static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) |
| 600 | { | 601 | { |
| 601 | if (segno > TOTAL_SEGS(sbi) - 1) | 602 | if (segno > TOTAL_SEGS(sbi) - 1) |
| 602 | sbi->need_fsck = true; | 603 | set_sbi_flag(sbi, SBI_NEED_FSCK); |
| 603 | } | 604 | } |
| 604 | 605 | ||
| 605 | static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr) | 606 | static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr) |
| 606 | { | 607 | { |
| 607 | if (blk_addr < SEG0_BLKADDR(sbi) || blk_addr >= MAX_BLKADDR(sbi)) | 608 | if (blk_addr < SEG0_BLKADDR(sbi) || blk_addr >= MAX_BLKADDR(sbi)) |
| 608 | sbi->need_fsck = true; | 609 | set_sbi_flag(sbi, SBI_NEED_FSCK); |
| 609 | } | 610 | } |
| 610 | 611 | ||
| 611 | /* | 612 | /* |
| @@ -616,11 +617,11 @@ static inline void check_block_count(struct f2fs_sb_info *sbi, | |||
| 616 | { | 617 | { |
| 617 | /* check segment usage */ | 618 | /* check segment usage */ |
| 618 | if (GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg) | 619 | if (GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg) |
| 619 | sbi->need_fsck = true; | 620 | set_sbi_flag(sbi, SBI_NEED_FSCK); |
| 620 | 621 | ||
| 621 | /* check boundary of a given segment number */ | 622 | /* check boundary of a given segment number */ |
| 622 | if (segno > TOTAL_SEGS(sbi) - 1) | 623 | if (segno > TOTAL_SEGS(sbi) - 1) |
| 623 | sbi->need_fsck = true; | 624 | set_sbi_flag(sbi, SBI_NEED_FSCK); |
| 624 | } | 625 | } |
| 625 | #endif | 626 | #endif |
| 626 | 627 | ||
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index f71421d70475..f2fe666a6ea9 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include "segment.h" | 30 | #include "segment.h" |
| 31 | #include "xattr.h" | 31 | #include "xattr.h" |
| 32 | #include "gc.h" | 32 | #include "gc.h" |
| 33 | #include "trace.h" | ||
| 33 | 34 | ||
| 34 | #define CREATE_TRACE_POINTS | 35 | #define CREATE_TRACE_POINTS |
| 35 | #include <trace/events/f2fs.h> | 36 | #include <trace/events/f2fs.h> |
| @@ -41,6 +42,7 @@ static struct kset *f2fs_kset; | |||
| 41 | enum { | 42 | enum { |
| 42 | Opt_gc_background, | 43 | Opt_gc_background, |
| 43 | Opt_disable_roll_forward, | 44 | Opt_disable_roll_forward, |
| 45 | Opt_norecovery, | ||
| 44 | Opt_discard, | 46 | Opt_discard, |
| 45 | Opt_noheap, | 47 | Opt_noheap, |
| 46 | Opt_user_xattr, | 48 | Opt_user_xattr, |
| @@ -61,6 +63,7 @@ enum { | |||
| 61 | static match_table_t f2fs_tokens = { | 63 | static match_table_t f2fs_tokens = { |
| 62 | {Opt_gc_background, "background_gc=%s"}, | 64 | {Opt_gc_background, "background_gc=%s"}, |
| 63 | {Opt_disable_roll_forward, "disable_roll_forward"}, | 65 | {Opt_disable_roll_forward, "disable_roll_forward"}, |
| 66 | {Opt_norecovery, "norecovery"}, | ||
| 64 | {Opt_discard, "discard"}, | 67 | {Opt_discard, "discard"}, |
| 65 | {Opt_noheap, "no_heap"}, | 68 | {Opt_noheap, "no_heap"}, |
| 66 | {Opt_user_xattr, "user_xattr"}, | 69 | {Opt_user_xattr, "user_xattr"}, |
| @@ -192,6 +195,7 @@ F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time); | |||
| 192 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle); | 195 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle); |
| 193 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); | 196 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); |
| 194 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, max_small_discards, max_discards); | 197 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, max_small_discards, max_discards); |
| 198 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections); | ||
| 195 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy); | 199 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy); |
| 196 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util); | 200 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util); |
| 197 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks); | 201 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks); |
| @@ -207,6 +211,7 @@ static struct attribute *f2fs_attrs[] = { | |||
| 207 | ATTR_LIST(gc_idle), | 211 | ATTR_LIST(gc_idle), |
| 208 | ATTR_LIST(reclaim_segments), | 212 | ATTR_LIST(reclaim_segments), |
| 209 | ATTR_LIST(max_small_discards), | 213 | ATTR_LIST(max_small_discards), |
| 214 | ATTR_LIST(batched_trim_sections), | ||
| 210 | ATTR_LIST(ipu_policy), | 215 | ATTR_LIST(ipu_policy), |
| 211 | ATTR_LIST(min_ipu_util), | 216 | ATTR_LIST(min_ipu_util), |
| 212 | ATTR_LIST(min_fsync_blocks), | 217 | ATTR_LIST(min_fsync_blocks), |
| @@ -286,6 +291,12 @@ static int parse_options(struct super_block *sb, char *options) | |||
| 286 | case Opt_disable_roll_forward: | 291 | case Opt_disable_roll_forward: |
| 287 | set_opt(sbi, DISABLE_ROLL_FORWARD); | 292 | set_opt(sbi, DISABLE_ROLL_FORWARD); |
| 288 | break; | 293 | break; |
| 294 | case Opt_norecovery: | ||
| 295 | /* this option mounts f2fs with ro */ | ||
| 296 | set_opt(sbi, DISABLE_ROLL_FORWARD); | ||
| 297 | if (!f2fs_readonly(sb)) | ||
| 298 | return -EINVAL; | ||
| 299 | break; | ||
| 289 | case Opt_discard: | 300 | case Opt_discard: |
| 290 | set_opt(sbi, DISCARD); | 301 | set_opt(sbi, DISCARD); |
| 291 | break; | 302 | break; |
| @@ -446,8 +457,13 @@ static void f2fs_put_super(struct super_block *sb) | |||
| 446 | f2fs_destroy_stats(sbi); | 457 | f2fs_destroy_stats(sbi); |
| 447 | stop_gc_thread(sbi); | 458 | stop_gc_thread(sbi); |
| 448 | 459 | ||
| 449 | /* We don't need to do checkpoint when it's clean */ | 460 | /* |
| 450 | if (sbi->s_dirty) { | 461 | * We don't need to do checkpoint when superblock is clean. |
| 462 | * But, the previous checkpoint was not done by umount, it needs to do | ||
| 463 | * clean checkpoint again. | ||
| 464 | */ | ||
| 465 | if (is_sbi_flag_set(sbi, SBI_IS_DIRTY) || | ||
| 466 | !is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG)) { | ||
| 451 | struct cp_control cpc = { | 467 | struct cp_control cpc = { |
| 452 | .reason = CP_UMOUNT, | 468 | .reason = CP_UMOUNT, |
| 453 | }; | 469 | }; |
| @@ -486,13 +502,15 @@ int f2fs_sync_fs(struct super_block *sb, int sync) | |||
| 486 | if (sync) { | 502 | if (sync) { |
| 487 | struct cp_control cpc; | 503 | struct cp_control cpc; |
| 488 | 504 | ||
| 489 | cpc.reason = test_opt(sbi, FASTBOOT) ? CP_UMOUNT : CP_SYNC; | 505 | cpc.reason = __get_cp_reason(sbi); |
| 506 | |||
| 490 | mutex_lock(&sbi->gc_mutex); | 507 | mutex_lock(&sbi->gc_mutex); |
| 491 | write_checkpoint(sbi, &cpc); | 508 | write_checkpoint(sbi, &cpc); |
| 492 | mutex_unlock(&sbi->gc_mutex); | 509 | mutex_unlock(&sbi->gc_mutex); |
| 493 | } else { | 510 | } else { |
| 494 | f2fs_balance_fs(sbi); | 511 | f2fs_balance_fs(sbi); |
| 495 | } | 512 | } |
| 513 | f2fs_trace_ios(NULL, NULL, 1); | ||
| 496 | 514 | ||
| 497 | return 0; | 515 | return 0; |
| 498 | } | 516 | } |
| @@ -887,7 +905,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi) | |||
| 887 | atomic_set(&sbi->nr_pages[i], 0); | 905 | atomic_set(&sbi->nr_pages[i], 0); |
| 888 | 906 | ||
| 889 | sbi->dir_level = DEF_DIR_LEVEL; | 907 | sbi->dir_level = DEF_DIR_LEVEL; |
| 890 | sbi->need_fsck = false; | 908 | clear_sbi_flag(sbi, SBI_NEED_FSCK); |
| 891 | } | 909 | } |
| 892 | 910 | ||
| 893 | /* | 911 | /* |
| @@ -942,6 +960,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 942 | struct inode *root; | 960 | struct inode *root; |
| 943 | long err = -EINVAL; | 961 | long err = -EINVAL; |
| 944 | bool retry = true; | 962 | bool retry = true; |
| 963 | char *options = NULL; | ||
| 945 | int i; | 964 | int i; |
| 946 | 965 | ||
| 947 | try_onemore: | 966 | try_onemore: |
| @@ -973,9 +992,15 @@ try_onemore: | |||
| 973 | set_opt(sbi, POSIX_ACL); | 992 | set_opt(sbi, POSIX_ACL); |
| 974 | #endif | 993 | #endif |
| 975 | /* parse mount options */ | 994 | /* parse mount options */ |
| 976 | err = parse_options(sb, (char *)data); | 995 | options = kstrdup((const char *)data, GFP_KERNEL); |
| 977 | if (err) | 996 | if (data && !options) { |
| 997 | err = -ENOMEM; | ||
| 978 | goto free_sb_buf; | 998 | goto free_sb_buf; |
| 999 | } | ||
| 1000 | |||
| 1001 | err = parse_options(sb, options); | ||
| 1002 | if (err) | ||
| 1003 | goto free_options; | ||
| 979 | 1004 | ||
| 980 | sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize)); | 1005 | sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize)); |
| 981 | sb->s_max_links = F2FS_LINK_MAX; | 1006 | sb->s_max_links = F2FS_LINK_MAX; |
| @@ -998,7 +1023,7 @@ try_onemore: | |||
| 998 | mutex_init(&sbi->writepages); | 1023 | mutex_init(&sbi->writepages); |
| 999 | mutex_init(&sbi->cp_mutex); | 1024 | mutex_init(&sbi->cp_mutex); |
| 1000 | init_rwsem(&sbi->node_write); | 1025 | init_rwsem(&sbi->node_write); |
| 1001 | sbi->por_doing = false; | 1026 | clear_sbi_flag(sbi, SBI_POR_DOING); |
| 1002 | spin_lock_init(&sbi->stat_lock); | 1027 | spin_lock_init(&sbi->stat_lock); |
| 1003 | 1028 | ||
| 1004 | init_rwsem(&sbi->read_io.io_rwsem); | 1029 | init_rwsem(&sbi->read_io.io_rwsem); |
| @@ -1019,7 +1044,7 @@ try_onemore: | |||
| 1019 | if (IS_ERR(sbi->meta_inode)) { | 1044 | if (IS_ERR(sbi->meta_inode)) { |
| 1020 | f2fs_msg(sb, KERN_ERR, "Failed to read F2FS meta data inode"); | 1045 | f2fs_msg(sb, KERN_ERR, "Failed to read F2FS meta data inode"); |
| 1021 | err = PTR_ERR(sbi->meta_inode); | 1046 | err = PTR_ERR(sbi->meta_inode); |
| 1022 | goto free_sb_buf; | 1047 | goto free_options; |
| 1023 | } | 1048 | } |
| 1024 | 1049 | ||
| 1025 | err = get_valid_checkpoint(sbi); | 1050 | err = get_valid_checkpoint(sbi); |
| @@ -1122,10 +1147,19 @@ try_onemore: | |||
| 1122 | goto free_proc; | 1147 | goto free_proc; |
| 1123 | 1148 | ||
| 1124 | if (!retry) | 1149 | if (!retry) |
| 1125 | sbi->need_fsck = true; | 1150 | set_sbi_flag(sbi, SBI_NEED_FSCK); |
| 1126 | 1151 | ||
| 1127 | /* recover fsynced data */ | 1152 | /* recover fsynced data */ |
| 1128 | if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) { | 1153 | if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) { |
| 1154 | /* | ||
| 1155 | * mount should be failed, when device has readonly mode, and | ||
| 1156 | * previous checkpoint was not done by clean system shutdown. | ||
| 1157 | */ | ||
| 1158 | if (bdev_read_only(sb->s_bdev) && | ||
| 1159 | !is_set_ckpt_flags(sbi->ckpt, CP_UMOUNT_FLAG)) { | ||
| 1160 | err = -EROFS; | ||
| 1161 | goto free_kobj; | ||
| 1162 | } | ||
| 1129 | err = recover_fsync_data(sbi); | 1163 | err = recover_fsync_data(sbi); |
| 1130 | if (err) { | 1164 | if (err) { |
| 1131 | f2fs_msg(sb, KERN_ERR, | 1165 | f2fs_msg(sb, KERN_ERR, |
| @@ -1144,6 +1178,7 @@ try_onemore: | |||
| 1144 | if (err) | 1178 | if (err) |
| 1145 | goto free_kobj; | 1179 | goto free_kobj; |
| 1146 | } | 1180 | } |
| 1181 | kfree(options); | ||
| 1147 | return 0; | 1182 | return 0; |
| 1148 | 1183 | ||
| 1149 | free_kobj: | 1184 | free_kobj: |
| @@ -1168,6 +1203,8 @@ free_cp: | |||
| 1168 | free_meta_inode: | 1203 | free_meta_inode: |
| 1169 | make_bad_inode(sbi->meta_inode); | 1204 | make_bad_inode(sbi->meta_inode); |
| 1170 | iput(sbi->meta_inode); | 1205 | iput(sbi->meta_inode); |
| 1206 | free_options: | ||
| 1207 | kfree(options); | ||
| 1171 | free_sb_buf: | 1208 | free_sb_buf: |
| 1172 | brelse(raw_super_buf); | 1209 | brelse(raw_super_buf); |
| 1173 | free_sbi: | 1210 | free_sbi: |
| @@ -1188,11 +1225,18 @@ static struct dentry *f2fs_mount(struct file_system_type *fs_type, int flags, | |||
| 1188 | return mount_bdev(fs_type, flags, dev_name, data, f2fs_fill_super); | 1225 | return mount_bdev(fs_type, flags, dev_name, data, f2fs_fill_super); |
| 1189 | } | 1226 | } |
| 1190 | 1227 | ||
| 1228 | static void kill_f2fs_super(struct super_block *sb) | ||
| 1229 | { | ||
| 1230 | if (sb->s_root) | ||
| 1231 | set_sbi_flag(F2FS_SB(sb), SBI_IS_CLOSE); | ||
| 1232 | kill_block_super(sb); | ||
| 1233 | } | ||
| 1234 | |||
| 1191 | static struct file_system_type f2fs_fs_type = { | 1235 | static struct file_system_type f2fs_fs_type = { |
| 1192 | .owner = THIS_MODULE, | 1236 | .owner = THIS_MODULE, |
| 1193 | .name = "f2fs", | 1237 | .name = "f2fs", |
| 1194 | .mount = f2fs_mount, | 1238 | .mount = f2fs_mount, |
| 1195 | .kill_sb = kill_block_super, | 1239 | .kill_sb = kill_f2fs_super, |
| 1196 | .fs_flags = FS_REQUIRES_DEV, | 1240 | .fs_flags = FS_REQUIRES_DEV, |
| 1197 | }; | 1241 | }; |
| 1198 | MODULE_ALIAS_FS("f2fs"); | 1242 | MODULE_ALIAS_FS("f2fs"); |
| @@ -1220,6 +1264,8 @@ static int __init init_f2fs_fs(void) | |||
| 1220 | { | 1264 | { |
| 1221 | int err; | 1265 | int err; |
| 1222 | 1266 | ||
| 1267 | f2fs_build_trace_ios(); | ||
| 1268 | |||
| 1223 | err = init_inodecache(); | 1269 | err = init_inodecache(); |
| 1224 | if (err) | 1270 | if (err) |
| 1225 | goto fail; | 1271 | goto fail; |
| @@ -1229,12 +1275,9 @@ static int __init init_f2fs_fs(void) | |||
| 1229 | err = create_segment_manager_caches(); | 1275 | err = create_segment_manager_caches(); |
| 1230 | if (err) | 1276 | if (err) |
| 1231 | goto free_node_manager_caches; | 1277 | goto free_node_manager_caches; |
| 1232 | err = create_gc_caches(); | ||
| 1233 | if (err) | ||
| 1234 | goto free_segment_manager_caches; | ||
| 1235 | err = create_checkpoint_caches(); | 1278 | err = create_checkpoint_caches(); |
| 1236 | if (err) | 1279 | if (err) |
| 1237 | goto free_gc_caches; | 1280 | goto free_segment_manager_caches; |
| 1238 | f2fs_kset = kset_create_and_add("f2fs", NULL, fs_kobj); | 1281 | f2fs_kset = kset_create_and_add("f2fs", NULL, fs_kobj); |
| 1239 | if (!f2fs_kset) { | 1282 | if (!f2fs_kset) { |
| 1240 | err = -ENOMEM; | 1283 | err = -ENOMEM; |
| @@ -1251,8 +1294,6 @@ free_kset: | |||
| 1251 | kset_unregister(f2fs_kset); | 1294 | kset_unregister(f2fs_kset); |
| 1252 | free_checkpoint_caches: | 1295 | free_checkpoint_caches: |
| 1253 | destroy_checkpoint_caches(); | 1296 | destroy_checkpoint_caches(); |
| 1254 | free_gc_caches: | ||
| 1255 | destroy_gc_caches(); | ||
| 1256 | free_segment_manager_caches: | 1297 | free_segment_manager_caches: |
| 1257 | destroy_segment_manager_caches(); | 1298 | destroy_segment_manager_caches(); |
| 1258 | free_node_manager_caches: | 1299 | free_node_manager_caches: |
| @@ -1269,11 +1310,11 @@ static void __exit exit_f2fs_fs(void) | |||
| 1269 | f2fs_destroy_root_stats(); | 1310 | f2fs_destroy_root_stats(); |
| 1270 | unregister_filesystem(&f2fs_fs_type); | 1311 | unregister_filesystem(&f2fs_fs_type); |
| 1271 | destroy_checkpoint_caches(); | 1312 | destroy_checkpoint_caches(); |
| 1272 | destroy_gc_caches(); | ||
| 1273 | destroy_segment_manager_caches(); | 1313 | destroy_segment_manager_caches(); |
| 1274 | destroy_node_manager_caches(); | 1314 | destroy_node_manager_caches(); |
| 1275 | destroy_inodecache(); | 1315 | destroy_inodecache(); |
| 1276 | kset_unregister(f2fs_kset); | 1316 | kset_unregister(f2fs_kset); |
| 1317 | f2fs_destroy_trace_ios(); | ||
| 1277 | } | 1318 | } |
| 1278 | 1319 | ||
| 1279 | module_init(init_f2fs_fs) | 1320 | module_init(init_f2fs_fs) |
diff --git a/fs/f2fs/trace.c b/fs/f2fs/trace.c new file mode 100644 index 000000000000..875aa8179bc1 --- /dev/null +++ b/fs/f2fs/trace.c | |||
| @@ -0,0 +1,159 @@ | |||
| 1 | /* | ||
| 2 | * f2fs IO tracer | ||
| 3 | * | ||
| 4 | * Copyright (c) 2014 Motorola Mobility | ||
| 5 | * Copyright (c) 2014 Jaegeuk Kim <jaegeuk@kernel.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | #include <linux/fs.h> | ||
| 12 | #include <linux/f2fs_fs.h> | ||
| 13 | #include <linux/sched.h> | ||
| 14 | #include <linux/radix-tree.h> | ||
| 15 | |||
| 16 | #include "f2fs.h" | ||
| 17 | #include "trace.h" | ||
| 18 | |||
| 19 | static RADIX_TREE(pids, GFP_ATOMIC); | ||
| 20 | static spinlock_t pids_lock; | ||
| 21 | static struct last_io_info last_io; | ||
| 22 | |||
| 23 | static inline void __print_last_io(void) | ||
| 24 | { | ||
| 25 | if (!last_io.len) | ||
| 26 | return; | ||
| 27 | |||
| 28 | trace_printk("%3x:%3x %4x %-16s %2x %5x %12x %4x\n", | ||
| 29 | last_io.major, last_io.minor, | ||
| 30 | last_io.pid, "----------------", | ||
| 31 | last_io.type, | ||
| 32 | last_io.fio.rw, last_io.fio.blk_addr, | ||
| 33 | last_io.len); | ||
| 34 | memset(&last_io, 0, sizeof(last_io)); | ||
| 35 | } | ||
| 36 | |||
| 37 | static int __file_type(struct inode *inode, pid_t pid) | ||
| 38 | { | ||
| 39 | if (f2fs_is_atomic_file(inode)) | ||
| 40 | return __ATOMIC_FILE; | ||
| 41 | else if (f2fs_is_volatile_file(inode)) | ||
| 42 | return __VOLATILE_FILE; | ||
| 43 | else if (S_ISDIR(inode->i_mode)) | ||
| 44 | return __DIR_FILE; | ||
| 45 | else if (inode->i_ino == F2FS_NODE_INO(F2FS_I_SB(inode))) | ||
| 46 | return __NODE_FILE; | ||
| 47 | else if (inode->i_ino == F2FS_META_INO(F2FS_I_SB(inode))) | ||
| 48 | return __META_FILE; | ||
| 49 | else if (pid) | ||
| 50 | return __NORMAL_FILE; | ||
| 51 | else | ||
| 52 | return __MISC_FILE; | ||
| 53 | } | ||
| 54 | |||
| 55 | void f2fs_trace_pid(struct page *page) | ||
| 56 | { | ||
| 57 | struct inode *inode = page->mapping->host; | ||
| 58 | pid_t pid = task_pid_nr(current); | ||
| 59 | void *p; | ||
| 60 | |||
| 61 | page->private = pid; | ||
| 62 | |||
| 63 | if (radix_tree_preload(GFP_NOFS)) | ||
| 64 | return; | ||
| 65 | |||
| 66 | spin_lock(&pids_lock); | ||
| 67 | p = radix_tree_lookup(&pids, pid); | ||
| 68 | if (p == current) | ||
| 69 | goto out; | ||
| 70 | if (p) | ||
| 71 | radix_tree_delete(&pids, pid); | ||
| 72 | |||
| 73 | f2fs_radix_tree_insert(&pids, pid, current); | ||
| 74 | |||
| 75 | trace_printk("%3x:%3x %4x %-16s\n", | ||
| 76 | MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev), | ||
| 77 | pid, current->comm); | ||
| 78 | out: | ||
| 79 | spin_unlock(&pids_lock); | ||
| 80 | radix_tree_preload_end(); | ||
| 81 | } | ||
| 82 | |||
| 83 | void f2fs_trace_ios(struct page *page, struct f2fs_io_info *fio, int flush) | ||
| 84 | { | ||
| 85 | struct inode *inode; | ||
| 86 | pid_t pid; | ||
| 87 | int major, minor; | ||
| 88 | |||
| 89 | if (flush) { | ||
| 90 | __print_last_io(); | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | |||
| 94 | inode = page->mapping->host; | ||
| 95 | pid = page_private(page); | ||
| 96 | |||
| 97 | major = MAJOR(inode->i_sb->s_dev); | ||
| 98 | minor = MINOR(inode->i_sb->s_dev); | ||
| 99 | |||
| 100 | if (last_io.major == major && last_io.minor == minor && | ||
| 101 | last_io.pid == pid && | ||
| 102 | last_io.type == __file_type(inode, pid) && | ||
| 103 | last_io.fio.rw == fio->rw && | ||
| 104 | last_io.fio.blk_addr + last_io.len == fio->blk_addr) { | ||
| 105 | last_io.len++; | ||
| 106 | return; | ||
| 107 | } | ||
| 108 | |||
| 109 | __print_last_io(); | ||
| 110 | |||
| 111 | last_io.major = major; | ||
| 112 | last_io.minor = minor; | ||
| 113 | last_io.pid = pid; | ||
| 114 | last_io.type = __file_type(inode, pid); | ||
| 115 | last_io.fio = *fio; | ||
| 116 | last_io.len = 1; | ||
| 117 | return; | ||
| 118 | } | ||
| 119 | |||
| 120 | void f2fs_build_trace_ios(void) | ||
| 121 | { | ||
| 122 | spin_lock_init(&pids_lock); | ||
| 123 | } | ||
| 124 | |||
| 125 | #define PIDVEC_SIZE 128 | ||
| 126 | static unsigned int gang_lookup_pids(pid_t *results, unsigned long first_index, | ||
| 127 | unsigned int max_items) | ||
| 128 | { | ||
| 129 | struct radix_tree_iter iter; | ||
| 130 | void **slot; | ||
| 131 | unsigned int ret = 0; | ||
| 132 | |||
| 133 | if (unlikely(!max_items)) | ||
| 134 | return 0; | ||
| 135 | |||
| 136 | radix_tree_for_each_slot(slot, &pids, &iter, first_index) { | ||
| 137 | results[ret] = iter.index; | ||
| 138 | if (++ret == PIDVEC_SIZE) | ||
| 139 | break; | ||
| 140 | } | ||
| 141 | return ret; | ||
| 142 | } | ||
| 143 | |||
| 144 | void f2fs_destroy_trace_ios(void) | ||
| 145 | { | ||
| 146 | pid_t pid[PIDVEC_SIZE]; | ||
| 147 | pid_t next_pid = 0; | ||
| 148 | unsigned int found; | ||
| 149 | |||
| 150 | spin_lock(&pids_lock); | ||
| 151 | while ((found = gang_lookup_pids(pid, next_pid, PIDVEC_SIZE))) { | ||
| 152 | unsigned idx; | ||
| 153 | |||
| 154 | next_pid = pid[found - 1] + 1; | ||
| 155 | for (idx = 0; idx < found; idx++) | ||
| 156 | radix_tree_delete(&pids, pid[idx]); | ||
| 157 | } | ||
| 158 | spin_unlock(&pids_lock); | ||
| 159 | } | ||
diff --git a/fs/f2fs/trace.h b/fs/f2fs/trace.h new file mode 100644 index 000000000000..1041dbeb52ae --- /dev/null +++ b/fs/f2fs/trace.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | /* | ||
| 2 | * f2fs IO tracer | ||
| 3 | * | ||
| 4 | * Copyright (c) 2014 Motorola Mobility | ||
| 5 | * Copyright (c) 2014 Jaegeuk Kim <jaegeuk@kernel.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | #ifndef __F2FS_TRACE_H__ | ||
| 12 | #define __F2FS_TRACE_H__ | ||
| 13 | |||
| 14 | #ifdef CONFIG_F2FS_IO_TRACE | ||
| 15 | #include <trace/events/f2fs.h> | ||
| 16 | |||
| 17 | enum file_type { | ||
| 18 | __NORMAL_FILE, | ||
| 19 | __DIR_FILE, | ||
| 20 | __NODE_FILE, | ||
| 21 | __META_FILE, | ||
| 22 | __ATOMIC_FILE, | ||
| 23 | __VOLATILE_FILE, | ||
| 24 | __MISC_FILE, | ||
| 25 | }; | ||
| 26 | |||
| 27 | struct last_io_info { | ||
| 28 | int major, minor; | ||
| 29 | pid_t pid; | ||
| 30 | enum file_type type; | ||
| 31 | struct f2fs_io_info fio; | ||
| 32 | block_t len; | ||
| 33 | }; | ||
| 34 | |||
| 35 | extern void f2fs_trace_pid(struct page *); | ||
| 36 | extern void f2fs_trace_ios(struct page *, struct f2fs_io_info *, int); | ||
| 37 | extern void f2fs_build_trace_ios(void); | ||
| 38 | extern void f2fs_destroy_trace_ios(void); | ||
| 39 | #else | ||
| 40 | #define f2fs_trace_pid(p) | ||
| 41 | #define f2fs_trace_ios(p, i, n) | ||
| 42 | #define f2fs_build_trace_ios() | ||
| 43 | #define f2fs_destroy_trace_ios() | ||
| 44 | |||
| 45 | #endif | ||
| 46 | #endif /* __F2FS_TRACE_H__ */ | ||
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 87f14e90e984..a23556c32703 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h | |||
| @@ -19,12 +19,16 @@ | |||
| 19 | #define F2FS_MAX_LOG_SECTOR_SIZE 12 /* 12 bits for 4096 bytes */ | 19 | #define F2FS_MAX_LOG_SECTOR_SIZE 12 /* 12 bits for 4096 bytes */ |
| 20 | #define F2FS_LOG_SECTORS_PER_BLOCK 3 /* log number for sector/blk */ | 20 | #define F2FS_LOG_SECTORS_PER_BLOCK 3 /* log number for sector/blk */ |
| 21 | #define F2FS_BLKSIZE 4096 /* support only 4KB block */ | 21 | #define F2FS_BLKSIZE 4096 /* support only 4KB block */ |
| 22 | #define F2FS_BLKSIZE_BITS 12 /* bits for F2FS_BLKSIZE */ | ||
| 22 | #define F2FS_MAX_EXTENSION 64 /* # of extension entries */ | 23 | #define F2FS_MAX_EXTENSION 64 /* # of extension entries */ |
| 23 | #define F2FS_BLK_ALIGN(x) (((x) + F2FS_BLKSIZE - 1) / F2FS_BLKSIZE) | 24 | #define F2FS_BLK_ALIGN(x) (((x) + F2FS_BLKSIZE - 1) / F2FS_BLKSIZE) |
| 24 | 25 | ||
| 25 | #define NULL_ADDR ((block_t)0) /* used as block_t addresses */ | 26 | #define NULL_ADDR ((block_t)0) /* used as block_t addresses */ |
| 26 | #define NEW_ADDR ((block_t)-1) /* used as block_t addresses */ | 27 | #define NEW_ADDR ((block_t)-1) /* used as block_t addresses */ |
| 27 | 28 | ||
| 29 | #define F2FS_BYTES_TO_BLK(bytes) ((bytes) >> F2FS_BLKSIZE_BITS) | ||
| 30 | #define F2FS_BLK_TO_BYTES(blk) ((blk) << F2FS_BLKSIZE_BITS) | ||
| 31 | |||
| 28 | /* 0, 1(node nid), 2(meta nid) are reserved node id */ | 32 | /* 0, 1(node nid), 2(meta nid) are reserved node id */ |
| 29 | #define F2FS_RESERVED_NODE_NUM 3 | 33 | #define F2FS_RESERVED_NODE_NUM 3 |
| 30 | 34 | ||
| @@ -87,6 +91,7 @@ struct f2fs_super_block { | |||
| 87 | /* | 91 | /* |
| 88 | * For checkpoint | 92 | * For checkpoint |
| 89 | */ | 93 | */ |
| 94 | #define CP_FASTBOOT_FLAG 0x00000020 | ||
| 90 | #define CP_FSCK_FLAG 0x00000010 | 95 | #define CP_FSCK_FLAG 0x00000010 |
| 91 | #define CP_ERROR_FLAG 0x00000008 | 96 | #define CP_ERROR_FLAG 0x00000008 |
| 92 | #define CP_COMPACT_SUM_FLAG 0x00000004 | 97 | #define CP_COMPACT_SUM_FLAG 0x00000004 |
| @@ -224,6 +229,8 @@ enum { | |||
| 224 | OFFSET_BIT_SHIFT | 229 | OFFSET_BIT_SHIFT |
| 225 | }; | 230 | }; |
| 226 | 231 | ||
| 232 | #define OFFSET_BIT_MASK (0x07) /* (0x01 << OFFSET_BIT_SHIFT) - 1 */ | ||
| 233 | |||
| 227 | struct node_footer { | 234 | struct node_footer { |
| 228 | __le32 nid; /* node id */ | 235 | __le32 nid; /* node id */ |
| 229 | __le32 ino; /* inode nunmber */ | 236 | __le32 ino; /* inode nunmber */ |
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index bbc4de9baef7..5422dbfaf97d 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h | |||
| @@ -72,6 +72,7 @@ | |||
| 72 | #define show_cpreason(type) \ | 72 | #define show_cpreason(type) \ |
| 73 | __print_symbolic(type, \ | 73 | __print_symbolic(type, \ |
| 74 | { CP_UMOUNT, "Umount" }, \ | 74 | { CP_UMOUNT, "Umount" }, \ |
| 75 | { CP_FASTBOOT, "Fastboot" }, \ | ||
| 75 | { CP_SYNC, "Sync" }, \ | 76 | { CP_SYNC, "Sync" }, \ |
| 76 | { CP_DISCARD, "Discard" }) | 77 | { CP_DISCARD, "Discard" }) |
| 77 | 78 | ||
| @@ -148,14 +149,14 @@ DEFINE_EVENT(f2fs__inode, f2fs_sync_file_enter, | |||
| 148 | 149 | ||
| 149 | TRACE_EVENT(f2fs_sync_file_exit, | 150 | TRACE_EVENT(f2fs_sync_file_exit, |
| 150 | 151 | ||
| 151 | TP_PROTO(struct inode *inode, bool need_cp, int datasync, int ret), | 152 | TP_PROTO(struct inode *inode, int need_cp, int datasync, int ret), |
| 152 | 153 | ||
| 153 | TP_ARGS(inode, need_cp, datasync, ret), | 154 | TP_ARGS(inode, need_cp, datasync, ret), |
| 154 | 155 | ||
| 155 | TP_STRUCT__entry( | 156 | TP_STRUCT__entry( |
| 156 | __field(dev_t, dev) | 157 | __field(dev_t, dev) |
| 157 | __field(ino_t, ino) | 158 | __field(ino_t, ino) |
| 158 | __field(bool, need_cp) | 159 | __field(int, need_cp) |
| 159 | __field(int, datasync) | 160 | __field(int, datasync) |
| 160 | __field(int, ret) | 161 | __field(int, ret) |
| 161 | ), | 162 | ), |
| @@ -190,7 +191,7 @@ TRACE_EVENT(f2fs_sync_fs, | |||
| 190 | 191 | ||
| 191 | TP_fast_assign( | 192 | TP_fast_assign( |
| 192 | __entry->dev = sb->s_dev; | 193 | __entry->dev = sb->s_dev; |
| 193 | __entry->dirty = F2FS_SB(sb)->s_dirty; | 194 | __entry->dirty = is_sbi_flag_set(F2FS_SB(sb), SBI_IS_DIRTY); |
| 194 | __entry->wait = wait; | 195 | __entry->wait = wait; |
| 195 | ), | 196 | ), |
| 196 | 197 | ||
| @@ -440,38 +441,6 @@ TRACE_EVENT(f2fs_truncate_partial_nodes, | |||
| 440 | __entry->err) | 441 | __entry->err) |
| 441 | ); | 442 | ); |
| 442 | 443 | ||
| 443 | TRACE_EVENT_CONDITION(f2fs_submit_page_bio, | ||
| 444 | |||
| 445 | TP_PROTO(struct page *page, sector_t blkaddr, int type), | ||
| 446 | |||
| 447 | TP_ARGS(page, blkaddr, type), | ||
| 448 | |||
| 449 | TP_CONDITION(page->mapping), | ||
| 450 | |||
| 451 | TP_STRUCT__entry( | ||
| 452 | __field(dev_t, dev) | ||
| 453 | __field(ino_t, ino) | ||
| 454 | __field(pgoff_t, index) | ||
| 455 | __field(sector_t, blkaddr) | ||
| 456 | __field(int, type) | ||
| 457 | ), | ||
| 458 | |||
| 459 | TP_fast_assign( | ||
| 460 | __entry->dev = page->mapping->host->i_sb->s_dev; | ||
| 461 | __entry->ino = page->mapping->host->i_ino; | ||
| 462 | __entry->index = page->index; | ||
| 463 | __entry->blkaddr = blkaddr; | ||
| 464 | __entry->type = type; | ||
| 465 | ), | ||
| 466 | |||
| 467 | TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, " | ||
| 468 | "blkaddr = 0x%llx, bio_type = %s%s", | ||
| 469 | show_dev_ino(__entry), | ||
| 470 | (unsigned long)__entry->index, | ||
| 471 | (unsigned long long)__entry->blkaddr, | ||
| 472 | show_bio_type(__entry->type)) | ||
| 473 | ); | ||
| 474 | |||
| 475 | TRACE_EVENT(f2fs_get_data_block, | 444 | TRACE_EVENT(f2fs_get_data_block, |
| 476 | TP_PROTO(struct inode *inode, sector_t iblock, | 445 | TP_PROTO(struct inode *inode, sector_t iblock, |
| 477 | struct buffer_head *bh, int ret), | 446 | struct buffer_head *bh, int ret), |
| @@ -680,11 +649,63 @@ TRACE_EVENT(f2fs_reserve_new_block, | |||
| 680 | __entry->ofs_in_node) | 649 | __entry->ofs_in_node) |
| 681 | ); | 650 | ); |
| 682 | 651 | ||
| 652 | DECLARE_EVENT_CLASS(f2fs__submit_page_bio, | ||
| 653 | |||
| 654 | TP_PROTO(struct page *page, struct f2fs_io_info *fio), | ||
| 655 | |||
| 656 | TP_ARGS(page, fio), | ||
| 657 | |||
| 658 | TP_STRUCT__entry( | ||
| 659 | __field(dev_t, dev) | ||
| 660 | __field(ino_t, ino) | ||
| 661 | __field(pgoff_t, index) | ||
| 662 | __field(block_t, blkaddr) | ||
| 663 | __field(int, rw) | ||
| 664 | __field(int, type) | ||
| 665 | ), | ||
| 666 | |||
| 667 | TP_fast_assign( | ||
| 668 | __entry->dev = page->mapping->host->i_sb->s_dev; | ||
| 669 | __entry->ino = page->mapping->host->i_ino; | ||
| 670 | __entry->index = page->index; | ||
| 671 | __entry->blkaddr = fio->blk_addr; | ||
| 672 | __entry->rw = fio->rw; | ||
| 673 | __entry->type = fio->type; | ||
| 674 | ), | ||
| 675 | |||
| 676 | TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, " | ||
| 677 | "blkaddr = 0x%llx, rw = %s%s, type = %s", | ||
| 678 | show_dev_ino(__entry), | ||
| 679 | (unsigned long)__entry->index, | ||
| 680 | (unsigned long long)__entry->blkaddr, | ||
| 681 | show_bio_type(__entry->rw), | ||
| 682 | show_block_type(__entry->type)) | ||
| 683 | ); | ||
| 684 | |||
| 685 | DEFINE_EVENT_CONDITION(f2fs__submit_page_bio, f2fs_submit_page_bio, | ||
| 686 | |||
| 687 | TP_PROTO(struct page *page, struct f2fs_io_info *fio), | ||
| 688 | |||
| 689 | TP_ARGS(page, fio), | ||
| 690 | |||
| 691 | TP_CONDITION(page->mapping) | ||
| 692 | ); | ||
| 693 | |||
| 694 | DEFINE_EVENT_CONDITION(f2fs__submit_page_bio, f2fs_submit_page_mbio, | ||
| 695 | |||
| 696 | TP_PROTO(struct page *page, struct f2fs_io_info *fio), | ||
| 697 | |||
| 698 | TP_ARGS(page, fio), | ||
| 699 | |||
| 700 | TP_CONDITION(page->mapping) | ||
| 701 | ); | ||
| 702 | |||
| 683 | DECLARE_EVENT_CLASS(f2fs__submit_bio, | 703 | DECLARE_EVENT_CLASS(f2fs__submit_bio, |
| 684 | 704 | ||
| 685 | TP_PROTO(struct super_block *sb, int rw, int type, struct bio *bio), | 705 | TP_PROTO(struct super_block *sb, struct f2fs_io_info *fio, |
| 706 | struct bio *bio), | ||
| 686 | 707 | ||
| 687 | TP_ARGS(sb, rw, type, bio), | 708 | TP_ARGS(sb, fio, bio), |
| 688 | 709 | ||
| 689 | TP_STRUCT__entry( | 710 | TP_STRUCT__entry( |
| 690 | __field(dev_t, dev) | 711 | __field(dev_t, dev) |
| @@ -696,8 +717,8 @@ DECLARE_EVENT_CLASS(f2fs__submit_bio, | |||
| 696 | 717 | ||
| 697 | TP_fast_assign( | 718 | TP_fast_assign( |
| 698 | __entry->dev = sb->s_dev; | 719 | __entry->dev = sb->s_dev; |
| 699 | __entry->rw = rw; | 720 | __entry->rw = fio->rw; |
| 700 | __entry->type = type; | 721 | __entry->type = fio->type; |
| 701 | __entry->sector = bio->bi_iter.bi_sector; | 722 | __entry->sector = bio->bi_iter.bi_sector; |
| 702 | __entry->size = bio->bi_iter.bi_size; | 723 | __entry->size = bio->bi_iter.bi_size; |
| 703 | ), | 724 | ), |
| @@ -712,18 +733,20 @@ DECLARE_EVENT_CLASS(f2fs__submit_bio, | |||
| 712 | 733 | ||
| 713 | DEFINE_EVENT_CONDITION(f2fs__submit_bio, f2fs_submit_write_bio, | 734 | DEFINE_EVENT_CONDITION(f2fs__submit_bio, f2fs_submit_write_bio, |
| 714 | 735 | ||
| 715 | TP_PROTO(struct super_block *sb, int rw, int type, struct bio *bio), | 736 | TP_PROTO(struct super_block *sb, struct f2fs_io_info *fio, |
| 737 | struct bio *bio), | ||
| 716 | 738 | ||
| 717 | TP_ARGS(sb, rw, type, bio), | 739 | TP_ARGS(sb, fio, bio), |
| 718 | 740 | ||
| 719 | TP_CONDITION(bio) | 741 | TP_CONDITION(bio) |
| 720 | ); | 742 | ); |
| 721 | 743 | ||
| 722 | DEFINE_EVENT_CONDITION(f2fs__submit_bio, f2fs_submit_read_bio, | 744 | DEFINE_EVENT_CONDITION(f2fs__submit_bio, f2fs_submit_read_bio, |
| 723 | 745 | ||
| 724 | TP_PROTO(struct super_block *sb, int rw, int type, struct bio *bio), | 746 | TP_PROTO(struct super_block *sb, struct f2fs_io_info *fio, |
| 747 | struct bio *bio), | ||
| 725 | 748 | ||
| 726 | TP_ARGS(sb, rw, type, bio), | 749 | TP_ARGS(sb, fio, bio), |
| 727 | 750 | ||
| 728 | TP_CONDITION(bio) | 751 | TP_CONDITION(bio) |
| 729 | ); | 752 | ); |
| @@ -916,38 +939,6 @@ TRACE_EVENT(f2fs_writepages, | |||
| 916 | __entry->for_sync) | 939 | __entry->for_sync) |
| 917 | ); | 940 | ); |
| 918 | 941 | ||
| 919 | TRACE_EVENT(f2fs_submit_page_mbio, | ||
| 920 | |||
| 921 | TP_PROTO(struct page *page, int rw, int type, block_t blk_addr), | ||
| 922 | |||
| 923 | TP_ARGS(page, rw, type, blk_addr), | ||
| 924 | |||
| 925 | TP_STRUCT__entry( | ||
| 926 | __field(dev_t, dev) | ||
| 927 | __field(ino_t, ino) | ||
| 928 | __field(int, rw) | ||
| 929 | __field(int, type) | ||
| 930 | __field(pgoff_t, index) | ||
| 931 | __field(block_t, block) | ||
| 932 | ), | ||
| 933 | |||
| 934 | TP_fast_assign( | ||
| 935 | __entry->dev = page->mapping->host->i_sb->s_dev; | ||
| 936 | __entry->ino = page->mapping->host->i_ino; | ||
| 937 | __entry->rw = rw; | ||
| 938 | __entry->type = type; | ||
| 939 | __entry->index = page->index; | ||
| 940 | __entry->block = blk_addr; | ||
| 941 | ), | ||
| 942 | |||
| 943 | TP_printk("dev = (%d,%d), ino = %lu, %s%s, %s, index = %lu, blkaddr = 0x%llx", | ||
| 944 | show_dev_ino(__entry), | ||
| 945 | show_bio_type(__entry->rw), | ||
| 946 | show_block_type(__entry->type), | ||
| 947 | (unsigned long)__entry->index, | ||
| 948 | (unsigned long long)__entry->block) | ||
| 949 | ); | ||
| 950 | |||
| 951 | TRACE_EVENT(f2fs_write_checkpoint, | 942 | TRACE_EVENT(f2fs_write_checkpoint, |
| 952 | 943 | ||
| 953 | TP_PROTO(struct super_block *sb, int reason, char *msg), | 944 | TP_PROTO(struct super_block *sb, int reason, char *msg), |
| @@ -998,14 +989,15 @@ TRACE_EVENT(f2fs_issue_discard, | |||
| 998 | 989 | ||
| 999 | TRACE_EVENT(f2fs_issue_flush, | 990 | TRACE_EVENT(f2fs_issue_flush, |
| 1000 | 991 | ||
| 1001 | TP_PROTO(struct super_block *sb, bool nobarrier, bool flush_merge), | 992 | TP_PROTO(struct super_block *sb, unsigned int nobarrier, |
| 993 | unsigned int flush_merge), | ||
| 1002 | 994 | ||
| 1003 | TP_ARGS(sb, nobarrier, flush_merge), | 995 | TP_ARGS(sb, nobarrier, flush_merge), |
| 1004 | 996 | ||
| 1005 | TP_STRUCT__entry( | 997 | TP_STRUCT__entry( |
| 1006 | __field(dev_t, dev) | 998 | __field(dev_t, dev) |
| 1007 | __field(bool, nobarrier) | 999 | __field(unsigned int, nobarrier) |
| 1008 | __field(bool, flush_merge) | 1000 | __field(unsigned int, flush_merge) |
| 1009 | ), | 1001 | ), |
| 1010 | 1002 | ||
| 1011 | TP_fast_assign( | 1003 | TP_fast_assign( |
