aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs/segment.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/f2fs/segment.c')
-rw-r--r--fs/f2fs/segment.c122
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++;
120aligned:
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; 119pass:
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; 127found:
131 128 return result - size + __reverse_ffs(tmp);
132 tmp = __reverse_ulong((unsigned char *)p);
133found_first:
134 tmp &= (~0UL << (BITS_PER_LONG - size));
135 if (!tmp) /* Are any bits set? */
136 return result + size; /* Nope. */
137found_middle:
138 return result + __reverse_ffs(tmp);
139} 129}
140 130
141static unsigned long __find_rev_next_zero_bit(const unsigned long *addr, 131static 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++;
167aligned:
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; 156pass:
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; 164found:
178 165 return result - size + __reverse_ffz(tmp);
179 tmp = __reverse_ulong((unsigned char *)p);
180found_first:
181 tmp |= ~(~0UL << (BITS_PER_LONG - size));
182 if (tmp == ~0UL) /* Are any bits zero? */
183 return result + size; /* Nope. */
184found_middle:
185 return result + __reverse_ffz(tmp);
186} 166}
187 167
188void register_inmem_page(struct inode *inode, struct page *page) 168void 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 */
284void f2fs_balance_fs(struct f2fs_sb_info *sbi) 265void 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
317static int issue_flush_thread(void *data) 304static 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 }
1170out: 1158out:
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
1175static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type) 1163static 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;