diff options
Diffstat (limited to 'fs/f2fs/segment.c')
-rw-r--r-- | fs/f2fs/segment.c | 122 |
1 files changed, 55 insertions, 67 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index f77b3258454a..5904a411c86f 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c | |||
@@ -86,6 +86,7 @@ static inline unsigned long __reverse_ffs(unsigned long word) | |||
86 | /* | 86 | /* |
87 | * __find_rev_next(_zero)_bit is copied from lib/find_next_bit.c because | 87 | * __find_rev_next(_zero)_bit is copied from lib/find_next_bit.c because |
88 | * f2fs_set_bit makes MSB and LSB reversed in a byte. | 88 | * f2fs_set_bit makes MSB and LSB reversed in a byte. |
89 | * @size must be integral times of unsigned long. | ||
89 | * Example: | 90 | * Example: |
90 | * MSB <--> LSB | 91 | * MSB <--> LSB |
91 | * f2fs_set_bit(0, bitmap) => 1000 0000 | 92 | * f2fs_set_bit(0, bitmap) => 1000 0000 |
@@ -95,94 +96,73 @@ static unsigned long __find_rev_next_bit(const unsigned long *addr, | |||
95 | unsigned long size, unsigned long offset) | 96 | unsigned long size, unsigned long offset) |
96 | { | 97 | { |
97 | const unsigned long *p = addr + BIT_WORD(offset); | 98 | const unsigned long *p = addr + BIT_WORD(offset); |
98 | unsigned long result = offset & ~(BITS_PER_LONG - 1); | 99 | unsigned long result = size; |
99 | unsigned long tmp; | 100 | unsigned long tmp; |
100 | 101 | ||
101 | if (offset >= size) | 102 | if (offset >= size) |
102 | return size; | 103 | return size; |
103 | 104 | ||
104 | size -= result; | 105 | size -= (offset & ~(BITS_PER_LONG - 1)); |
105 | offset %= BITS_PER_LONG; | 106 | offset %= BITS_PER_LONG; |
106 | if (!offset) | 107 | |
107 | goto aligned; | 108 | while (1) { |
108 | 109 | if (*p == 0) | |
109 | tmp = __reverse_ulong((unsigned char *)p); | 110 | goto pass; |
110 | tmp &= ~0UL >> offset; | 111 | |
111 | |||
112 | if (size < BITS_PER_LONG) | ||
113 | goto found_first; | ||
114 | if (tmp) | ||
115 | goto found_middle; | ||
116 | |||
117 | size -= BITS_PER_LONG; | ||
118 | result += BITS_PER_LONG; | ||
119 | p++; | ||
120 | aligned: | ||
121 | while (size & ~(BITS_PER_LONG-1)) { | ||
122 | tmp = __reverse_ulong((unsigned char *)p); | 112 | tmp = __reverse_ulong((unsigned char *)p); |
113 | |||
114 | tmp &= ~0UL >> offset; | ||
115 | if (size < BITS_PER_LONG) | ||
116 | tmp &= (~0UL << (BITS_PER_LONG - size)); | ||
123 | if (tmp) | 117 | if (tmp) |
124 | goto found_middle; | 118 | goto found; |
125 | result += BITS_PER_LONG; | 119 | pass: |
120 | if (size <= BITS_PER_LONG) | ||
121 | break; | ||
126 | size -= BITS_PER_LONG; | 122 | size -= BITS_PER_LONG; |
123 | offset = 0; | ||
127 | p++; | 124 | p++; |
128 | } | 125 | } |
129 | if (!size) | 126 | return result; |
130 | return result; | 127 | found: |
131 | 128 | return result - size + __reverse_ffs(tmp); | |
132 | tmp = __reverse_ulong((unsigned char *)p); | ||
133 | found_first: | ||
134 | tmp &= (~0UL << (BITS_PER_LONG - size)); | ||
135 | if (!tmp) /* Are any bits set? */ | ||
136 | return result + size; /* Nope. */ | ||
137 | found_middle: | ||
138 | return result + __reverse_ffs(tmp); | ||
139 | } | 129 | } |
140 | 130 | ||
141 | static unsigned long __find_rev_next_zero_bit(const unsigned long *addr, | 131 | static unsigned long __find_rev_next_zero_bit(const unsigned long *addr, |
142 | unsigned long size, unsigned long offset) | 132 | unsigned long size, unsigned long offset) |
143 | { | 133 | { |
144 | const unsigned long *p = addr + BIT_WORD(offset); | 134 | const unsigned long *p = addr + BIT_WORD(offset); |
145 | unsigned long result = offset & ~(BITS_PER_LONG - 1); | 135 | unsigned long result = size; |
146 | unsigned long tmp; | 136 | unsigned long tmp; |
147 | 137 | ||
148 | if (offset >= size) | 138 | if (offset >= size) |
149 | return size; | 139 | return size; |
150 | 140 | ||
151 | size -= result; | 141 | size -= (offset & ~(BITS_PER_LONG - 1)); |
152 | offset %= BITS_PER_LONG; | 142 | offset %= BITS_PER_LONG; |
153 | if (!offset) | 143 | |
154 | goto aligned; | 144 | while (1) { |
155 | 145 | if (*p == ~0UL) | |
156 | tmp = __reverse_ulong((unsigned char *)p); | 146 | goto pass; |
157 | tmp |= ~((~0UL << offset) >> offset); | 147 | |
158 | |||
159 | if (size < BITS_PER_LONG) | ||
160 | goto found_first; | ||
161 | if (tmp != ~0UL) | ||
162 | goto found_middle; | ||
163 | |||
164 | size -= BITS_PER_LONG; | ||
165 | result += BITS_PER_LONG; | ||
166 | p++; | ||
167 | aligned: | ||
168 | while (size & ~(BITS_PER_LONG - 1)) { | ||
169 | tmp = __reverse_ulong((unsigned char *)p); | 148 | tmp = __reverse_ulong((unsigned char *)p); |
149 | |||
150 | if (offset) | ||
151 | tmp |= ~0UL << (BITS_PER_LONG - offset); | ||
152 | if (size < BITS_PER_LONG) | ||
153 | tmp |= ~0UL >> size; | ||
170 | if (tmp != ~0UL) | 154 | if (tmp != ~0UL) |
171 | goto found_middle; | 155 | goto found; |
172 | result += BITS_PER_LONG; | 156 | pass: |
157 | if (size <= BITS_PER_LONG) | ||
158 | break; | ||
173 | size -= BITS_PER_LONG; | 159 | size -= BITS_PER_LONG; |
160 | offset = 0; | ||
174 | p++; | 161 | p++; |
175 | } | 162 | } |
176 | if (!size) | 163 | return result; |
177 | return result; | 164 | found: |
178 | 165 | return result - size + __reverse_ffz(tmp); | |
179 | tmp = __reverse_ulong((unsigned char *)p); | ||
180 | found_first: | ||
181 | tmp |= ~(~0UL << (BITS_PER_LONG - size)); | ||
182 | if (tmp == ~0UL) /* Are any bits zero? */ | ||
183 | return result + size; /* Nope. */ | ||
184 | found_middle: | ||
185 | return result + __reverse_ffz(tmp); | ||
186 | } | 166 | } |
187 | 167 | ||
188 | void register_inmem_page(struct inode *inode, struct page *page) | 168 | void register_inmem_page(struct inode *inode, struct page *page) |
@@ -233,7 +213,7 @@ int commit_inmem_pages(struct inode *inode, bool abort) | |||
233 | * inode becomes free by iget_locked in f2fs_iget. | 213 | * inode becomes free by iget_locked in f2fs_iget. |
234 | */ | 214 | */ |
235 | if (!abort) { | 215 | if (!abort) { |
236 | f2fs_balance_fs(sbi); | 216 | f2fs_balance_fs(sbi, true); |
237 | f2fs_lock_op(sbi); | 217 | f2fs_lock_op(sbi); |
238 | } | 218 | } |
239 | 219 | ||
@@ -257,6 +237,7 @@ int commit_inmem_pages(struct inode *inode, bool abort) | |||
257 | submit_bio = true; | 237 | submit_bio = true; |
258 | } | 238 | } |
259 | } else { | 239 | } else { |
240 | ClearPageUptodate(cur->page); | ||
260 | trace_f2fs_commit_inmem_page(cur->page, INMEM_DROP); | 241 | trace_f2fs_commit_inmem_page(cur->page, INMEM_DROP); |
261 | } | 242 | } |
262 | set_page_private(cur->page, 0); | 243 | set_page_private(cur->page, 0); |
@@ -281,8 +262,10 @@ int commit_inmem_pages(struct inode *inode, bool abort) | |||
281 | * This function balances dirty node and dentry pages. | 262 | * This function balances dirty node and dentry pages. |
282 | * In addition, it controls garbage collection. | 263 | * In addition, it controls garbage collection. |
283 | */ | 264 | */ |
284 | void f2fs_balance_fs(struct f2fs_sb_info *sbi) | 265 | void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) |
285 | { | 266 | { |
267 | if (!need) | ||
268 | return; | ||
286 | /* | 269 | /* |
287 | * We should do GC or end up with checkpoint, if there are so many dirty | 270 | * We should do GC or end up with checkpoint, if there are so many dirty |
288 | * dir/node pages without enough free segments. | 271 | * dir/node pages without enough free segments. |
@@ -310,8 +293,12 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) | |||
310 | if (!available_free_memory(sbi, NAT_ENTRIES) || | 293 | if (!available_free_memory(sbi, NAT_ENTRIES) || |
311 | excess_prefree_segs(sbi) || | 294 | excess_prefree_segs(sbi) || |
312 | !available_free_memory(sbi, INO_ENTRIES) || | 295 | !available_free_memory(sbi, INO_ENTRIES) || |
313 | jiffies > sbi->cp_expires) | 296 | (is_idle(sbi) && f2fs_time_over(sbi, CP_TIME))) { |
297 | if (test_opt(sbi, DATA_FLUSH)) | ||
298 | sync_dirty_inodes(sbi, FILE_INODE); | ||
314 | f2fs_sync_fs(sbi->sb, true); | 299 | f2fs_sync_fs(sbi->sb, true); |
300 | stat_inc_bg_cp_count(sbi->stat_info); | ||
301 | } | ||
315 | } | 302 | } |
316 | 303 | ||
317 | static int issue_flush_thread(void *data) | 304 | static int issue_flush_thread(void *data) |
@@ -1134,6 +1121,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) | |||
1134 | __u64 end = start + F2FS_BYTES_TO_BLK(range->len) - 1; | 1121 | __u64 end = start + F2FS_BYTES_TO_BLK(range->len) - 1; |
1135 | unsigned int start_segno, end_segno; | 1122 | unsigned int start_segno, end_segno; |
1136 | struct cp_control cpc; | 1123 | struct cp_control cpc; |
1124 | int err = 0; | ||
1137 | 1125 | ||
1138 | if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize) | 1126 | if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize) |
1139 | return -EINVAL; | 1127 | return -EINVAL; |
@@ -1164,12 +1152,12 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) | |||
1164 | sbi->segs_per_sec) - 1, end_segno); | 1152 | sbi->segs_per_sec) - 1, end_segno); |
1165 | 1153 | ||
1166 | mutex_lock(&sbi->gc_mutex); | 1154 | mutex_lock(&sbi->gc_mutex); |
1167 | write_checkpoint(sbi, &cpc); | 1155 | err = write_checkpoint(sbi, &cpc); |
1168 | mutex_unlock(&sbi->gc_mutex); | 1156 | mutex_unlock(&sbi->gc_mutex); |
1169 | } | 1157 | } |
1170 | out: | 1158 | out: |
1171 | range->len = F2FS_BLK_TO_BYTES(cpc.trimmed); | 1159 | range->len = F2FS_BLK_TO_BYTES(cpc.trimmed); |
1172 | return 0; | 1160 | return err; |
1173 | } | 1161 | } |
1174 | 1162 | ||
1175 | static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type) | 1163 | static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type) |
@@ -1749,13 +1737,13 @@ int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type, | |||
1749 | if (le32_to_cpu(nid_in_journal(sum, i)) == val) | 1737 | if (le32_to_cpu(nid_in_journal(sum, i)) == val) |
1750 | return i; | 1738 | return i; |
1751 | } | 1739 | } |
1752 | if (alloc && nats_in_cursum(sum) < NAT_JOURNAL_ENTRIES) | 1740 | if (alloc && __has_cursum_space(sum, 1, NAT_JOURNAL)) |
1753 | return update_nats_in_cursum(sum, 1); | 1741 | return update_nats_in_cursum(sum, 1); |
1754 | } else if (type == SIT_JOURNAL) { | 1742 | } else if (type == SIT_JOURNAL) { |
1755 | for (i = 0; i < sits_in_cursum(sum); i++) | 1743 | for (i = 0; i < sits_in_cursum(sum); i++) |
1756 | if (le32_to_cpu(segno_in_journal(sum, i)) == val) | 1744 | if (le32_to_cpu(segno_in_journal(sum, i)) == val) |
1757 | return i; | 1745 | return i; |
1758 | if (alloc && sits_in_cursum(sum) < SIT_JOURNAL_ENTRIES) | 1746 | if (alloc && __has_cursum_space(sum, 1, SIT_JOURNAL)) |
1759 | return update_sits_in_cursum(sum, 1); | 1747 | return update_sits_in_cursum(sum, 1); |
1760 | } | 1748 | } |
1761 | return -1; | 1749 | return -1; |