1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * fs/f2fs/segment.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2012 Samsung Electronics Co., Ltd.
6*4882a593Smuzhiyun * http://www.samsung.com/
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun #include <linux/fs.h>
9*4882a593Smuzhiyun #include <linux/f2fs_fs.h>
10*4882a593Smuzhiyun #include <linux/bio.h>
11*4882a593Smuzhiyun #include <linux/blkdev.h>
12*4882a593Smuzhiyun #include <linux/prefetch.h>
13*4882a593Smuzhiyun #include <linux/kthread.h>
14*4882a593Smuzhiyun #include <linux/swap.h>
15*4882a593Smuzhiyun #include <linux/timer.h>
16*4882a593Smuzhiyun #include <linux/freezer.h>
17*4882a593Smuzhiyun #include <linux/sched/signal.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include "f2fs.h"
20*4882a593Smuzhiyun #include "segment.h"
21*4882a593Smuzhiyun #include "node.h"
22*4882a593Smuzhiyun #include "gc.h"
23*4882a593Smuzhiyun #include <trace/events/f2fs.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #define __reverse_ffz(x) __reverse_ffs(~(x))
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun static struct kmem_cache *discard_entry_slab;
28*4882a593Smuzhiyun static struct kmem_cache *discard_cmd_slab;
29*4882a593Smuzhiyun static struct kmem_cache *sit_entry_set_slab;
30*4882a593Smuzhiyun static struct kmem_cache *inmem_entry_slab;
31*4882a593Smuzhiyun
__reverse_ulong(unsigned char * str)32*4882a593Smuzhiyun static unsigned long __reverse_ulong(unsigned char *str)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun unsigned long tmp = 0;
35*4882a593Smuzhiyun int shift = 24, idx = 0;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #if BITS_PER_LONG == 64
38*4882a593Smuzhiyun shift = 56;
39*4882a593Smuzhiyun #endif
40*4882a593Smuzhiyun while (shift >= 0) {
41*4882a593Smuzhiyun tmp |= (unsigned long)str[idx++] << shift;
42*4882a593Smuzhiyun shift -= BITS_PER_BYTE;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun return tmp;
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /*
48*4882a593Smuzhiyun * __reverse_ffs is copied from include/asm-generic/bitops/__ffs.h since
49*4882a593Smuzhiyun * MSB and LSB are reversed in a byte by f2fs_set_bit.
50*4882a593Smuzhiyun */
__reverse_ffs(unsigned long word)51*4882a593Smuzhiyun static inline unsigned long __reverse_ffs(unsigned long word)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun int num = 0;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun #if BITS_PER_LONG == 64
56*4882a593Smuzhiyun if ((word & 0xffffffff00000000UL) == 0)
57*4882a593Smuzhiyun num += 32;
58*4882a593Smuzhiyun else
59*4882a593Smuzhiyun word >>= 32;
60*4882a593Smuzhiyun #endif
61*4882a593Smuzhiyun if ((word & 0xffff0000) == 0)
62*4882a593Smuzhiyun num += 16;
63*4882a593Smuzhiyun else
64*4882a593Smuzhiyun word >>= 16;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun if ((word & 0xff00) == 0)
67*4882a593Smuzhiyun num += 8;
68*4882a593Smuzhiyun else
69*4882a593Smuzhiyun word >>= 8;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun if ((word & 0xf0) == 0)
72*4882a593Smuzhiyun num += 4;
73*4882a593Smuzhiyun else
74*4882a593Smuzhiyun word >>= 4;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun if ((word & 0xc) == 0)
77*4882a593Smuzhiyun num += 2;
78*4882a593Smuzhiyun else
79*4882a593Smuzhiyun word >>= 2;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun if ((word & 0x2) == 0)
82*4882a593Smuzhiyun num += 1;
83*4882a593Smuzhiyun return num;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun /*
87*4882a593Smuzhiyun * __find_rev_next(_zero)_bit is copied from lib/find_next_bit.c because
88*4882a593Smuzhiyun * f2fs_set_bit makes MSB and LSB reversed in a byte.
89*4882a593Smuzhiyun * @size must be integral times of unsigned long.
90*4882a593Smuzhiyun * Example:
91*4882a593Smuzhiyun * MSB <--> LSB
92*4882a593Smuzhiyun * f2fs_set_bit(0, bitmap) => 1000 0000
93*4882a593Smuzhiyun * f2fs_set_bit(7, bitmap) => 0000 0001
94*4882a593Smuzhiyun */
__find_rev_next_bit(const unsigned long * addr,unsigned long size,unsigned long offset)95*4882a593Smuzhiyun static unsigned long __find_rev_next_bit(const unsigned long *addr,
96*4882a593Smuzhiyun unsigned long size, unsigned long offset)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun const unsigned long *p = addr + BIT_WORD(offset);
99*4882a593Smuzhiyun unsigned long result = size;
100*4882a593Smuzhiyun unsigned long tmp;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun if (offset >= size)
103*4882a593Smuzhiyun return size;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun size -= (offset & ~(BITS_PER_LONG - 1));
106*4882a593Smuzhiyun offset %= BITS_PER_LONG;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun while (1) {
109*4882a593Smuzhiyun if (*p == 0)
110*4882a593Smuzhiyun goto pass;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun tmp = __reverse_ulong((unsigned char *)p);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun tmp &= ~0UL >> offset;
115*4882a593Smuzhiyun if (size < BITS_PER_LONG)
116*4882a593Smuzhiyun tmp &= (~0UL << (BITS_PER_LONG - size));
117*4882a593Smuzhiyun if (tmp)
118*4882a593Smuzhiyun goto found;
119*4882a593Smuzhiyun pass:
120*4882a593Smuzhiyun if (size <= BITS_PER_LONG)
121*4882a593Smuzhiyun break;
122*4882a593Smuzhiyun size -= BITS_PER_LONG;
123*4882a593Smuzhiyun offset = 0;
124*4882a593Smuzhiyun p++;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun return result;
127*4882a593Smuzhiyun found:
128*4882a593Smuzhiyun return result - size + __reverse_ffs(tmp);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
__find_rev_next_zero_bit(const unsigned long * addr,unsigned long size,unsigned long offset)131*4882a593Smuzhiyun static unsigned long __find_rev_next_zero_bit(const unsigned long *addr,
132*4882a593Smuzhiyun unsigned long size, unsigned long offset)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun const unsigned long *p = addr + BIT_WORD(offset);
135*4882a593Smuzhiyun unsigned long result = size;
136*4882a593Smuzhiyun unsigned long tmp;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun if (offset >= size)
139*4882a593Smuzhiyun return size;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun size -= (offset & ~(BITS_PER_LONG - 1));
142*4882a593Smuzhiyun offset %= BITS_PER_LONG;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun while (1) {
145*4882a593Smuzhiyun if (*p == ~0UL)
146*4882a593Smuzhiyun goto pass;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun tmp = __reverse_ulong((unsigned char *)p);
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun if (offset)
151*4882a593Smuzhiyun tmp |= ~0UL << (BITS_PER_LONG - offset);
152*4882a593Smuzhiyun if (size < BITS_PER_LONG)
153*4882a593Smuzhiyun tmp |= ~0UL >> size;
154*4882a593Smuzhiyun if (tmp != ~0UL)
155*4882a593Smuzhiyun goto found;
156*4882a593Smuzhiyun pass:
157*4882a593Smuzhiyun if (size <= BITS_PER_LONG)
158*4882a593Smuzhiyun break;
159*4882a593Smuzhiyun size -= BITS_PER_LONG;
160*4882a593Smuzhiyun offset = 0;
161*4882a593Smuzhiyun p++;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun return result;
164*4882a593Smuzhiyun found:
165*4882a593Smuzhiyun return result - size + __reverse_ffz(tmp);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
f2fs_need_SSR(struct f2fs_sb_info * sbi)168*4882a593Smuzhiyun bool f2fs_need_SSR(struct f2fs_sb_info *sbi)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
171*4882a593Smuzhiyun int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
172*4882a593Smuzhiyun int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA);
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun if (f2fs_lfs_mode(sbi))
175*4882a593Smuzhiyun return false;
176*4882a593Smuzhiyun if (sbi->gc_mode == GC_URGENT_HIGH)
177*4882a593Smuzhiyun return true;
178*4882a593Smuzhiyun if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
179*4882a593Smuzhiyun return true;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun return free_sections(sbi) <= (node_secs + 2 * dent_secs + imeta_secs +
182*4882a593Smuzhiyun SM_I(sbi)->min_ssr_sections + reserved_sections(sbi));
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
f2fs_register_inmem_page(struct inode * inode,struct page * page)185*4882a593Smuzhiyun void f2fs_register_inmem_page(struct inode *inode, struct page *page)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun struct inmem_pages *new;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun set_page_private_atomic(page);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /* add atomic page indices to the list */
194*4882a593Smuzhiyun new->page = page;
195*4882a593Smuzhiyun INIT_LIST_HEAD(&new->list);
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /* increase reference count with clean state */
198*4882a593Smuzhiyun get_page(page);
199*4882a593Smuzhiyun mutex_lock(&F2FS_I(inode)->inmem_lock);
200*4882a593Smuzhiyun list_add_tail(&new->list, &F2FS_I(inode)->inmem_pages);
201*4882a593Smuzhiyun inc_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES);
202*4882a593Smuzhiyun mutex_unlock(&F2FS_I(inode)->inmem_lock);
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun trace_f2fs_register_inmem_page(page, INMEM);
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
__revoke_inmem_pages(struct inode * inode,struct list_head * head,bool drop,bool recover,bool trylock)207*4882a593Smuzhiyun static int __revoke_inmem_pages(struct inode *inode,
208*4882a593Smuzhiyun struct list_head *head, bool drop, bool recover,
209*4882a593Smuzhiyun bool trylock)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
212*4882a593Smuzhiyun struct inmem_pages *cur, *tmp;
213*4882a593Smuzhiyun int err = 0;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun list_for_each_entry_safe(cur, tmp, head, list) {
216*4882a593Smuzhiyun struct page *page = cur->page;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun if (drop)
219*4882a593Smuzhiyun trace_f2fs_commit_inmem_page(page, INMEM_DROP);
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun if (trylock) {
222*4882a593Smuzhiyun /*
223*4882a593Smuzhiyun * to avoid deadlock in between page lock and
224*4882a593Smuzhiyun * inmem_lock.
225*4882a593Smuzhiyun */
226*4882a593Smuzhiyun if (!trylock_page(page))
227*4882a593Smuzhiyun continue;
228*4882a593Smuzhiyun } else {
229*4882a593Smuzhiyun lock_page(page);
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun f2fs_wait_on_page_writeback(page, DATA, true, true);
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun if (recover) {
235*4882a593Smuzhiyun struct dnode_of_data dn;
236*4882a593Smuzhiyun struct node_info ni;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun trace_f2fs_commit_inmem_page(page, INMEM_REVOKE);
239*4882a593Smuzhiyun retry:
240*4882a593Smuzhiyun set_new_dnode(&dn, inode, NULL, NULL, 0);
241*4882a593Smuzhiyun err = f2fs_get_dnode_of_data(&dn, page->index,
242*4882a593Smuzhiyun LOOKUP_NODE);
243*4882a593Smuzhiyun if (err) {
244*4882a593Smuzhiyun if (err == -ENOMEM) {
245*4882a593Smuzhiyun congestion_wait(BLK_RW_ASYNC,
246*4882a593Smuzhiyun DEFAULT_IO_TIMEOUT);
247*4882a593Smuzhiyun cond_resched();
248*4882a593Smuzhiyun goto retry;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun err = -EAGAIN;
251*4882a593Smuzhiyun goto next;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun err = f2fs_get_node_info(sbi, dn.nid, &ni, false);
255*4882a593Smuzhiyun if (err) {
256*4882a593Smuzhiyun f2fs_put_dnode(&dn);
257*4882a593Smuzhiyun return err;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (cur->old_addr == NEW_ADDR) {
261*4882a593Smuzhiyun f2fs_invalidate_blocks(sbi, dn.data_blkaddr);
262*4882a593Smuzhiyun f2fs_update_data_blkaddr(&dn, NEW_ADDR);
263*4882a593Smuzhiyun } else
264*4882a593Smuzhiyun f2fs_replace_block(sbi, &dn, dn.data_blkaddr,
265*4882a593Smuzhiyun cur->old_addr, ni.version, true, true);
266*4882a593Smuzhiyun f2fs_put_dnode(&dn);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun next:
269*4882a593Smuzhiyun /* we don't need to invalidate this in the sccessful status */
270*4882a593Smuzhiyun if (drop || recover) {
271*4882a593Smuzhiyun ClearPageUptodate(page);
272*4882a593Smuzhiyun clear_page_private_gcing(page);
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun detach_page_private(page);
275*4882a593Smuzhiyun set_page_private(page, 0);
276*4882a593Smuzhiyun f2fs_put_page(page, 1);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun list_del(&cur->list);
279*4882a593Smuzhiyun kmem_cache_free(inmem_entry_slab, cur);
280*4882a593Smuzhiyun dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES);
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun return err;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
f2fs_drop_inmem_pages_all(struct f2fs_sb_info * sbi,bool gc_failure)285*4882a593Smuzhiyun void f2fs_drop_inmem_pages_all(struct f2fs_sb_info *sbi, bool gc_failure)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun struct list_head *head = &sbi->inode_list[ATOMIC_FILE];
288*4882a593Smuzhiyun struct inode *inode;
289*4882a593Smuzhiyun struct f2fs_inode_info *fi;
290*4882a593Smuzhiyun unsigned int count = sbi->atomic_files;
291*4882a593Smuzhiyun unsigned int looped = 0;
292*4882a593Smuzhiyun next:
293*4882a593Smuzhiyun spin_lock(&sbi->inode_lock[ATOMIC_FILE]);
294*4882a593Smuzhiyun if (list_empty(head)) {
295*4882a593Smuzhiyun spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
296*4882a593Smuzhiyun return;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun fi = list_first_entry(head, struct f2fs_inode_info, inmem_ilist);
299*4882a593Smuzhiyun inode = igrab(&fi->vfs_inode);
300*4882a593Smuzhiyun if (inode)
301*4882a593Smuzhiyun list_move_tail(&fi->inmem_ilist, head);
302*4882a593Smuzhiyun spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun if (inode) {
305*4882a593Smuzhiyun if (gc_failure) {
306*4882a593Smuzhiyun if (!fi->i_gc_failures[GC_FAILURE_ATOMIC])
307*4882a593Smuzhiyun goto skip;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun set_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST);
310*4882a593Smuzhiyun f2fs_drop_inmem_pages(inode);
311*4882a593Smuzhiyun skip:
312*4882a593Smuzhiyun iput(inode);
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT);
315*4882a593Smuzhiyun cond_resched();
316*4882a593Smuzhiyun if (gc_failure) {
317*4882a593Smuzhiyun if (++looped >= count)
318*4882a593Smuzhiyun return;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun goto next;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
f2fs_drop_inmem_pages(struct inode * inode)323*4882a593Smuzhiyun void f2fs_drop_inmem_pages(struct inode *inode)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
326*4882a593Smuzhiyun struct f2fs_inode_info *fi = F2FS_I(inode);
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun do {
329*4882a593Smuzhiyun mutex_lock(&fi->inmem_lock);
330*4882a593Smuzhiyun if (list_empty(&fi->inmem_pages)) {
331*4882a593Smuzhiyun fi->i_gc_failures[GC_FAILURE_ATOMIC] = 0;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun spin_lock(&sbi->inode_lock[ATOMIC_FILE]);
334*4882a593Smuzhiyun if (!list_empty(&fi->inmem_ilist))
335*4882a593Smuzhiyun list_del_init(&fi->inmem_ilist);
336*4882a593Smuzhiyun if (f2fs_is_atomic_file(inode)) {
337*4882a593Smuzhiyun clear_inode_flag(inode, FI_ATOMIC_FILE);
338*4882a593Smuzhiyun sbi->atomic_files--;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun mutex_unlock(&fi->inmem_lock);
343*4882a593Smuzhiyun break;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun __revoke_inmem_pages(inode, &fi->inmem_pages,
346*4882a593Smuzhiyun true, false, true);
347*4882a593Smuzhiyun mutex_unlock(&fi->inmem_lock);
348*4882a593Smuzhiyun } while (1);
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
f2fs_drop_inmem_page(struct inode * inode,struct page * page)351*4882a593Smuzhiyun void f2fs_drop_inmem_page(struct inode *inode, struct page *page)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun struct f2fs_inode_info *fi = F2FS_I(inode);
354*4882a593Smuzhiyun struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
355*4882a593Smuzhiyun struct list_head *head = &fi->inmem_pages;
356*4882a593Smuzhiyun struct inmem_pages *cur = NULL;
357*4882a593Smuzhiyun struct inmem_pages *tmp;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun f2fs_bug_on(sbi, !page_private_atomic(page));
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun mutex_lock(&fi->inmem_lock);
362*4882a593Smuzhiyun list_for_each_entry(tmp, head, list) {
363*4882a593Smuzhiyun if (tmp->page == page) {
364*4882a593Smuzhiyun cur = tmp;
365*4882a593Smuzhiyun break;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun f2fs_bug_on(sbi, !cur);
370*4882a593Smuzhiyun list_del(&cur->list);
371*4882a593Smuzhiyun mutex_unlock(&fi->inmem_lock);
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun dec_page_count(sbi, F2FS_INMEM_PAGES);
374*4882a593Smuzhiyun kmem_cache_free(inmem_entry_slab, cur);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun ClearPageUptodate(page);
377*4882a593Smuzhiyun clear_page_private_atomic(page);
378*4882a593Smuzhiyun f2fs_put_page(page, 0);
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun detach_page_private(page);
381*4882a593Smuzhiyun set_page_private(page, 0);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun trace_f2fs_commit_inmem_page(page, INMEM_INVALIDATE);
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
__f2fs_commit_inmem_pages(struct inode * inode)386*4882a593Smuzhiyun static int __f2fs_commit_inmem_pages(struct inode *inode)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
389*4882a593Smuzhiyun struct f2fs_inode_info *fi = F2FS_I(inode);
390*4882a593Smuzhiyun struct inmem_pages *cur, *tmp;
391*4882a593Smuzhiyun struct f2fs_io_info fio = {
392*4882a593Smuzhiyun .sbi = sbi,
393*4882a593Smuzhiyun .ino = inode->i_ino,
394*4882a593Smuzhiyun .type = DATA,
395*4882a593Smuzhiyun .op = REQ_OP_WRITE,
396*4882a593Smuzhiyun .op_flags = REQ_SYNC | REQ_PRIO,
397*4882a593Smuzhiyun .io_type = FS_DATA_IO,
398*4882a593Smuzhiyun };
399*4882a593Smuzhiyun struct list_head revoke_list;
400*4882a593Smuzhiyun bool submit_bio = false;
401*4882a593Smuzhiyun int err = 0;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun INIT_LIST_HEAD(&revoke_list);
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun list_for_each_entry_safe(cur, tmp, &fi->inmem_pages, list) {
406*4882a593Smuzhiyun struct page *page = cur->page;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun lock_page(page);
409*4882a593Smuzhiyun if (page->mapping == inode->i_mapping) {
410*4882a593Smuzhiyun trace_f2fs_commit_inmem_page(page, INMEM);
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun f2fs_wait_on_page_writeback(page, DATA, true, true);
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun set_page_dirty(page);
415*4882a593Smuzhiyun if (clear_page_dirty_for_io(page)) {
416*4882a593Smuzhiyun inode_dec_dirty_pages(inode);
417*4882a593Smuzhiyun f2fs_remove_dirty_inode(inode);
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun retry:
420*4882a593Smuzhiyun fio.page = page;
421*4882a593Smuzhiyun fio.old_blkaddr = NULL_ADDR;
422*4882a593Smuzhiyun fio.encrypted_page = NULL;
423*4882a593Smuzhiyun fio.need_lock = LOCK_DONE;
424*4882a593Smuzhiyun err = f2fs_do_write_data_page(&fio);
425*4882a593Smuzhiyun if (err) {
426*4882a593Smuzhiyun if (err == -ENOMEM) {
427*4882a593Smuzhiyun congestion_wait(BLK_RW_ASYNC,
428*4882a593Smuzhiyun DEFAULT_IO_TIMEOUT);
429*4882a593Smuzhiyun cond_resched();
430*4882a593Smuzhiyun goto retry;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun unlock_page(page);
433*4882a593Smuzhiyun break;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun /* record old blkaddr for revoking */
436*4882a593Smuzhiyun cur->old_addr = fio.old_blkaddr;
437*4882a593Smuzhiyun submit_bio = true;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun unlock_page(page);
440*4882a593Smuzhiyun list_move_tail(&cur->list, &revoke_list);
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun if (submit_bio)
444*4882a593Smuzhiyun f2fs_submit_merged_write_cond(sbi, inode, NULL, 0, DATA);
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun if (err) {
447*4882a593Smuzhiyun /*
448*4882a593Smuzhiyun * try to revoke all committed pages, but still we could fail
449*4882a593Smuzhiyun * due to no memory or other reason, if that happened, EAGAIN
450*4882a593Smuzhiyun * will be returned, which means in such case, transaction is
451*4882a593Smuzhiyun * already not integrity, caller should use journal to do the
452*4882a593Smuzhiyun * recovery or rewrite & commit last transaction. For other
453*4882a593Smuzhiyun * error number, revoking was done by filesystem itself.
454*4882a593Smuzhiyun */
455*4882a593Smuzhiyun err = __revoke_inmem_pages(inode, &revoke_list,
456*4882a593Smuzhiyun false, true, false);
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun /* drop all uncommitted pages */
459*4882a593Smuzhiyun __revoke_inmem_pages(inode, &fi->inmem_pages,
460*4882a593Smuzhiyun true, false, false);
461*4882a593Smuzhiyun } else {
462*4882a593Smuzhiyun __revoke_inmem_pages(inode, &revoke_list,
463*4882a593Smuzhiyun false, false, false);
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun return err;
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun
f2fs_commit_inmem_pages(struct inode * inode)469*4882a593Smuzhiyun int f2fs_commit_inmem_pages(struct inode *inode)
470*4882a593Smuzhiyun {
471*4882a593Smuzhiyun struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
472*4882a593Smuzhiyun struct f2fs_inode_info *fi = F2FS_I(inode);
473*4882a593Smuzhiyun int err;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun f2fs_balance_fs(sbi, true);
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun f2fs_down_write(&fi->i_gc_rwsem[WRITE]);
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun f2fs_lock_op(sbi);
480*4882a593Smuzhiyun set_inode_flag(inode, FI_ATOMIC_COMMIT);
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun mutex_lock(&fi->inmem_lock);
483*4882a593Smuzhiyun err = __f2fs_commit_inmem_pages(inode);
484*4882a593Smuzhiyun mutex_unlock(&fi->inmem_lock);
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun clear_inode_flag(inode, FI_ATOMIC_COMMIT);
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun f2fs_unlock_op(sbi);
489*4882a593Smuzhiyun f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun return err;
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun /*
495*4882a593Smuzhiyun * This function balances dirty node and dentry pages.
496*4882a593Smuzhiyun * In addition, it controls garbage collection.
497*4882a593Smuzhiyun */
f2fs_balance_fs(struct f2fs_sb_info * sbi,bool need)498*4882a593Smuzhiyun void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun if (time_to_inject(sbi, FAULT_CHECKPOINT)) {
501*4882a593Smuzhiyun f2fs_show_injection_info(sbi, FAULT_CHECKPOINT);
502*4882a593Smuzhiyun f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_FAULT_INJECT);
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun /* balance_fs_bg is able to be pending */
506*4882a593Smuzhiyun if (need && excess_cached_nats(sbi))
507*4882a593Smuzhiyun f2fs_balance_fs_bg(sbi, false);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun if (!f2fs_is_checkpoint_ready(sbi))
510*4882a593Smuzhiyun return;
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun /*
513*4882a593Smuzhiyun * We should do GC or end up with checkpoint, if there are so many dirty
514*4882a593Smuzhiyun * dir/node pages without enough free segments.
515*4882a593Smuzhiyun */
516*4882a593Smuzhiyun if (has_not_enough_free_secs(sbi, 0, 0)) {
517*4882a593Smuzhiyun if (test_opt(sbi, GC_MERGE) && sbi->gc_thread &&
518*4882a593Smuzhiyun sbi->gc_thread->f2fs_gc_task) {
519*4882a593Smuzhiyun DEFINE_WAIT(wait);
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun prepare_to_wait(&sbi->gc_thread->fggc_wq, &wait,
522*4882a593Smuzhiyun TASK_UNINTERRUPTIBLE);
523*4882a593Smuzhiyun wake_up(&sbi->gc_thread->gc_wait_queue_head);
524*4882a593Smuzhiyun io_schedule();
525*4882a593Smuzhiyun finish_wait(&sbi->gc_thread->fggc_wq, &wait);
526*4882a593Smuzhiyun } else {
527*4882a593Smuzhiyun f2fs_down_write(&sbi->gc_lock);
528*4882a593Smuzhiyun f2fs_gc(sbi, false, false, false, NULL_SEGNO);
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun
f2fs_balance_fs_bg(struct f2fs_sb_info * sbi,bool from_bg)533*4882a593Smuzhiyun void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
536*4882a593Smuzhiyun return;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun /* try to shrink extent cache when there is no enough memory */
539*4882a593Smuzhiyun if (!f2fs_available_free_memory(sbi, READ_EXTENT_CACHE))
540*4882a593Smuzhiyun f2fs_shrink_read_extent_tree(sbi,
541*4882a593Smuzhiyun READ_EXTENT_CACHE_SHRINK_NUMBER);
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun /* try to shrink age extent cache when there is no enough memory */
544*4882a593Smuzhiyun if (!f2fs_available_free_memory(sbi, AGE_EXTENT_CACHE))
545*4882a593Smuzhiyun f2fs_shrink_age_extent_tree(sbi,
546*4882a593Smuzhiyun AGE_EXTENT_CACHE_SHRINK_NUMBER);
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun /* check the # of cached NAT entries */
549*4882a593Smuzhiyun if (!f2fs_available_free_memory(sbi, NAT_ENTRIES))
550*4882a593Smuzhiyun f2fs_try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK);
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun if (!f2fs_available_free_memory(sbi, FREE_NIDS))
553*4882a593Smuzhiyun f2fs_try_to_free_nids(sbi, MAX_FREE_NIDS);
554*4882a593Smuzhiyun else
555*4882a593Smuzhiyun f2fs_build_free_nids(sbi, false, false);
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun if (excess_dirty_nats(sbi) || excess_dirty_nodes(sbi) ||
558*4882a593Smuzhiyun excess_prefree_segs(sbi))
559*4882a593Smuzhiyun goto do_sync;
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun /* there is background inflight IO or foreground operation recently */
562*4882a593Smuzhiyun if (is_inflight_io(sbi, REQ_TIME) ||
563*4882a593Smuzhiyun (!f2fs_time_over(sbi, REQ_TIME) && f2fs_rwsem_is_locked(&sbi->cp_rwsem)))
564*4882a593Smuzhiyun return;
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun /* exceed periodical checkpoint timeout threshold */
567*4882a593Smuzhiyun if (f2fs_time_over(sbi, CP_TIME))
568*4882a593Smuzhiyun goto do_sync;
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun /* checkpoint is the only way to shrink partial cached entries */
571*4882a593Smuzhiyun if (f2fs_available_free_memory(sbi, NAT_ENTRIES) ||
572*4882a593Smuzhiyun f2fs_available_free_memory(sbi, INO_ENTRIES))
573*4882a593Smuzhiyun return;
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun do_sync:
576*4882a593Smuzhiyun if (test_opt(sbi, DATA_FLUSH) && from_bg) {
577*4882a593Smuzhiyun struct blk_plug plug;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun mutex_lock(&sbi->flush_lock);
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun blk_start_plug(&plug);
582*4882a593Smuzhiyun f2fs_sync_dirty_inodes(sbi, FILE_INODE, NULL);
583*4882a593Smuzhiyun blk_finish_plug(&plug);
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun mutex_unlock(&sbi->flush_lock);
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun f2fs_sync_fs(sbi->sb, true);
588*4882a593Smuzhiyun stat_inc_bg_cp_count(sbi->stat_info);
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun
__submit_flush_wait(struct f2fs_sb_info * sbi,struct block_device * bdev)591*4882a593Smuzhiyun static int __submit_flush_wait(struct f2fs_sb_info *sbi,
592*4882a593Smuzhiyun struct block_device *bdev)
593*4882a593Smuzhiyun {
594*4882a593Smuzhiyun int ret = blkdev_issue_flush(bdev, GFP_NOFS);
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun trace_f2fs_issue_flush(bdev, test_opt(sbi, NOBARRIER),
597*4882a593Smuzhiyun test_opt(sbi, FLUSH_MERGE), ret);
598*4882a593Smuzhiyun return ret;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
submit_flush_wait(struct f2fs_sb_info * sbi,nid_t ino)601*4882a593Smuzhiyun static int submit_flush_wait(struct f2fs_sb_info *sbi, nid_t ino)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun int ret = 0;
604*4882a593Smuzhiyun int i;
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun if (!f2fs_is_multi_device(sbi))
607*4882a593Smuzhiyun return __submit_flush_wait(sbi, sbi->sb->s_bdev);
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun for (i = 0; i < sbi->s_ndevs; i++) {
610*4882a593Smuzhiyun if (!f2fs_is_dirty_device(sbi, ino, i, FLUSH_INO))
611*4882a593Smuzhiyun continue;
612*4882a593Smuzhiyun ret = __submit_flush_wait(sbi, FDEV(i).bdev);
613*4882a593Smuzhiyun if (ret)
614*4882a593Smuzhiyun break;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun return ret;
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun
issue_flush_thread(void * data)619*4882a593Smuzhiyun static int issue_flush_thread(void *data)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun struct f2fs_sb_info *sbi = data;
622*4882a593Smuzhiyun struct flush_cmd_control *fcc = SM_I(sbi)->fcc_info;
623*4882a593Smuzhiyun wait_queue_head_t *q = &fcc->flush_wait_queue;
624*4882a593Smuzhiyun repeat:
625*4882a593Smuzhiyun if (kthread_should_stop())
626*4882a593Smuzhiyun return 0;
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun if (!llist_empty(&fcc->issue_list)) {
629*4882a593Smuzhiyun struct flush_cmd *cmd, *next;
630*4882a593Smuzhiyun int ret;
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun fcc->dispatch_list = llist_del_all(&fcc->issue_list);
633*4882a593Smuzhiyun fcc->dispatch_list = llist_reverse_order(fcc->dispatch_list);
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun cmd = llist_entry(fcc->dispatch_list, struct flush_cmd, llnode);
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun ret = submit_flush_wait(sbi, cmd->ino);
638*4882a593Smuzhiyun atomic_inc(&fcc->issued_flush);
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun llist_for_each_entry_safe(cmd, next,
641*4882a593Smuzhiyun fcc->dispatch_list, llnode) {
642*4882a593Smuzhiyun cmd->ret = ret;
643*4882a593Smuzhiyun complete(&cmd->wait);
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun fcc->dispatch_list = NULL;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun wait_event_interruptible(*q,
649*4882a593Smuzhiyun kthread_should_stop() || !llist_empty(&fcc->issue_list));
650*4882a593Smuzhiyun goto repeat;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun
f2fs_issue_flush(struct f2fs_sb_info * sbi,nid_t ino)653*4882a593Smuzhiyun int f2fs_issue_flush(struct f2fs_sb_info *sbi, nid_t ino)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun struct flush_cmd_control *fcc = SM_I(sbi)->fcc_info;
656*4882a593Smuzhiyun struct flush_cmd cmd;
657*4882a593Smuzhiyun int ret;
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun if (test_opt(sbi, NOBARRIER))
660*4882a593Smuzhiyun return 0;
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun if (!test_opt(sbi, FLUSH_MERGE)) {
663*4882a593Smuzhiyun atomic_inc(&fcc->queued_flush);
664*4882a593Smuzhiyun ret = submit_flush_wait(sbi, ino);
665*4882a593Smuzhiyun atomic_dec(&fcc->queued_flush);
666*4882a593Smuzhiyun atomic_inc(&fcc->issued_flush);
667*4882a593Smuzhiyun return ret;
668*4882a593Smuzhiyun }
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun if (atomic_inc_return(&fcc->queued_flush) == 1 ||
671*4882a593Smuzhiyun f2fs_is_multi_device(sbi)) {
672*4882a593Smuzhiyun ret = submit_flush_wait(sbi, ino);
673*4882a593Smuzhiyun atomic_dec(&fcc->queued_flush);
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun atomic_inc(&fcc->issued_flush);
676*4882a593Smuzhiyun return ret;
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun cmd.ino = ino;
680*4882a593Smuzhiyun init_completion(&cmd.wait);
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun llist_add(&cmd.llnode, &fcc->issue_list);
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun /*
685*4882a593Smuzhiyun * update issue_list before we wake up issue_flush thread, this
686*4882a593Smuzhiyun * smp_mb() pairs with another barrier in ___wait_event(), see
687*4882a593Smuzhiyun * more details in comments of waitqueue_active().
688*4882a593Smuzhiyun */
689*4882a593Smuzhiyun smp_mb();
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun if (waitqueue_active(&fcc->flush_wait_queue))
692*4882a593Smuzhiyun wake_up(&fcc->flush_wait_queue);
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun if (fcc->f2fs_issue_flush) {
695*4882a593Smuzhiyun wait_for_completion(&cmd.wait);
696*4882a593Smuzhiyun atomic_dec(&fcc->queued_flush);
697*4882a593Smuzhiyun } else {
698*4882a593Smuzhiyun struct llist_node *list;
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun list = llist_del_all(&fcc->issue_list);
701*4882a593Smuzhiyun if (!list) {
702*4882a593Smuzhiyun wait_for_completion(&cmd.wait);
703*4882a593Smuzhiyun atomic_dec(&fcc->queued_flush);
704*4882a593Smuzhiyun } else {
705*4882a593Smuzhiyun struct flush_cmd *tmp, *next;
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun ret = submit_flush_wait(sbi, ino);
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun llist_for_each_entry_safe(tmp, next, list, llnode) {
710*4882a593Smuzhiyun if (tmp == &cmd) {
711*4882a593Smuzhiyun cmd.ret = ret;
712*4882a593Smuzhiyun atomic_dec(&fcc->queued_flush);
713*4882a593Smuzhiyun continue;
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun tmp->ret = ret;
716*4882a593Smuzhiyun complete(&tmp->wait);
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun return cmd.ret;
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun
f2fs_create_flush_cmd_control(struct f2fs_sb_info * sbi)724*4882a593Smuzhiyun int f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi)
725*4882a593Smuzhiyun {
726*4882a593Smuzhiyun dev_t dev = sbi->sb->s_bdev->bd_dev;
727*4882a593Smuzhiyun struct flush_cmd_control *fcc;
728*4882a593Smuzhiyun int err = 0;
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun if (SM_I(sbi)->fcc_info) {
731*4882a593Smuzhiyun fcc = SM_I(sbi)->fcc_info;
732*4882a593Smuzhiyun if (fcc->f2fs_issue_flush)
733*4882a593Smuzhiyun return err;
734*4882a593Smuzhiyun goto init_thread;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun fcc = f2fs_kzalloc(sbi, sizeof(struct flush_cmd_control), GFP_KERNEL);
738*4882a593Smuzhiyun if (!fcc)
739*4882a593Smuzhiyun return -ENOMEM;
740*4882a593Smuzhiyun atomic_set(&fcc->issued_flush, 0);
741*4882a593Smuzhiyun atomic_set(&fcc->queued_flush, 0);
742*4882a593Smuzhiyun init_waitqueue_head(&fcc->flush_wait_queue);
743*4882a593Smuzhiyun init_llist_head(&fcc->issue_list);
744*4882a593Smuzhiyun SM_I(sbi)->fcc_info = fcc;
745*4882a593Smuzhiyun if (!test_opt(sbi, FLUSH_MERGE))
746*4882a593Smuzhiyun return err;
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun init_thread:
749*4882a593Smuzhiyun fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
750*4882a593Smuzhiyun "f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));
751*4882a593Smuzhiyun if (IS_ERR(fcc->f2fs_issue_flush)) {
752*4882a593Smuzhiyun err = PTR_ERR(fcc->f2fs_issue_flush);
753*4882a593Smuzhiyun kfree(fcc);
754*4882a593Smuzhiyun SM_I(sbi)->fcc_info = NULL;
755*4882a593Smuzhiyun return err;
756*4882a593Smuzhiyun }
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun return err;
759*4882a593Smuzhiyun }
760*4882a593Smuzhiyun
f2fs_destroy_flush_cmd_control(struct f2fs_sb_info * sbi,bool free)761*4882a593Smuzhiyun void f2fs_destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free)
762*4882a593Smuzhiyun {
763*4882a593Smuzhiyun struct flush_cmd_control *fcc = SM_I(sbi)->fcc_info;
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun if (fcc && fcc->f2fs_issue_flush) {
766*4882a593Smuzhiyun struct task_struct *flush_thread = fcc->f2fs_issue_flush;
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun fcc->f2fs_issue_flush = NULL;
769*4882a593Smuzhiyun kthread_stop(flush_thread);
770*4882a593Smuzhiyun }
771*4882a593Smuzhiyun if (free) {
772*4882a593Smuzhiyun kfree(fcc);
773*4882a593Smuzhiyun SM_I(sbi)->fcc_info = NULL;
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun
f2fs_flush_device_cache(struct f2fs_sb_info * sbi)777*4882a593Smuzhiyun int f2fs_flush_device_cache(struct f2fs_sb_info *sbi)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun int ret = 0, i;
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun if (!f2fs_is_multi_device(sbi))
782*4882a593Smuzhiyun return 0;
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun if (test_opt(sbi, NOBARRIER))
785*4882a593Smuzhiyun return 0;
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun for (i = 1; i < sbi->s_ndevs; i++) {
788*4882a593Smuzhiyun if (!f2fs_test_bit(i, (char *)&sbi->dirty_device))
789*4882a593Smuzhiyun continue;
790*4882a593Smuzhiyun ret = __submit_flush_wait(sbi, FDEV(i).bdev);
791*4882a593Smuzhiyun if (ret) {
792*4882a593Smuzhiyun f2fs_stop_checkpoint(sbi, false,
793*4882a593Smuzhiyun STOP_CP_REASON_FLUSH_FAIL);
794*4882a593Smuzhiyun break;
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun spin_lock(&sbi->dev_lock);
798*4882a593Smuzhiyun f2fs_clear_bit(i, (char *)&sbi->dirty_device);
799*4882a593Smuzhiyun spin_unlock(&sbi->dev_lock);
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun return ret;
803*4882a593Smuzhiyun }
804*4882a593Smuzhiyun
__locate_dirty_segment(struct f2fs_sb_info * sbi,unsigned int segno,enum dirty_type dirty_type)805*4882a593Smuzhiyun static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
806*4882a593Smuzhiyun enum dirty_type dirty_type)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun /* need not be added */
811*4882a593Smuzhiyun if (IS_CURSEG(sbi, segno))
812*4882a593Smuzhiyun return;
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type]))
815*4882a593Smuzhiyun dirty_i->nr_dirty[dirty_type]++;
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun if (dirty_type == DIRTY) {
818*4882a593Smuzhiyun struct seg_entry *sentry = get_seg_entry(sbi, segno);
819*4882a593Smuzhiyun enum dirty_type t = sentry->type;
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun if (unlikely(t >= DIRTY)) {
822*4882a593Smuzhiyun f2fs_bug_on(sbi, 1);
823*4882a593Smuzhiyun return;
824*4882a593Smuzhiyun }
825*4882a593Smuzhiyun if (!test_and_set_bit(segno, dirty_i->dirty_segmap[t]))
826*4882a593Smuzhiyun dirty_i->nr_dirty[t]++;
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun if (__is_large_section(sbi)) {
829*4882a593Smuzhiyun unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
830*4882a593Smuzhiyun block_t valid_blocks =
831*4882a593Smuzhiyun get_valid_blocks(sbi, segno, true);
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun f2fs_bug_on(sbi, unlikely(!valid_blocks ||
834*4882a593Smuzhiyun valid_blocks == BLKS_PER_SEC(sbi)));
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun if (!IS_CURSEC(sbi, secno))
837*4882a593Smuzhiyun set_bit(secno, dirty_i->dirty_secmap);
838*4882a593Smuzhiyun }
839*4882a593Smuzhiyun }
840*4882a593Smuzhiyun }
841*4882a593Smuzhiyun
__remove_dirty_segment(struct f2fs_sb_info * sbi,unsigned int segno,enum dirty_type dirty_type)842*4882a593Smuzhiyun static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
843*4882a593Smuzhiyun enum dirty_type dirty_type)
844*4882a593Smuzhiyun {
845*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
846*4882a593Smuzhiyun block_t valid_blocks;
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun if (test_and_clear_bit(segno, dirty_i->dirty_segmap[dirty_type]))
849*4882a593Smuzhiyun dirty_i->nr_dirty[dirty_type]--;
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun if (dirty_type == DIRTY) {
852*4882a593Smuzhiyun struct seg_entry *sentry = get_seg_entry(sbi, segno);
853*4882a593Smuzhiyun enum dirty_type t = sentry->type;
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
856*4882a593Smuzhiyun dirty_i->nr_dirty[t]--;
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun valid_blocks = get_valid_blocks(sbi, segno, true);
859*4882a593Smuzhiyun if (valid_blocks == 0) {
860*4882a593Smuzhiyun clear_bit(GET_SEC_FROM_SEG(sbi, segno),
861*4882a593Smuzhiyun dirty_i->victim_secmap);
862*4882a593Smuzhiyun #ifdef CONFIG_F2FS_CHECK_FS
863*4882a593Smuzhiyun clear_bit(segno, SIT_I(sbi)->invalid_segmap);
864*4882a593Smuzhiyun #endif
865*4882a593Smuzhiyun }
866*4882a593Smuzhiyun if (__is_large_section(sbi)) {
867*4882a593Smuzhiyun unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun if (!valid_blocks ||
870*4882a593Smuzhiyun valid_blocks == BLKS_PER_SEC(sbi)) {
871*4882a593Smuzhiyun clear_bit(secno, dirty_i->dirty_secmap);
872*4882a593Smuzhiyun return;
873*4882a593Smuzhiyun }
874*4882a593Smuzhiyun
875*4882a593Smuzhiyun if (!IS_CURSEC(sbi, secno))
876*4882a593Smuzhiyun set_bit(secno, dirty_i->dirty_secmap);
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun
881*4882a593Smuzhiyun /*
882*4882a593Smuzhiyun * Should not occur error such as -ENOMEM.
883*4882a593Smuzhiyun * Adding dirty entry into seglist is not critical operation.
884*4882a593Smuzhiyun * If a given segment is one of current working segments, it won't be added.
885*4882a593Smuzhiyun */
locate_dirty_segment(struct f2fs_sb_info * sbi,unsigned int segno)886*4882a593Smuzhiyun static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)
887*4882a593Smuzhiyun {
888*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
889*4882a593Smuzhiyun unsigned short valid_blocks, ckpt_valid_blocks;
890*4882a593Smuzhiyun unsigned int usable_blocks;
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun if (segno == NULL_SEGNO || IS_CURSEG(sbi, segno))
893*4882a593Smuzhiyun return;
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun usable_blocks = f2fs_usable_blks_in_seg(sbi, segno);
896*4882a593Smuzhiyun mutex_lock(&dirty_i->seglist_lock);
897*4882a593Smuzhiyun
898*4882a593Smuzhiyun valid_blocks = get_valid_blocks(sbi, segno, false);
899*4882a593Smuzhiyun ckpt_valid_blocks = get_ckpt_valid_blocks(sbi, segno, false);
900*4882a593Smuzhiyun
901*4882a593Smuzhiyun if (valid_blocks == 0 && (!is_sbi_flag_set(sbi, SBI_CP_DISABLED) ||
902*4882a593Smuzhiyun ckpt_valid_blocks == usable_blocks)) {
903*4882a593Smuzhiyun __locate_dirty_segment(sbi, segno, PRE);
904*4882a593Smuzhiyun __remove_dirty_segment(sbi, segno, DIRTY);
905*4882a593Smuzhiyun } else if (valid_blocks < usable_blocks) {
906*4882a593Smuzhiyun __locate_dirty_segment(sbi, segno, DIRTY);
907*4882a593Smuzhiyun } else {
908*4882a593Smuzhiyun /* Recovery routine with SSR needs this */
909*4882a593Smuzhiyun __remove_dirty_segment(sbi, segno, DIRTY);
910*4882a593Smuzhiyun }
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun mutex_unlock(&dirty_i->seglist_lock);
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun /* This moves currently empty dirty blocks to prefree. Must hold seglist_lock */
f2fs_dirty_to_prefree(struct f2fs_sb_info * sbi)916*4882a593Smuzhiyun void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi)
917*4882a593Smuzhiyun {
918*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
919*4882a593Smuzhiyun unsigned int segno;
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun mutex_lock(&dirty_i->seglist_lock);
922*4882a593Smuzhiyun for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) {
923*4882a593Smuzhiyun if (get_valid_blocks(sbi, segno, false))
924*4882a593Smuzhiyun continue;
925*4882a593Smuzhiyun if (IS_CURSEG(sbi, segno))
926*4882a593Smuzhiyun continue;
927*4882a593Smuzhiyun __locate_dirty_segment(sbi, segno, PRE);
928*4882a593Smuzhiyun __remove_dirty_segment(sbi, segno, DIRTY);
929*4882a593Smuzhiyun }
930*4882a593Smuzhiyun mutex_unlock(&dirty_i->seglist_lock);
931*4882a593Smuzhiyun }
932*4882a593Smuzhiyun
f2fs_get_unusable_blocks(struct f2fs_sb_info * sbi)933*4882a593Smuzhiyun block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi)
934*4882a593Smuzhiyun {
935*4882a593Smuzhiyun int ovp_hole_segs =
936*4882a593Smuzhiyun (overprovision_segments(sbi) - reserved_segments(sbi));
937*4882a593Smuzhiyun block_t ovp_holes = ovp_hole_segs << sbi->log_blocks_per_seg;
938*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
939*4882a593Smuzhiyun block_t holes[2] = {0, 0}; /* DATA and NODE */
940*4882a593Smuzhiyun block_t unusable;
941*4882a593Smuzhiyun struct seg_entry *se;
942*4882a593Smuzhiyun unsigned int segno;
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun mutex_lock(&dirty_i->seglist_lock);
945*4882a593Smuzhiyun for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) {
946*4882a593Smuzhiyun se = get_seg_entry(sbi, segno);
947*4882a593Smuzhiyun if (IS_NODESEG(se->type))
948*4882a593Smuzhiyun holes[NODE] += f2fs_usable_blks_in_seg(sbi, segno) -
949*4882a593Smuzhiyun se->valid_blocks;
950*4882a593Smuzhiyun else
951*4882a593Smuzhiyun holes[DATA] += f2fs_usable_blks_in_seg(sbi, segno) -
952*4882a593Smuzhiyun se->valid_blocks;
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun mutex_unlock(&dirty_i->seglist_lock);
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun unusable = holes[DATA] > holes[NODE] ? holes[DATA] : holes[NODE];
957*4882a593Smuzhiyun if (unusable > ovp_holes)
958*4882a593Smuzhiyun return unusable - ovp_holes;
959*4882a593Smuzhiyun return 0;
960*4882a593Smuzhiyun }
961*4882a593Smuzhiyun
f2fs_disable_cp_again(struct f2fs_sb_info * sbi,block_t unusable)962*4882a593Smuzhiyun int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable)
963*4882a593Smuzhiyun {
964*4882a593Smuzhiyun int ovp_hole_segs =
965*4882a593Smuzhiyun (overprovision_segments(sbi) - reserved_segments(sbi));
966*4882a593Smuzhiyun if (unusable > F2FS_OPTION(sbi).unusable_cap)
967*4882a593Smuzhiyun return -EAGAIN;
968*4882a593Smuzhiyun if (is_sbi_flag_set(sbi, SBI_CP_DISABLED_QUICK) &&
969*4882a593Smuzhiyun dirty_segments(sbi) > ovp_hole_segs)
970*4882a593Smuzhiyun return -EAGAIN;
971*4882a593Smuzhiyun return 0;
972*4882a593Smuzhiyun }
973*4882a593Smuzhiyun
974*4882a593Smuzhiyun /* This is only used by SBI_CP_DISABLED */
get_free_segment(struct f2fs_sb_info * sbi)975*4882a593Smuzhiyun static unsigned int get_free_segment(struct f2fs_sb_info *sbi)
976*4882a593Smuzhiyun {
977*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
978*4882a593Smuzhiyun unsigned int segno = 0;
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun mutex_lock(&dirty_i->seglist_lock);
981*4882a593Smuzhiyun for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) {
982*4882a593Smuzhiyun if (get_valid_blocks(sbi, segno, false))
983*4882a593Smuzhiyun continue;
984*4882a593Smuzhiyun if (get_ckpt_valid_blocks(sbi, segno, false))
985*4882a593Smuzhiyun continue;
986*4882a593Smuzhiyun mutex_unlock(&dirty_i->seglist_lock);
987*4882a593Smuzhiyun return segno;
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun mutex_unlock(&dirty_i->seglist_lock);
990*4882a593Smuzhiyun return NULL_SEGNO;
991*4882a593Smuzhiyun }
992*4882a593Smuzhiyun
__create_discard_cmd(struct f2fs_sb_info * sbi,struct block_device * bdev,block_t lstart,block_t start,block_t len)993*4882a593Smuzhiyun static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi,
994*4882a593Smuzhiyun struct block_device *bdev, block_t lstart,
995*4882a593Smuzhiyun block_t start, block_t len)
996*4882a593Smuzhiyun {
997*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
998*4882a593Smuzhiyun struct list_head *pend_list;
999*4882a593Smuzhiyun struct discard_cmd *dc;
1000*4882a593Smuzhiyun
1001*4882a593Smuzhiyun f2fs_bug_on(sbi, !len);
1002*4882a593Smuzhiyun
1003*4882a593Smuzhiyun pend_list = &dcc->pend_list[plist_idx(len)];
1004*4882a593Smuzhiyun
1005*4882a593Smuzhiyun dc = f2fs_kmem_cache_alloc(discard_cmd_slab, GFP_NOFS);
1006*4882a593Smuzhiyun INIT_LIST_HEAD(&dc->list);
1007*4882a593Smuzhiyun dc->bdev = bdev;
1008*4882a593Smuzhiyun dc->lstart = lstart;
1009*4882a593Smuzhiyun dc->start = start;
1010*4882a593Smuzhiyun dc->len = len;
1011*4882a593Smuzhiyun dc->ref = 0;
1012*4882a593Smuzhiyun dc->state = D_PREP;
1013*4882a593Smuzhiyun dc->queued = 0;
1014*4882a593Smuzhiyun dc->error = 0;
1015*4882a593Smuzhiyun init_completion(&dc->wait);
1016*4882a593Smuzhiyun list_add_tail(&dc->list, pend_list);
1017*4882a593Smuzhiyun spin_lock_init(&dc->lock);
1018*4882a593Smuzhiyun dc->bio_ref = 0;
1019*4882a593Smuzhiyun atomic_inc(&dcc->discard_cmd_cnt);
1020*4882a593Smuzhiyun dcc->undiscard_blks += len;
1021*4882a593Smuzhiyun
1022*4882a593Smuzhiyun return dc;
1023*4882a593Smuzhiyun }
1024*4882a593Smuzhiyun
__attach_discard_cmd(struct f2fs_sb_info * sbi,struct block_device * bdev,block_t lstart,block_t start,block_t len,struct rb_node * parent,struct rb_node ** p,bool leftmost)1025*4882a593Smuzhiyun static struct discard_cmd *__attach_discard_cmd(struct f2fs_sb_info *sbi,
1026*4882a593Smuzhiyun struct block_device *bdev, block_t lstart,
1027*4882a593Smuzhiyun block_t start, block_t len,
1028*4882a593Smuzhiyun struct rb_node *parent, struct rb_node **p,
1029*4882a593Smuzhiyun bool leftmost)
1030*4882a593Smuzhiyun {
1031*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1032*4882a593Smuzhiyun struct discard_cmd *dc;
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun dc = __create_discard_cmd(sbi, bdev, lstart, start, len);
1035*4882a593Smuzhiyun
1036*4882a593Smuzhiyun rb_link_node(&dc->rb_node, parent, p);
1037*4882a593Smuzhiyun rb_insert_color_cached(&dc->rb_node, &dcc->root, leftmost);
1038*4882a593Smuzhiyun
1039*4882a593Smuzhiyun return dc;
1040*4882a593Smuzhiyun }
1041*4882a593Smuzhiyun
__detach_discard_cmd(struct discard_cmd_control * dcc,struct discard_cmd * dc)1042*4882a593Smuzhiyun static void __detach_discard_cmd(struct discard_cmd_control *dcc,
1043*4882a593Smuzhiyun struct discard_cmd *dc)
1044*4882a593Smuzhiyun {
1045*4882a593Smuzhiyun if (dc->state == D_DONE)
1046*4882a593Smuzhiyun atomic_sub(dc->queued, &dcc->queued_discard);
1047*4882a593Smuzhiyun
1048*4882a593Smuzhiyun list_del(&dc->list);
1049*4882a593Smuzhiyun rb_erase_cached(&dc->rb_node, &dcc->root);
1050*4882a593Smuzhiyun dcc->undiscard_blks -= dc->len;
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun kmem_cache_free(discard_cmd_slab, dc);
1053*4882a593Smuzhiyun
1054*4882a593Smuzhiyun atomic_dec(&dcc->discard_cmd_cnt);
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun
__remove_discard_cmd(struct f2fs_sb_info * sbi,struct discard_cmd * dc)1057*4882a593Smuzhiyun static void __remove_discard_cmd(struct f2fs_sb_info *sbi,
1058*4882a593Smuzhiyun struct discard_cmd *dc)
1059*4882a593Smuzhiyun {
1060*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1061*4882a593Smuzhiyun unsigned long flags;
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun trace_f2fs_remove_discard(dc->bdev, dc->start, dc->len);
1064*4882a593Smuzhiyun
1065*4882a593Smuzhiyun spin_lock_irqsave(&dc->lock, flags);
1066*4882a593Smuzhiyun if (dc->bio_ref) {
1067*4882a593Smuzhiyun spin_unlock_irqrestore(&dc->lock, flags);
1068*4882a593Smuzhiyun return;
1069*4882a593Smuzhiyun }
1070*4882a593Smuzhiyun spin_unlock_irqrestore(&dc->lock, flags);
1071*4882a593Smuzhiyun
1072*4882a593Smuzhiyun f2fs_bug_on(sbi, dc->ref);
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun if (dc->error == -EOPNOTSUPP)
1075*4882a593Smuzhiyun dc->error = 0;
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun if (dc->error)
1078*4882a593Smuzhiyun printk_ratelimited(
1079*4882a593Smuzhiyun "%sF2FS-fs (%s): Issue discard(%u, %u, %u) failed, ret: %d",
1080*4882a593Smuzhiyun KERN_INFO, sbi->sb->s_id,
1081*4882a593Smuzhiyun dc->lstart, dc->start, dc->len, dc->error);
1082*4882a593Smuzhiyun __detach_discard_cmd(dcc, dc);
1083*4882a593Smuzhiyun }
1084*4882a593Smuzhiyun
f2fs_submit_discard_endio(struct bio * bio)1085*4882a593Smuzhiyun static void f2fs_submit_discard_endio(struct bio *bio)
1086*4882a593Smuzhiyun {
1087*4882a593Smuzhiyun struct discard_cmd *dc = (struct discard_cmd *)bio->bi_private;
1088*4882a593Smuzhiyun unsigned long flags;
1089*4882a593Smuzhiyun
1090*4882a593Smuzhiyun spin_lock_irqsave(&dc->lock, flags);
1091*4882a593Smuzhiyun if (!dc->error)
1092*4882a593Smuzhiyun dc->error = blk_status_to_errno(bio->bi_status);
1093*4882a593Smuzhiyun dc->bio_ref--;
1094*4882a593Smuzhiyun if (!dc->bio_ref && dc->state == D_SUBMIT) {
1095*4882a593Smuzhiyun dc->state = D_DONE;
1096*4882a593Smuzhiyun complete_all(&dc->wait);
1097*4882a593Smuzhiyun }
1098*4882a593Smuzhiyun spin_unlock_irqrestore(&dc->lock, flags);
1099*4882a593Smuzhiyun bio_put(bio);
1100*4882a593Smuzhiyun }
1101*4882a593Smuzhiyun
__check_sit_bitmap(struct f2fs_sb_info * sbi,block_t start,block_t end)1102*4882a593Smuzhiyun static void __check_sit_bitmap(struct f2fs_sb_info *sbi,
1103*4882a593Smuzhiyun block_t start, block_t end)
1104*4882a593Smuzhiyun {
1105*4882a593Smuzhiyun #ifdef CONFIG_F2FS_CHECK_FS
1106*4882a593Smuzhiyun struct seg_entry *sentry;
1107*4882a593Smuzhiyun unsigned int segno;
1108*4882a593Smuzhiyun block_t blk = start;
1109*4882a593Smuzhiyun unsigned long offset, size, max_blocks = sbi->blocks_per_seg;
1110*4882a593Smuzhiyun unsigned long *map;
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun while (blk < end) {
1113*4882a593Smuzhiyun segno = GET_SEGNO(sbi, blk);
1114*4882a593Smuzhiyun sentry = get_seg_entry(sbi, segno);
1115*4882a593Smuzhiyun offset = GET_BLKOFF_FROM_SEG0(sbi, blk);
1116*4882a593Smuzhiyun
1117*4882a593Smuzhiyun if (end < START_BLOCK(sbi, segno + 1))
1118*4882a593Smuzhiyun size = GET_BLKOFF_FROM_SEG0(sbi, end);
1119*4882a593Smuzhiyun else
1120*4882a593Smuzhiyun size = max_blocks;
1121*4882a593Smuzhiyun map = (unsigned long *)(sentry->cur_valid_map);
1122*4882a593Smuzhiyun offset = __find_rev_next_bit(map, size, offset);
1123*4882a593Smuzhiyun f2fs_bug_on(sbi, offset != size);
1124*4882a593Smuzhiyun blk = START_BLOCK(sbi, segno + 1);
1125*4882a593Smuzhiyun }
1126*4882a593Smuzhiyun #endif
1127*4882a593Smuzhiyun }
1128*4882a593Smuzhiyun
__init_discard_policy(struct f2fs_sb_info * sbi,struct discard_policy * dpolicy,int discard_type,unsigned int granularity)1129*4882a593Smuzhiyun static void __init_discard_policy(struct f2fs_sb_info *sbi,
1130*4882a593Smuzhiyun struct discard_policy *dpolicy,
1131*4882a593Smuzhiyun int discard_type, unsigned int granularity)
1132*4882a593Smuzhiyun {
1133*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun /* common policy */
1136*4882a593Smuzhiyun dpolicy->type = discard_type;
1137*4882a593Smuzhiyun dpolicy->sync = true;
1138*4882a593Smuzhiyun dpolicy->ordered = false;
1139*4882a593Smuzhiyun dpolicy->granularity = granularity;
1140*4882a593Smuzhiyun
1141*4882a593Smuzhiyun dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST;
1142*4882a593Smuzhiyun dpolicy->io_aware_gran = MAX_PLIST_NUM;
1143*4882a593Smuzhiyun dpolicy->timeout = false;
1144*4882a593Smuzhiyun
1145*4882a593Smuzhiyun if (discard_type == DPOLICY_BG) {
1146*4882a593Smuzhiyun dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME;
1147*4882a593Smuzhiyun dpolicy->mid_interval = DEF_MID_DISCARD_ISSUE_TIME;
1148*4882a593Smuzhiyun dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME;
1149*4882a593Smuzhiyun dpolicy->io_aware = true;
1150*4882a593Smuzhiyun dpolicy->sync = false;
1151*4882a593Smuzhiyun dpolicy->ordered = true;
1152*4882a593Smuzhiyun if (utilization(sbi) > DEF_DISCARD_URGENT_UTIL) {
1153*4882a593Smuzhiyun dpolicy->granularity = 1;
1154*4882a593Smuzhiyun if (atomic_read(&dcc->discard_cmd_cnt))
1155*4882a593Smuzhiyun dpolicy->max_interval =
1156*4882a593Smuzhiyun DEF_MIN_DISCARD_ISSUE_TIME;
1157*4882a593Smuzhiyun }
1158*4882a593Smuzhiyun } else if (discard_type == DPOLICY_FORCE) {
1159*4882a593Smuzhiyun dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME;
1160*4882a593Smuzhiyun dpolicy->mid_interval = DEF_MID_DISCARD_ISSUE_TIME;
1161*4882a593Smuzhiyun dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME;
1162*4882a593Smuzhiyun dpolicy->io_aware = false;
1163*4882a593Smuzhiyun } else if (discard_type == DPOLICY_FSTRIM) {
1164*4882a593Smuzhiyun dpolicy->io_aware = false;
1165*4882a593Smuzhiyun } else if (discard_type == DPOLICY_UMOUNT) {
1166*4882a593Smuzhiyun dpolicy->io_aware = false;
1167*4882a593Smuzhiyun /* we need to issue all to keep CP_TRIMMED_FLAG */
1168*4882a593Smuzhiyun dpolicy->granularity = 1;
1169*4882a593Smuzhiyun dpolicy->timeout = true;
1170*4882a593Smuzhiyun }
1171*4882a593Smuzhiyun }
1172*4882a593Smuzhiyun
1173*4882a593Smuzhiyun static void __update_discard_tree_range(struct f2fs_sb_info *sbi,
1174*4882a593Smuzhiyun struct block_device *bdev, block_t lstart,
1175*4882a593Smuzhiyun block_t start, block_t len);
1176*4882a593Smuzhiyun /* this function is copied from blkdev_issue_discard from block/blk-lib.c */
__submit_discard_cmd(struct f2fs_sb_info * sbi,struct discard_policy * dpolicy,struct discard_cmd * dc,unsigned int * issued)1177*4882a593Smuzhiyun static int __submit_discard_cmd(struct f2fs_sb_info *sbi,
1178*4882a593Smuzhiyun struct discard_policy *dpolicy,
1179*4882a593Smuzhiyun struct discard_cmd *dc,
1180*4882a593Smuzhiyun unsigned int *issued)
1181*4882a593Smuzhiyun {
1182*4882a593Smuzhiyun struct block_device *bdev = dc->bdev;
1183*4882a593Smuzhiyun struct request_queue *q = bdev_get_queue(bdev);
1184*4882a593Smuzhiyun unsigned int max_discard_blocks =
1185*4882a593Smuzhiyun SECTOR_TO_BLOCK(q->limits.max_discard_sectors);
1186*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1187*4882a593Smuzhiyun struct list_head *wait_list = (dpolicy->type == DPOLICY_FSTRIM) ?
1188*4882a593Smuzhiyun &(dcc->fstrim_list) : &(dcc->wait_list);
1189*4882a593Smuzhiyun int flag = dpolicy->sync ? REQ_SYNC : 0;
1190*4882a593Smuzhiyun block_t lstart, start, len, total_len;
1191*4882a593Smuzhiyun int err = 0;
1192*4882a593Smuzhiyun
1193*4882a593Smuzhiyun if (dc->state != D_PREP)
1194*4882a593Smuzhiyun return 0;
1195*4882a593Smuzhiyun
1196*4882a593Smuzhiyun if (is_sbi_flag_set(sbi, SBI_NEED_FSCK))
1197*4882a593Smuzhiyun return 0;
1198*4882a593Smuzhiyun
1199*4882a593Smuzhiyun trace_f2fs_issue_discard(bdev, dc->start, dc->len);
1200*4882a593Smuzhiyun
1201*4882a593Smuzhiyun lstart = dc->lstart;
1202*4882a593Smuzhiyun start = dc->start;
1203*4882a593Smuzhiyun len = dc->len;
1204*4882a593Smuzhiyun total_len = len;
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun dc->len = 0;
1207*4882a593Smuzhiyun
1208*4882a593Smuzhiyun while (total_len && *issued < dpolicy->max_requests && !err) {
1209*4882a593Smuzhiyun struct bio *bio = NULL;
1210*4882a593Smuzhiyun unsigned long flags;
1211*4882a593Smuzhiyun bool last = true;
1212*4882a593Smuzhiyun
1213*4882a593Smuzhiyun if (len > max_discard_blocks) {
1214*4882a593Smuzhiyun len = max_discard_blocks;
1215*4882a593Smuzhiyun last = false;
1216*4882a593Smuzhiyun }
1217*4882a593Smuzhiyun
1218*4882a593Smuzhiyun (*issued)++;
1219*4882a593Smuzhiyun if (*issued == dpolicy->max_requests)
1220*4882a593Smuzhiyun last = true;
1221*4882a593Smuzhiyun
1222*4882a593Smuzhiyun dc->len += len;
1223*4882a593Smuzhiyun
1224*4882a593Smuzhiyun if (time_to_inject(sbi, FAULT_DISCARD)) {
1225*4882a593Smuzhiyun f2fs_show_injection_info(sbi, FAULT_DISCARD);
1226*4882a593Smuzhiyun err = -EIO;
1227*4882a593Smuzhiyun goto submit;
1228*4882a593Smuzhiyun }
1229*4882a593Smuzhiyun err = __blkdev_issue_discard(bdev,
1230*4882a593Smuzhiyun SECTOR_FROM_BLOCK(start),
1231*4882a593Smuzhiyun SECTOR_FROM_BLOCK(len),
1232*4882a593Smuzhiyun GFP_NOFS, 0, &bio);
1233*4882a593Smuzhiyun submit:
1234*4882a593Smuzhiyun if (err) {
1235*4882a593Smuzhiyun spin_lock_irqsave(&dc->lock, flags);
1236*4882a593Smuzhiyun if (dc->state == D_PARTIAL)
1237*4882a593Smuzhiyun dc->state = D_SUBMIT;
1238*4882a593Smuzhiyun spin_unlock_irqrestore(&dc->lock, flags);
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun break;
1241*4882a593Smuzhiyun }
1242*4882a593Smuzhiyun
1243*4882a593Smuzhiyun f2fs_bug_on(sbi, !bio);
1244*4882a593Smuzhiyun
1245*4882a593Smuzhiyun /*
1246*4882a593Smuzhiyun * should keep before submission to avoid D_DONE
1247*4882a593Smuzhiyun * right away
1248*4882a593Smuzhiyun */
1249*4882a593Smuzhiyun spin_lock_irqsave(&dc->lock, flags);
1250*4882a593Smuzhiyun if (last)
1251*4882a593Smuzhiyun dc->state = D_SUBMIT;
1252*4882a593Smuzhiyun else
1253*4882a593Smuzhiyun dc->state = D_PARTIAL;
1254*4882a593Smuzhiyun dc->bio_ref++;
1255*4882a593Smuzhiyun spin_unlock_irqrestore(&dc->lock, flags);
1256*4882a593Smuzhiyun
1257*4882a593Smuzhiyun atomic_inc(&dcc->queued_discard);
1258*4882a593Smuzhiyun dc->queued++;
1259*4882a593Smuzhiyun list_move_tail(&dc->list, wait_list);
1260*4882a593Smuzhiyun
1261*4882a593Smuzhiyun /* sanity check on discard range */
1262*4882a593Smuzhiyun __check_sit_bitmap(sbi, lstart, lstart + len);
1263*4882a593Smuzhiyun
1264*4882a593Smuzhiyun bio->bi_private = dc;
1265*4882a593Smuzhiyun bio->bi_end_io = f2fs_submit_discard_endio;
1266*4882a593Smuzhiyun bio->bi_opf |= flag;
1267*4882a593Smuzhiyun submit_bio(bio);
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun atomic_inc(&dcc->issued_discard);
1270*4882a593Smuzhiyun
1271*4882a593Smuzhiyun f2fs_update_iostat(sbi, FS_DISCARD, 1);
1272*4882a593Smuzhiyun
1273*4882a593Smuzhiyun lstart += len;
1274*4882a593Smuzhiyun start += len;
1275*4882a593Smuzhiyun total_len -= len;
1276*4882a593Smuzhiyun len = total_len;
1277*4882a593Smuzhiyun }
1278*4882a593Smuzhiyun
1279*4882a593Smuzhiyun if (!err && len) {
1280*4882a593Smuzhiyun dcc->undiscard_blks -= len;
1281*4882a593Smuzhiyun __update_discard_tree_range(sbi, bdev, lstart, start, len);
1282*4882a593Smuzhiyun }
1283*4882a593Smuzhiyun return err;
1284*4882a593Smuzhiyun }
1285*4882a593Smuzhiyun
__insert_discard_tree(struct f2fs_sb_info * sbi,struct block_device * bdev,block_t lstart,block_t start,block_t len,struct rb_node ** insert_p,struct rb_node * insert_parent)1286*4882a593Smuzhiyun static void __insert_discard_tree(struct f2fs_sb_info *sbi,
1287*4882a593Smuzhiyun struct block_device *bdev, block_t lstart,
1288*4882a593Smuzhiyun block_t start, block_t len,
1289*4882a593Smuzhiyun struct rb_node **insert_p,
1290*4882a593Smuzhiyun struct rb_node *insert_parent)
1291*4882a593Smuzhiyun {
1292*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1293*4882a593Smuzhiyun struct rb_node **p;
1294*4882a593Smuzhiyun struct rb_node *parent = NULL;
1295*4882a593Smuzhiyun bool leftmost = true;
1296*4882a593Smuzhiyun
1297*4882a593Smuzhiyun if (insert_p && insert_parent) {
1298*4882a593Smuzhiyun parent = insert_parent;
1299*4882a593Smuzhiyun p = insert_p;
1300*4882a593Smuzhiyun goto do_insert;
1301*4882a593Smuzhiyun }
1302*4882a593Smuzhiyun
1303*4882a593Smuzhiyun p = f2fs_lookup_rb_tree_for_insert(sbi, &dcc->root, &parent,
1304*4882a593Smuzhiyun lstart, &leftmost);
1305*4882a593Smuzhiyun do_insert:
1306*4882a593Smuzhiyun __attach_discard_cmd(sbi, bdev, lstart, start, len, parent,
1307*4882a593Smuzhiyun p, leftmost);
1308*4882a593Smuzhiyun }
1309*4882a593Smuzhiyun
__relocate_discard_cmd(struct discard_cmd_control * dcc,struct discard_cmd * dc)1310*4882a593Smuzhiyun static void __relocate_discard_cmd(struct discard_cmd_control *dcc,
1311*4882a593Smuzhiyun struct discard_cmd *dc)
1312*4882a593Smuzhiyun {
1313*4882a593Smuzhiyun list_move_tail(&dc->list, &dcc->pend_list[plist_idx(dc->len)]);
1314*4882a593Smuzhiyun }
1315*4882a593Smuzhiyun
__punch_discard_cmd(struct f2fs_sb_info * sbi,struct discard_cmd * dc,block_t blkaddr)1316*4882a593Smuzhiyun static void __punch_discard_cmd(struct f2fs_sb_info *sbi,
1317*4882a593Smuzhiyun struct discard_cmd *dc, block_t blkaddr)
1318*4882a593Smuzhiyun {
1319*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1320*4882a593Smuzhiyun struct discard_info di = dc->di;
1321*4882a593Smuzhiyun bool modified = false;
1322*4882a593Smuzhiyun
1323*4882a593Smuzhiyun if (dc->state == D_DONE || dc->len == 1) {
1324*4882a593Smuzhiyun __remove_discard_cmd(sbi, dc);
1325*4882a593Smuzhiyun return;
1326*4882a593Smuzhiyun }
1327*4882a593Smuzhiyun
1328*4882a593Smuzhiyun dcc->undiscard_blks -= di.len;
1329*4882a593Smuzhiyun
1330*4882a593Smuzhiyun if (blkaddr > di.lstart) {
1331*4882a593Smuzhiyun dc->len = blkaddr - dc->lstart;
1332*4882a593Smuzhiyun dcc->undiscard_blks += dc->len;
1333*4882a593Smuzhiyun __relocate_discard_cmd(dcc, dc);
1334*4882a593Smuzhiyun modified = true;
1335*4882a593Smuzhiyun }
1336*4882a593Smuzhiyun
1337*4882a593Smuzhiyun if (blkaddr < di.lstart + di.len - 1) {
1338*4882a593Smuzhiyun if (modified) {
1339*4882a593Smuzhiyun __insert_discard_tree(sbi, dc->bdev, blkaddr + 1,
1340*4882a593Smuzhiyun di.start + blkaddr + 1 - di.lstart,
1341*4882a593Smuzhiyun di.lstart + di.len - 1 - blkaddr,
1342*4882a593Smuzhiyun NULL, NULL);
1343*4882a593Smuzhiyun } else {
1344*4882a593Smuzhiyun dc->lstart++;
1345*4882a593Smuzhiyun dc->len--;
1346*4882a593Smuzhiyun dc->start++;
1347*4882a593Smuzhiyun dcc->undiscard_blks += dc->len;
1348*4882a593Smuzhiyun __relocate_discard_cmd(dcc, dc);
1349*4882a593Smuzhiyun }
1350*4882a593Smuzhiyun }
1351*4882a593Smuzhiyun }
1352*4882a593Smuzhiyun
__update_discard_tree_range(struct f2fs_sb_info * sbi,struct block_device * bdev,block_t lstart,block_t start,block_t len)1353*4882a593Smuzhiyun static void __update_discard_tree_range(struct f2fs_sb_info *sbi,
1354*4882a593Smuzhiyun struct block_device *bdev, block_t lstart,
1355*4882a593Smuzhiyun block_t start, block_t len)
1356*4882a593Smuzhiyun {
1357*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1358*4882a593Smuzhiyun struct discard_cmd *prev_dc = NULL, *next_dc = NULL;
1359*4882a593Smuzhiyun struct discard_cmd *dc;
1360*4882a593Smuzhiyun struct discard_info di = {0};
1361*4882a593Smuzhiyun struct rb_node **insert_p = NULL, *insert_parent = NULL;
1362*4882a593Smuzhiyun struct request_queue *q = bdev_get_queue(bdev);
1363*4882a593Smuzhiyun unsigned int max_discard_blocks =
1364*4882a593Smuzhiyun SECTOR_TO_BLOCK(q->limits.max_discard_sectors);
1365*4882a593Smuzhiyun block_t end = lstart + len;
1366*4882a593Smuzhiyun
1367*4882a593Smuzhiyun dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root,
1368*4882a593Smuzhiyun NULL, lstart,
1369*4882a593Smuzhiyun (struct rb_entry **)&prev_dc,
1370*4882a593Smuzhiyun (struct rb_entry **)&next_dc,
1371*4882a593Smuzhiyun &insert_p, &insert_parent, true, NULL);
1372*4882a593Smuzhiyun if (dc)
1373*4882a593Smuzhiyun prev_dc = dc;
1374*4882a593Smuzhiyun
1375*4882a593Smuzhiyun if (!prev_dc) {
1376*4882a593Smuzhiyun di.lstart = lstart;
1377*4882a593Smuzhiyun di.len = next_dc ? next_dc->lstart - lstart : len;
1378*4882a593Smuzhiyun di.len = min(di.len, len);
1379*4882a593Smuzhiyun di.start = start;
1380*4882a593Smuzhiyun }
1381*4882a593Smuzhiyun
1382*4882a593Smuzhiyun while (1) {
1383*4882a593Smuzhiyun struct rb_node *node;
1384*4882a593Smuzhiyun bool merged = false;
1385*4882a593Smuzhiyun struct discard_cmd *tdc = NULL;
1386*4882a593Smuzhiyun
1387*4882a593Smuzhiyun if (prev_dc) {
1388*4882a593Smuzhiyun di.lstart = prev_dc->lstart + prev_dc->len;
1389*4882a593Smuzhiyun if (di.lstart < lstart)
1390*4882a593Smuzhiyun di.lstart = lstart;
1391*4882a593Smuzhiyun if (di.lstart >= end)
1392*4882a593Smuzhiyun break;
1393*4882a593Smuzhiyun
1394*4882a593Smuzhiyun if (!next_dc || next_dc->lstart > end)
1395*4882a593Smuzhiyun di.len = end - di.lstart;
1396*4882a593Smuzhiyun else
1397*4882a593Smuzhiyun di.len = next_dc->lstart - di.lstart;
1398*4882a593Smuzhiyun di.start = start + di.lstart - lstart;
1399*4882a593Smuzhiyun }
1400*4882a593Smuzhiyun
1401*4882a593Smuzhiyun if (!di.len)
1402*4882a593Smuzhiyun goto next;
1403*4882a593Smuzhiyun
1404*4882a593Smuzhiyun if (prev_dc && prev_dc->state == D_PREP &&
1405*4882a593Smuzhiyun prev_dc->bdev == bdev &&
1406*4882a593Smuzhiyun __is_discard_back_mergeable(&di, &prev_dc->di,
1407*4882a593Smuzhiyun max_discard_blocks)) {
1408*4882a593Smuzhiyun prev_dc->di.len += di.len;
1409*4882a593Smuzhiyun dcc->undiscard_blks += di.len;
1410*4882a593Smuzhiyun __relocate_discard_cmd(dcc, prev_dc);
1411*4882a593Smuzhiyun di = prev_dc->di;
1412*4882a593Smuzhiyun tdc = prev_dc;
1413*4882a593Smuzhiyun merged = true;
1414*4882a593Smuzhiyun }
1415*4882a593Smuzhiyun
1416*4882a593Smuzhiyun if (next_dc && next_dc->state == D_PREP &&
1417*4882a593Smuzhiyun next_dc->bdev == bdev &&
1418*4882a593Smuzhiyun __is_discard_front_mergeable(&di, &next_dc->di,
1419*4882a593Smuzhiyun max_discard_blocks)) {
1420*4882a593Smuzhiyun next_dc->di.lstart = di.lstart;
1421*4882a593Smuzhiyun next_dc->di.len += di.len;
1422*4882a593Smuzhiyun next_dc->di.start = di.start;
1423*4882a593Smuzhiyun dcc->undiscard_blks += di.len;
1424*4882a593Smuzhiyun __relocate_discard_cmd(dcc, next_dc);
1425*4882a593Smuzhiyun if (tdc)
1426*4882a593Smuzhiyun __remove_discard_cmd(sbi, tdc);
1427*4882a593Smuzhiyun merged = true;
1428*4882a593Smuzhiyun }
1429*4882a593Smuzhiyun
1430*4882a593Smuzhiyun if (!merged) {
1431*4882a593Smuzhiyun __insert_discard_tree(sbi, bdev, di.lstart, di.start,
1432*4882a593Smuzhiyun di.len, NULL, NULL);
1433*4882a593Smuzhiyun }
1434*4882a593Smuzhiyun next:
1435*4882a593Smuzhiyun prev_dc = next_dc;
1436*4882a593Smuzhiyun if (!prev_dc)
1437*4882a593Smuzhiyun break;
1438*4882a593Smuzhiyun
1439*4882a593Smuzhiyun node = rb_next(&prev_dc->rb_node);
1440*4882a593Smuzhiyun next_dc = rb_entry_safe(node, struct discard_cmd, rb_node);
1441*4882a593Smuzhiyun }
1442*4882a593Smuzhiyun }
1443*4882a593Smuzhiyun
__queue_discard_cmd(struct f2fs_sb_info * sbi,struct block_device * bdev,block_t blkstart,block_t blklen)1444*4882a593Smuzhiyun static int __queue_discard_cmd(struct f2fs_sb_info *sbi,
1445*4882a593Smuzhiyun struct block_device *bdev, block_t blkstart, block_t blklen)
1446*4882a593Smuzhiyun {
1447*4882a593Smuzhiyun block_t lblkstart = blkstart;
1448*4882a593Smuzhiyun
1449*4882a593Smuzhiyun if (!f2fs_bdev_support_discard(bdev))
1450*4882a593Smuzhiyun return 0;
1451*4882a593Smuzhiyun
1452*4882a593Smuzhiyun trace_f2fs_queue_discard(bdev, blkstart, blklen);
1453*4882a593Smuzhiyun
1454*4882a593Smuzhiyun if (f2fs_is_multi_device(sbi)) {
1455*4882a593Smuzhiyun int devi = f2fs_target_device_index(sbi, blkstart);
1456*4882a593Smuzhiyun
1457*4882a593Smuzhiyun blkstart -= FDEV(devi).start_blk;
1458*4882a593Smuzhiyun }
1459*4882a593Smuzhiyun mutex_lock(&SM_I(sbi)->dcc_info->cmd_lock);
1460*4882a593Smuzhiyun __update_discard_tree_range(sbi, bdev, lblkstart, blkstart, blklen);
1461*4882a593Smuzhiyun mutex_unlock(&SM_I(sbi)->dcc_info->cmd_lock);
1462*4882a593Smuzhiyun return 0;
1463*4882a593Smuzhiyun }
1464*4882a593Smuzhiyun
__issue_discard_cmd_orderly(struct f2fs_sb_info * sbi,struct discard_policy * dpolicy)1465*4882a593Smuzhiyun static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi,
1466*4882a593Smuzhiyun struct discard_policy *dpolicy)
1467*4882a593Smuzhiyun {
1468*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1469*4882a593Smuzhiyun struct discard_cmd *prev_dc = NULL, *next_dc = NULL;
1470*4882a593Smuzhiyun struct rb_node **insert_p = NULL, *insert_parent = NULL;
1471*4882a593Smuzhiyun struct discard_cmd *dc;
1472*4882a593Smuzhiyun struct blk_plug plug;
1473*4882a593Smuzhiyun unsigned int pos = dcc->next_pos;
1474*4882a593Smuzhiyun unsigned int issued = 0;
1475*4882a593Smuzhiyun bool io_interrupted = false;
1476*4882a593Smuzhiyun
1477*4882a593Smuzhiyun mutex_lock(&dcc->cmd_lock);
1478*4882a593Smuzhiyun dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root,
1479*4882a593Smuzhiyun NULL, pos,
1480*4882a593Smuzhiyun (struct rb_entry **)&prev_dc,
1481*4882a593Smuzhiyun (struct rb_entry **)&next_dc,
1482*4882a593Smuzhiyun &insert_p, &insert_parent, true, NULL);
1483*4882a593Smuzhiyun if (!dc)
1484*4882a593Smuzhiyun dc = next_dc;
1485*4882a593Smuzhiyun
1486*4882a593Smuzhiyun blk_start_plug(&plug);
1487*4882a593Smuzhiyun
1488*4882a593Smuzhiyun while (dc) {
1489*4882a593Smuzhiyun struct rb_node *node;
1490*4882a593Smuzhiyun int err = 0;
1491*4882a593Smuzhiyun
1492*4882a593Smuzhiyun if (dc->state != D_PREP)
1493*4882a593Smuzhiyun goto next;
1494*4882a593Smuzhiyun
1495*4882a593Smuzhiyun if (dpolicy->io_aware && !is_idle(sbi, DISCARD_TIME)) {
1496*4882a593Smuzhiyun io_interrupted = true;
1497*4882a593Smuzhiyun break;
1498*4882a593Smuzhiyun }
1499*4882a593Smuzhiyun
1500*4882a593Smuzhiyun dcc->next_pos = dc->lstart + dc->len;
1501*4882a593Smuzhiyun err = __submit_discard_cmd(sbi, dpolicy, dc, &issued);
1502*4882a593Smuzhiyun
1503*4882a593Smuzhiyun if (issued >= dpolicy->max_requests)
1504*4882a593Smuzhiyun break;
1505*4882a593Smuzhiyun next:
1506*4882a593Smuzhiyun node = rb_next(&dc->rb_node);
1507*4882a593Smuzhiyun if (err)
1508*4882a593Smuzhiyun __remove_discard_cmd(sbi, dc);
1509*4882a593Smuzhiyun dc = rb_entry_safe(node, struct discard_cmd, rb_node);
1510*4882a593Smuzhiyun }
1511*4882a593Smuzhiyun
1512*4882a593Smuzhiyun blk_finish_plug(&plug);
1513*4882a593Smuzhiyun
1514*4882a593Smuzhiyun if (!dc)
1515*4882a593Smuzhiyun dcc->next_pos = 0;
1516*4882a593Smuzhiyun
1517*4882a593Smuzhiyun mutex_unlock(&dcc->cmd_lock);
1518*4882a593Smuzhiyun
1519*4882a593Smuzhiyun if (!issued && io_interrupted)
1520*4882a593Smuzhiyun issued = -1;
1521*4882a593Smuzhiyun
1522*4882a593Smuzhiyun return issued;
1523*4882a593Smuzhiyun }
1524*4882a593Smuzhiyun static unsigned int __wait_all_discard_cmd(struct f2fs_sb_info *sbi,
1525*4882a593Smuzhiyun struct discard_policy *dpolicy);
1526*4882a593Smuzhiyun
__issue_discard_cmd(struct f2fs_sb_info * sbi,struct discard_policy * dpolicy)1527*4882a593Smuzhiyun static int __issue_discard_cmd(struct f2fs_sb_info *sbi,
1528*4882a593Smuzhiyun struct discard_policy *dpolicy)
1529*4882a593Smuzhiyun {
1530*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1531*4882a593Smuzhiyun struct list_head *pend_list;
1532*4882a593Smuzhiyun struct discard_cmd *dc, *tmp;
1533*4882a593Smuzhiyun struct blk_plug plug;
1534*4882a593Smuzhiyun int i, issued;
1535*4882a593Smuzhiyun bool io_interrupted = false;
1536*4882a593Smuzhiyun
1537*4882a593Smuzhiyun if (dpolicy->timeout)
1538*4882a593Smuzhiyun f2fs_update_time(sbi, UMOUNT_DISCARD_TIMEOUT);
1539*4882a593Smuzhiyun
1540*4882a593Smuzhiyun retry:
1541*4882a593Smuzhiyun issued = 0;
1542*4882a593Smuzhiyun for (i = MAX_PLIST_NUM - 1; i >= 0; i--) {
1543*4882a593Smuzhiyun if (dpolicy->timeout &&
1544*4882a593Smuzhiyun f2fs_time_over(sbi, UMOUNT_DISCARD_TIMEOUT))
1545*4882a593Smuzhiyun break;
1546*4882a593Smuzhiyun
1547*4882a593Smuzhiyun if (i + 1 < dpolicy->granularity)
1548*4882a593Smuzhiyun break;
1549*4882a593Smuzhiyun
1550*4882a593Smuzhiyun if (i < DEFAULT_DISCARD_GRANULARITY && dpolicy->ordered)
1551*4882a593Smuzhiyun return __issue_discard_cmd_orderly(sbi, dpolicy);
1552*4882a593Smuzhiyun
1553*4882a593Smuzhiyun pend_list = &dcc->pend_list[i];
1554*4882a593Smuzhiyun
1555*4882a593Smuzhiyun mutex_lock(&dcc->cmd_lock);
1556*4882a593Smuzhiyun if (list_empty(pend_list))
1557*4882a593Smuzhiyun goto next;
1558*4882a593Smuzhiyun if (unlikely(dcc->rbtree_check))
1559*4882a593Smuzhiyun f2fs_bug_on(sbi, !f2fs_check_rb_tree_consistence(sbi,
1560*4882a593Smuzhiyun &dcc->root, false));
1561*4882a593Smuzhiyun blk_start_plug(&plug);
1562*4882a593Smuzhiyun list_for_each_entry_safe(dc, tmp, pend_list, list) {
1563*4882a593Smuzhiyun f2fs_bug_on(sbi, dc->state != D_PREP);
1564*4882a593Smuzhiyun
1565*4882a593Smuzhiyun if (dpolicy->timeout &&
1566*4882a593Smuzhiyun f2fs_time_over(sbi, UMOUNT_DISCARD_TIMEOUT))
1567*4882a593Smuzhiyun break;
1568*4882a593Smuzhiyun
1569*4882a593Smuzhiyun if (dpolicy->io_aware && i < dpolicy->io_aware_gran &&
1570*4882a593Smuzhiyun !is_idle(sbi, DISCARD_TIME)) {
1571*4882a593Smuzhiyun io_interrupted = true;
1572*4882a593Smuzhiyun break;
1573*4882a593Smuzhiyun }
1574*4882a593Smuzhiyun
1575*4882a593Smuzhiyun __submit_discard_cmd(sbi, dpolicy, dc, &issued);
1576*4882a593Smuzhiyun
1577*4882a593Smuzhiyun if (issued >= dpolicy->max_requests)
1578*4882a593Smuzhiyun break;
1579*4882a593Smuzhiyun }
1580*4882a593Smuzhiyun blk_finish_plug(&plug);
1581*4882a593Smuzhiyun next:
1582*4882a593Smuzhiyun mutex_unlock(&dcc->cmd_lock);
1583*4882a593Smuzhiyun
1584*4882a593Smuzhiyun if (issued >= dpolicy->max_requests || io_interrupted)
1585*4882a593Smuzhiyun break;
1586*4882a593Smuzhiyun }
1587*4882a593Smuzhiyun
1588*4882a593Smuzhiyun if (dpolicy->type == DPOLICY_UMOUNT && issued) {
1589*4882a593Smuzhiyun __wait_all_discard_cmd(sbi, dpolicy);
1590*4882a593Smuzhiyun goto retry;
1591*4882a593Smuzhiyun }
1592*4882a593Smuzhiyun
1593*4882a593Smuzhiyun if (!issued && io_interrupted)
1594*4882a593Smuzhiyun issued = -1;
1595*4882a593Smuzhiyun
1596*4882a593Smuzhiyun return issued;
1597*4882a593Smuzhiyun }
1598*4882a593Smuzhiyun
__drop_discard_cmd(struct f2fs_sb_info * sbi)1599*4882a593Smuzhiyun static bool __drop_discard_cmd(struct f2fs_sb_info *sbi)
1600*4882a593Smuzhiyun {
1601*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1602*4882a593Smuzhiyun struct list_head *pend_list;
1603*4882a593Smuzhiyun struct discard_cmd *dc, *tmp;
1604*4882a593Smuzhiyun int i;
1605*4882a593Smuzhiyun bool dropped = false;
1606*4882a593Smuzhiyun
1607*4882a593Smuzhiyun mutex_lock(&dcc->cmd_lock);
1608*4882a593Smuzhiyun for (i = MAX_PLIST_NUM - 1; i >= 0; i--) {
1609*4882a593Smuzhiyun pend_list = &dcc->pend_list[i];
1610*4882a593Smuzhiyun list_for_each_entry_safe(dc, tmp, pend_list, list) {
1611*4882a593Smuzhiyun f2fs_bug_on(sbi, dc->state != D_PREP);
1612*4882a593Smuzhiyun __remove_discard_cmd(sbi, dc);
1613*4882a593Smuzhiyun dropped = true;
1614*4882a593Smuzhiyun }
1615*4882a593Smuzhiyun }
1616*4882a593Smuzhiyun mutex_unlock(&dcc->cmd_lock);
1617*4882a593Smuzhiyun
1618*4882a593Smuzhiyun return dropped;
1619*4882a593Smuzhiyun }
1620*4882a593Smuzhiyun
f2fs_drop_discard_cmd(struct f2fs_sb_info * sbi)1621*4882a593Smuzhiyun void f2fs_drop_discard_cmd(struct f2fs_sb_info *sbi)
1622*4882a593Smuzhiyun {
1623*4882a593Smuzhiyun __drop_discard_cmd(sbi);
1624*4882a593Smuzhiyun }
1625*4882a593Smuzhiyun
__wait_one_discard_bio(struct f2fs_sb_info * sbi,struct discard_cmd * dc)1626*4882a593Smuzhiyun static unsigned int __wait_one_discard_bio(struct f2fs_sb_info *sbi,
1627*4882a593Smuzhiyun struct discard_cmd *dc)
1628*4882a593Smuzhiyun {
1629*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1630*4882a593Smuzhiyun unsigned int len = 0;
1631*4882a593Smuzhiyun
1632*4882a593Smuzhiyun wait_for_completion_io(&dc->wait);
1633*4882a593Smuzhiyun mutex_lock(&dcc->cmd_lock);
1634*4882a593Smuzhiyun f2fs_bug_on(sbi, dc->state != D_DONE);
1635*4882a593Smuzhiyun dc->ref--;
1636*4882a593Smuzhiyun if (!dc->ref) {
1637*4882a593Smuzhiyun if (!dc->error)
1638*4882a593Smuzhiyun len = dc->len;
1639*4882a593Smuzhiyun __remove_discard_cmd(sbi, dc);
1640*4882a593Smuzhiyun }
1641*4882a593Smuzhiyun mutex_unlock(&dcc->cmd_lock);
1642*4882a593Smuzhiyun
1643*4882a593Smuzhiyun return len;
1644*4882a593Smuzhiyun }
1645*4882a593Smuzhiyun
__wait_discard_cmd_range(struct f2fs_sb_info * sbi,struct discard_policy * dpolicy,block_t start,block_t end)1646*4882a593Smuzhiyun static unsigned int __wait_discard_cmd_range(struct f2fs_sb_info *sbi,
1647*4882a593Smuzhiyun struct discard_policy *dpolicy,
1648*4882a593Smuzhiyun block_t start, block_t end)
1649*4882a593Smuzhiyun {
1650*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1651*4882a593Smuzhiyun struct list_head *wait_list = (dpolicy->type == DPOLICY_FSTRIM) ?
1652*4882a593Smuzhiyun &(dcc->fstrim_list) : &(dcc->wait_list);
1653*4882a593Smuzhiyun struct discard_cmd *dc, *tmp;
1654*4882a593Smuzhiyun bool need_wait;
1655*4882a593Smuzhiyun unsigned int trimmed = 0;
1656*4882a593Smuzhiyun
1657*4882a593Smuzhiyun next:
1658*4882a593Smuzhiyun need_wait = false;
1659*4882a593Smuzhiyun
1660*4882a593Smuzhiyun mutex_lock(&dcc->cmd_lock);
1661*4882a593Smuzhiyun list_for_each_entry_safe(dc, tmp, wait_list, list) {
1662*4882a593Smuzhiyun if (dc->lstart + dc->len <= start || end <= dc->lstart)
1663*4882a593Smuzhiyun continue;
1664*4882a593Smuzhiyun if (dc->len < dpolicy->granularity)
1665*4882a593Smuzhiyun continue;
1666*4882a593Smuzhiyun if (dc->state == D_DONE && !dc->ref) {
1667*4882a593Smuzhiyun wait_for_completion_io(&dc->wait);
1668*4882a593Smuzhiyun if (!dc->error)
1669*4882a593Smuzhiyun trimmed += dc->len;
1670*4882a593Smuzhiyun __remove_discard_cmd(sbi, dc);
1671*4882a593Smuzhiyun } else {
1672*4882a593Smuzhiyun dc->ref++;
1673*4882a593Smuzhiyun need_wait = true;
1674*4882a593Smuzhiyun break;
1675*4882a593Smuzhiyun }
1676*4882a593Smuzhiyun }
1677*4882a593Smuzhiyun mutex_unlock(&dcc->cmd_lock);
1678*4882a593Smuzhiyun
1679*4882a593Smuzhiyun if (need_wait) {
1680*4882a593Smuzhiyun trimmed += __wait_one_discard_bio(sbi, dc);
1681*4882a593Smuzhiyun goto next;
1682*4882a593Smuzhiyun }
1683*4882a593Smuzhiyun
1684*4882a593Smuzhiyun return trimmed;
1685*4882a593Smuzhiyun }
1686*4882a593Smuzhiyun
__wait_all_discard_cmd(struct f2fs_sb_info * sbi,struct discard_policy * dpolicy)1687*4882a593Smuzhiyun static unsigned int __wait_all_discard_cmd(struct f2fs_sb_info *sbi,
1688*4882a593Smuzhiyun struct discard_policy *dpolicy)
1689*4882a593Smuzhiyun {
1690*4882a593Smuzhiyun struct discard_policy dp;
1691*4882a593Smuzhiyun unsigned int discard_blks;
1692*4882a593Smuzhiyun
1693*4882a593Smuzhiyun if (dpolicy)
1694*4882a593Smuzhiyun return __wait_discard_cmd_range(sbi, dpolicy, 0, UINT_MAX);
1695*4882a593Smuzhiyun
1696*4882a593Smuzhiyun /* wait all */
1697*4882a593Smuzhiyun __init_discard_policy(sbi, &dp, DPOLICY_FSTRIM, 1);
1698*4882a593Smuzhiyun discard_blks = __wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX);
1699*4882a593Smuzhiyun __init_discard_policy(sbi, &dp, DPOLICY_UMOUNT, 1);
1700*4882a593Smuzhiyun discard_blks += __wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX);
1701*4882a593Smuzhiyun
1702*4882a593Smuzhiyun return discard_blks;
1703*4882a593Smuzhiyun }
1704*4882a593Smuzhiyun
1705*4882a593Smuzhiyun /* This should be covered by global mutex, &sit_i->sentry_lock */
f2fs_wait_discard_bio(struct f2fs_sb_info * sbi,block_t blkaddr)1706*4882a593Smuzhiyun static void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr)
1707*4882a593Smuzhiyun {
1708*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1709*4882a593Smuzhiyun struct discard_cmd *dc;
1710*4882a593Smuzhiyun bool need_wait = false;
1711*4882a593Smuzhiyun
1712*4882a593Smuzhiyun mutex_lock(&dcc->cmd_lock);
1713*4882a593Smuzhiyun dc = (struct discard_cmd *)f2fs_lookup_rb_tree(&dcc->root,
1714*4882a593Smuzhiyun NULL, blkaddr);
1715*4882a593Smuzhiyun if (dc) {
1716*4882a593Smuzhiyun if (dc->state == D_PREP) {
1717*4882a593Smuzhiyun __punch_discard_cmd(sbi, dc, blkaddr);
1718*4882a593Smuzhiyun } else {
1719*4882a593Smuzhiyun dc->ref++;
1720*4882a593Smuzhiyun need_wait = true;
1721*4882a593Smuzhiyun }
1722*4882a593Smuzhiyun }
1723*4882a593Smuzhiyun mutex_unlock(&dcc->cmd_lock);
1724*4882a593Smuzhiyun
1725*4882a593Smuzhiyun if (need_wait)
1726*4882a593Smuzhiyun __wait_one_discard_bio(sbi, dc);
1727*4882a593Smuzhiyun }
1728*4882a593Smuzhiyun
f2fs_stop_discard_thread(struct f2fs_sb_info * sbi)1729*4882a593Smuzhiyun void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi)
1730*4882a593Smuzhiyun {
1731*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1732*4882a593Smuzhiyun
1733*4882a593Smuzhiyun if (dcc && dcc->f2fs_issue_discard) {
1734*4882a593Smuzhiyun struct task_struct *discard_thread = dcc->f2fs_issue_discard;
1735*4882a593Smuzhiyun
1736*4882a593Smuzhiyun dcc->f2fs_issue_discard = NULL;
1737*4882a593Smuzhiyun kthread_stop(discard_thread);
1738*4882a593Smuzhiyun }
1739*4882a593Smuzhiyun }
1740*4882a593Smuzhiyun
1741*4882a593Smuzhiyun /* This comes from f2fs_put_super */
f2fs_issue_discard_timeout(struct f2fs_sb_info * sbi)1742*4882a593Smuzhiyun bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi)
1743*4882a593Smuzhiyun {
1744*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1745*4882a593Smuzhiyun struct discard_policy dpolicy;
1746*4882a593Smuzhiyun bool dropped;
1747*4882a593Smuzhiyun
1748*4882a593Smuzhiyun __init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT,
1749*4882a593Smuzhiyun dcc->discard_granularity);
1750*4882a593Smuzhiyun __issue_discard_cmd(sbi, &dpolicy);
1751*4882a593Smuzhiyun dropped = __drop_discard_cmd(sbi);
1752*4882a593Smuzhiyun
1753*4882a593Smuzhiyun /* just to make sure there is no pending discard commands */
1754*4882a593Smuzhiyun __wait_all_discard_cmd(sbi, NULL);
1755*4882a593Smuzhiyun
1756*4882a593Smuzhiyun f2fs_bug_on(sbi, atomic_read(&dcc->discard_cmd_cnt));
1757*4882a593Smuzhiyun return dropped;
1758*4882a593Smuzhiyun }
1759*4882a593Smuzhiyun
issue_discard_thread(void * data)1760*4882a593Smuzhiyun static int issue_discard_thread(void *data)
1761*4882a593Smuzhiyun {
1762*4882a593Smuzhiyun struct f2fs_sb_info *sbi = data;
1763*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
1764*4882a593Smuzhiyun wait_queue_head_t *q = &dcc->discard_wait_queue;
1765*4882a593Smuzhiyun struct discard_policy dpolicy;
1766*4882a593Smuzhiyun unsigned int wait_ms = DEF_MIN_DISCARD_ISSUE_TIME;
1767*4882a593Smuzhiyun int issued;
1768*4882a593Smuzhiyun
1769*4882a593Smuzhiyun set_freezable();
1770*4882a593Smuzhiyun
1771*4882a593Smuzhiyun do {
1772*4882a593Smuzhiyun if (sbi->gc_mode == GC_URGENT_HIGH ||
1773*4882a593Smuzhiyun !f2fs_available_free_memory(sbi, DISCARD_CACHE))
1774*4882a593Smuzhiyun __init_discard_policy(sbi, &dpolicy, DPOLICY_FORCE, 1);
1775*4882a593Smuzhiyun else
1776*4882a593Smuzhiyun __init_discard_policy(sbi, &dpolicy, DPOLICY_BG,
1777*4882a593Smuzhiyun dcc->discard_granularity);
1778*4882a593Smuzhiyun
1779*4882a593Smuzhiyun if (!atomic_read(&dcc->discard_cmd_cnt))
1780*4882a593Smuzhiyun wait_ms = dpolicy.max_interval;
1781*4882a593Smuzhiyun
1782*4882a593Smuzhiyun wait_event_interruptible_timeout(*q,
1783*4882a593Smuzhiyun kthread_should_stop() || freezing(current) ||
1784*4882a593Smuzhiyun dcc->discard_wake,
1785*4882a593Smuzhiyun msecs_to_jiffies(wait_ms));
1786*4882a593Smuzhiyun
1787*4882a593Smuzhiyun if (dcc->discard_wake)
1788*4882a593Smuzhiyun dcc->discard_wake = 0;
1789*4882a593Smuzhiyun
1790*4882a593Smuzhiyun /* clean up pending candidates before going to sleep */
1791*4882a593Smuzhiyun if (atomic_read(&dcc->queued_discard))
1792*4882a593Smuzhiyun __wait_all_discard_cmd(sbi, NULL);
1793*4882a593Smuzhiyun
1794*4882a593Smuzhiyun if (try_to_freeze())
1795*4882a593Smuzhiyun continue;
1796*4882a593Smuzhiyun if (f2fs_readonly(sbi->sb))
1797*4882a593Smuzhiyun continue;
1798*4882a593Smuzhiyun if (kthread_should_stop())
1799*4882a593Smuzhiyun return 0;
1800*4882a593Smuzhiyun if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) {
1801*4882a593Smuzhiyun wait_ms = dpolicy.max_interval;
1802*4882a593Smuzhiyun continue;
1803*4882a593Smuzhiyun }
1804*4882a593Smuzhiyun if (!atomic_read(&dcc->discard_cmd_cnt))
1805*4882a593Smuzhiyun continue;
1806*4882a593Smuzhiyun
1807*4882a593Smuzhiyun sb_start_intwrite(sbi->sb);
1808*4882a593Smuzhiyun
1809*4882a593Smuzhiyun issued = __issue_discard_cmd(sbi, &dpolicy);
1810*4882a593Smuzhiyun if (issued > 0) {
1811*4882a593Smuzhiyun __wait_all_discard_cmd(sbi, &dpolicy);
1812*4882a593Smuzhiyun wait_ms = dpolicy.min_interval;
1813*4882a593Smuzhiyun } else if (issued == -1) {
1814*4882a593Smuzhiyun wait_ms = f2fs_time_to_wait(sbi, DISCARD_TIME);
1815*4882a593Smuzhiyun if (!wait_ms)
1816*4882a593Smuzhiyun wait_ms = dpolicy.mid_interval;
1817*4882a593Smuzhiyun } else {
1818*4882a593Smuzhiyun wait_ms = dpolicy.max_interval;
1819*4882a593Smuzhiyun }
1820*4882a593Smuzhiyun
1821*4882a593Smuzhiyun sb_end_intwrite(sbi->sb);
1822*4882a593Smuzhiyun
1823*4882a593Smuzhiyun } while (!kthread_should_stop());
1824*4882a593Smuzhiyun return 0;
1825*4882a593Smuzhiyun }
1826*4882a593Smuzhiyun
1827*4882a593Smuzhiyun #ifdef CONFIG_BLK_DEV_ZONED
__f2fs_issue_discard_zone(struct f2fs_sb_info * sbi,struct block_device * bdev,block_t blkstart,block_t blklen)1828*4882a593Smuzhiyun static int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi,
1829*4882a593Smuzhiyun struct block_device *bdev, block_t blkstart, block_t blklen)
1830*4882a593Smuzhiyun {
1831*4882a593Smuzhiyun sector_t sector, nr_sects;
1832*4882a593Smuzhiyun block_t lblkstart = blkstart;
1833*4882a593Smuzhiyun int devi = 0;
1834*4882a593Smuzhiyun
1835*4882a593Smuzhiyun if (f2fs_is_multi_device(sbi)) {
1836*4882a593Smuzhiyun devi = f2fs_target_device_index(sbi, blkstart);
1837*4882a593Smuzhiyun if (blkstart < FDEV(devi).start_blk ||
1838*4882a593Smuzhiyun blkstart > FDEV(devi).end_blk) {
1839*4882a593Smuzhiyun f2fs_err(sbi, "Invalid block %x", blkstart);
1840*4882a593Smuzhiyun return -EIO;
1841*4882a593Smuzhiyun }
1842*4882a593Smuzhiyun blkstart -= FDEV(devi).start_blk;
1843*4882a593Smuzhiyun }
1844*4882a593Smuzhiyun
1845*4882a593Smuzhiyun /* For sequential zones, reset the zone write pointer */
1846*4882a593Smuzhiyun if (f2fs_blkz_is_seq(sbi, devi, blkstart)) {
1847*4882a593Smuzhiyun sector = SECTOR_FROM_BLOCK(blkstart);
1848*4882a593Smuzhiyun nr_sects = SECTOR_FROM_BLOCK(blklen);
1849*4882a593Smuzhiyun
1850*4882a593Smuzhiyun if (sector & (bdev_zone_sectors(bdev) - 1) ||
1851*4882a593Smuzhiyun nr_sects != bdev_zone_sectors(bdev)) {
1852*4882a593Smuzhiyun f2fs_err(sbi, "(%d) %s: Unaligned zone reset attempted (block %x + %x)",
1853*4882a593Smuzhiyun devi, sbi->s_ndevs ? FDEV(devi).path : "",
1854*4882a593Smuzhiyun blkstart, blklen);
1855*4882a593Smuzhiyun return -EIO;
1856*4882a593Smuzhiyun }
1857*4882a593Smuzhiyun trace_f2fs_issue_reset_zone(bdev, blkstart);
1858*4882a593Smuzhiyun return blkdev_zone_mgmt(bdev, REQ_OP_ZONE_RESET,
1859*4882a593Smuzhiyun sector, nr_sects, GFP_NOFS);
1860*4882a593Smuzhiyun }
1861*4882a593Smuzhiyun
1862*4882a593Smuzhiyun /* For conventional zones, use regular discard if supported */
1863*4882a593Smuzhiyun return __queue_discard_cmd(sbi, bdev, lblkstart, blklen);
1864*4882a593Smuzhiyun }
1865*4882a593Smuzhiyun #endif
1866*4882a593Smuzhiyun
__issue_discard_async(struct f2fs_sb_info * sbi,struct block_device * bdev,block_t blkstart,block_t blklen)1867*4882a593Smuzhiyun static int __issue_discard_async(struct f2fs_sb_info *sbi,
1868*4882a593Smuzhiyun struct block_device *bdev, block_t blkstart, block_t blklen)
1869*4882a593Smuzhiyun {
1870*4882a593Smuzhiyun #ifdef CONFIG_BLK_DEV_ZONED
1871*4882a593Smuzhiyun if (f2fs_sb_has_blkzoned(sbi) && bdev_is_zoned(bdev))
1872*4882a593Smuzhiyun return __f2fs_issue_discard_zone(sbi, bdev, blkstart, blklen);
1873*4882a593Smuzhiyun #endif
1874*4882a593Smuzhiyun return __queue_discard_cmd(sbi, bdev, blkstart, blklen);
1875*4882a593Smuzhiyun }
1876*4882a593Smuzhiyun
f2fs_issue_discard(struct f2fs_sb_info * sbi,block_t blkstart,block_t blklen)1877*4882a593Smuzhiyun static int f2fs_issue_discard(struct f2fs_sb_info *sbi,
1878*4882a593Smuzhiyun block_t blkstart, block_t blklen)
1879*4882a593Smuzhiyun {
1880*4882a593Smuzhiyun sector_t start = blkstart, len = 0;
1881*4882a593Smuzhiyun struct block_device *bdev;
1882*4882a593Smuzhiyun struct seg_entry *se;
1883*4882a593Smuzhiyun unsigned int offset;
1884*4882a593Smuzhiyun block_t i;
1885*4882a593Smuzhiyun int err = 0;
1886*4882a593Smuzhiyun
1887*4882a593Smuzhiyun bdev = f2fs_target_device(sbi, blkstart, NULL);
1888*4882a593Smuzhiyun
1889*4882a593Smuzhiyun for (i = blkstart; i < blkstart + blklen; i++, len++) {
1890*4882a593Smuzhiyun if (i != start) {
1891*4882a593Smuzhiyun struct block_device *bdev2 =
1892*4882a593Smuzhiyun f2fs_target_device(sbi, i, NULL);
1893*4882a593Smuzhiyun
1894*4882a593Smuzhiyun if (bdev2 != bdev) {
1895*4882a593Smuzhiyun err = __issue_discard_async(sbi, bdev,
1896*4882a593Smuzhiyun start, len);
1897*4882a593Smuzhiyun if (err)
1898*4882a593Smuzhiyun return err;
1899*4882a593Smuzhiyun bdev = bdev2;
1900*4882a593Smuzhiyun start = i;
1901*4882a593Smuzhiyun len = 0;
1902*4882a593Smuzhiyun }
1903*4882a593Smuzhiyun }
1904*4882a593Smuzhiyun
1905*4882a593Smuzhiyun se = get_seg_entry(sbi, GET_SEGNO(sbi, i));
1906*4882a593Smuzhiyun offset = GET_BLKOFF_FROM_SEG0(sbi, i);
1907*4882a593Smuzhiyun
1908*4882a593Smuzhiyun if (!f2fs_test_and_set_bit(offset, se->discard_map))
1909*4882a593Smuzhiyun sbi->discard_blks--;
1910*4882a593Smuzhiyun }
1911*4882a593Smuzhiyun
1912*4882a593Smuzhiyun if (len)
1913*4882a593Smuzhiyun err = __issue_discard_async(sbi, bdev, start, len);
1914*4882a593Smuzhiyun return err;
1915*4882a593Smuzhiyun }
1916*4882a593Smuzhiyun
add_discard_addrs(struct f2fs_sb_info * sbi,struct cp_control * cpc,bool check_only)1917*4882a593Smuzhiyun static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,
1918*4882a593Smuzhiyun bool check_only)
1919*4882a593Smuzhiyun {
1920*4882a593Smuzhiyun int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long);
1921*4882a593Smuzhiyun int max_blocks = sbi->blocks_per_seg;
1922*4882a593Smuzhiyun struct seg_entry *se = get_seg_entry(sbi, cpc->trim_start);
1923*4882a593Smuzhiyun unsigned long *cur_map = (unsigned long *)se->cur_valid_map;
1924*4882a593Smuzhiyun unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map;
1925*4882a593Smuzhiyun unsigned long *discard_map = (unsigned long *)se->discard_map;
1926*4882a593Smuzhiyun unsigned long *dmap = SIT_I(sbi)->tmp_map;
1927*4882a593Smuzhiyun unsigned int start = 0, end = -1;
1928*4882a593Smuzhiyun bool force = (cpc->reason & CP_DISCARD);
1929*4882a593Smuzhiyun struct discard_entry *de = NULL;
1930*4882a593Smuzhiyun struct list_head *head = &SM_I(sbi)->dcc_info->entry_list;
1931*4882a593Smuzhiyun int i;
1932*4882a593Smuzhiyun
1933*4882a593Smuzhiyun if (se->valid_blocks == max_blocks || !f2fs_hw_support_discard(sbi))
1934*4882a593Smuzhiyun return false;
1935*4882a593Smuzhiyun
1936*4882a593Smuzhiyun if (!force) {
1937*4882a593Smuzhiyun if (!f2fs_realtime_discard_enable(sbi) || !se->valid_blocks ||
1938*4882a593Smuzhiyun SM_I(sbi)->dcc_info->nr_discards >=
1939*4882a593Smuzhiyun SM_I(sbi)->dcc_info->max_discards)
1940*4882a593Smuzhiyun return false;
1941*4882a593Smuzhiyun }
1942*4882a593Smuzhiyun
1943*4882a593Smuzhiyun /* SIT_VBLOCK_MAP_SIZE should be multiple of sizeof(unsigned long) */
1944*4882a593Smuzhiyun for (i = 0; i < entries; i++)
1945*4882a593Smuzhiyun dmap[i] = force ? ~ckpt_map[i] & ~discard_map[i] :
1946*4882a593Smuzhiyun (cur_map[i] ^ ckpt_map[i]) & ckpt_map[i];
1947*4882a593Smuzhiyun
1948*4882a593Smuzhiyun while (force || SM_I(sbi)->dcc_info->nr_discards <=
1949*4882a593Smuzhiyun SM_I(sbi)->dcc_info->max_discards) {
1950*4882a593Smuzhiyun start = __find_rev_next_bit(dmap, max_blocks, end + 1);
1951*4882a593Smuzhiyun if (start >= max_blocks)
1952*4882a593Smuzhiyun break;
1953*4882a593Smuzhiyun
1954*4882a593Smuzhiyun end = __find_rev_next_zero_bit(dmap, max_blocks, start + 1);
1955*4882a593Smuzhiyun if (force && start && end != max_blocks
1956*4882a593Smuzhiyun && (end - start) < cpc->trim_minlen)
1957*4882a593Smuzhiyun continue;
1958*4882a593Smuzhiyun
1959*4882a593Smuzhiyun if (check_only)
1960*4882a593Smuzhiyun return true;
1961*4882a593Smuzhiyun
1962*4882a593Smuzhiyun if (!de) {
1963*4882a593Smuzhiyun de = f2fs_kmem_cache_alloc(discard_entry_slab,
1964*4882a593Smuzhiyun GFP_F2FS_ZERO);
1965*4882a593Smuzhiyun de->start_blkaddr = START_BLOCK(sbi, cpc->trim_start);
1966*4882a593Smuzhiyun list_add_tail(&de->list, head);
1967*4882a593Smuzhiyun }
1968*4882a593Smuzhiyun
1969*4882a593Smuzhiyun for (i = start; i < end; i++)
1970*4882a593Smuzhiyun __set_bit_le(i, (void *)de->discard_map);
1971*4882a593Smuzhiyun
1972*4882a593Smuzhiyun SM_I(sbi)->dcc_info->nr_discards += end - start;
1973*4882a593Smuzhiyun }
1974*4882a593Smuzhiyun return false;
1975*4882a593Smuzhiyun }
1976*4882a593Smuzhiyun
release_discard_addr(struct discard_entry * entry)1977*4882a593Smuzhiyun static void release_discard_addr(struct discard_entry *entry)
1978*4882a593Smuzhiyun {
1979*4882a593Smuzhiyun list_del(&entry->list);
1980*4882a593Smuzhiyun kmem_cache_free(discard_entry_slab, entry);
1981*4882a593Smuzhiyun }
1982*4882a593Smuzhiyun
f2fs_release_discard_addrs(struct f2fs_sb_info * sbi)1983*4882a593Smuzhiyun void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi)
1984*4882a593Smuzhiyun {
1985*4882a593Smuzhiyun struct list_head *head = &(SM_I(sbi)->dcc_info->entry_list);
1986*4882a593Smuzhiyun struct discard_entry *entry, *this;
1987*4882a593Smuzhiyun
1988*4882a593Smuzhiyun /* drop caches */
1989*4882a593Smuzhiyun list_for_each_entry_safe(entry, this, head, list)
1990*4882a593Smuzhiyun release_discard_addr(entry);
1991*4882a593Smuzhiyun }
1992*4882a593Smuzhiyun
1993*4882a593Smuzhiyun /*
1994*4882a593Smuzhiyun * Should call f2fs_clear_prefree_segments after checkpoint is done.
1995*4882a593Smuzhiyun */
set_prefree_as_free_segments(struct f2fs_sb_info * sbi)1996*4882a593Smuzhiyun static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi)
1997*4882a593Smuzhiyun {
1998*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
1999*4882a593Smuzhiyun unsigned int segno;
2000*4882a593Smuzhiyun
2001*4882a593Smuzhiyun mutex_lock(&dirty_i->seglist_lock);
2002*4882a593Smuzhiyun for_each_set_bit(segno, dirty_i->dirty_segmap[PRE], MAIN_SEGS(sbi))
2003*4882a593Smuzhiyun __set_test_and_free(sbi, segno, false);
2004*4882a593Smuzhiyun mutex_unlock(&dirty_i->seglist_lock);
2005*4882a593Smuzhiyun }
2006*4882a593Smuzhiyun
f2fs_clear_prefree_segments(struct f2fs_sb_info * sbi,struct cp_control * cpc)2007*4882a593Smuzhiyun void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
2008*4882a593Smuzhiyun struct cp_control *cpc)
2009*4882a593Smuzhiyun {
2010*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
2011*4882a593Smuzhiyun struct list_head *head = &dcc->entry_list;
2012*4882a593Smuzhiyun struct discard_entry *entry, *this;
2013*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
2014*4882a593Smuzhiyun unsigned long *prefree_map = dirty_i->dirty_segmap[PRE];
2015*4882a593Smuzhiyun unsigned int start = 0, end = -1;
2016*4882a593Smuzhiyun unsigned int secno, start_segno;
2017*4882a593Smuzhiyun bool force = (cpc->reason & CP_DISCARD);
2018*4882a593Smuzhiyun bool need_align = f2fs_lfs_mode(sbi) && __is_large_section(sbi);
2019*4882a593Smuzhiyun
2020*4882a593Smuzhiyun mutex_lock(&dirty_i->seglist_lock);
2021*4882a593Smuzhiyun
2022*4882a593Smuzhiyun while (1) {
2023*4882a593Smuzhiyun int i;
2024*4882a593Smuzhiyun
2025*4882a593Smuzhiyun if (need_align && end != -1)
2026*4882a593Smuzhiyun end--;
2027*4882a593Smuzhiyun start = find_next_bit(prefree_map, MAIN_SEGS(sbi), end + 1);
2028*4882a593Smuzhiyun if (start >= MAIN_SEGS(sbi))
2029*4882a593Smuzhiyun break;
2030*4882a593Smuzhiyun end = find_next_zero_bit(prefree_map, MAIN_SEGS(sbi),
2031*4882a593Smuzhiyun start + 1);
2032*4882a593Smuzhiyun
2033*4882a593Smuzhiyun if (need_align) {
2034*4882a593Smuzhiyun start = rounddown(start, sbi->segs_per_sec);
2035*4882a593Smuzhiyun end = roundup(end, sbi->segs_per_sec);
2036*4882a593Smuzhiyun }
2037*4882a593Smuzhiyun
2038*4882a593Smuzhiyun for (i = start; i < end; i++) {
2039*4882a593Smuzhiyun if (test_and_clear_bit(i, prefree_map))
2040*4882a593Smuzhiyun dirty_i->nr_dirty[PRE]--;
2041*4882a593Smuzhiyun }
2042*4882a593Smuzhiyun
2043*4882a593Smuzhiyun if (!f2fs_realtime_discard_enable(sbi))
2044*4882a593Smuzhiyun continue;
2045*4882a593Smuzhiyun
2046*4882a593Smuzhiyun if (force && start >= cpc->trim_start &&
2047*4882a593Smuzhiyun (end - 1) <= cpc->trim_end)
2048*4882a593Smuzhiyun continue;
2049*4882a593Smuzhiyun
2050*4882a593Smuzhiyun if (!f2fs_lfs_mode(sbi) || !__is_large_section(sbi)) {
2051*4882a593Smuzhiyun f2fs_issue_discard(sbi, START_BLOCK(sbi, start),
2052*4882a593Smuzhiyun (end - start) << sbi->log_blocks_per_seg);
2053*4882a593Smuzhiyun continue;
2054*4882a593Smuzhiyun }
2055*4882a593Smuzhiyun next:
2056*4882a593Smuzhiyun secno = GET_SEC_FROM_SEG(sbi, start);
2057*4882a593Smuzhiyun start_segno = GET_SEG_FROM_SEC(sbi, secno);
2058*4882a593Smuzhiyun if (!IS_CURSEC(sbi, secno) &&
2059*4882a593Smuzhiyun !get_valid_blocks(sbi, start, true))
2060*4882a593Smuzhiyun f2fs_issue_discard(sbi, START_BLOCK(sbi, start_segno),
2061*4882a593Smuzhiyun sbi->segs_per_sec << sbi->log_blocks_per_seg);
2062*4882a593Smuzhiyun
2063*4882a593Smuzhiyun start = start_segno + sbi->segs_per_sec;
2064*4882a593Smuzhiyun if (start < end)
2065*4882a593Smuzhiyun goto next;
2066*4882a593Smuzhiyun else
2067*4882a593Smuzhiyun end = start - 1;
2068*4882a593Smuzhiyun }
2069*4882a593Smuzhiyun mutex_unlock(&dirty_i->seglist_lock);
2070*4882a593Smuzhiyun
2071*4882a593Smuzhiyun /* send small discards */
2072*4882a593Smuzhiyun list_for_each_entry_safe(entry, this, head, list) {
2073*4882a593Smuzhiyun unsigned int cur_pos = 0, next_pos, len, total_len = 0;
2074*4882a593Smuzhiyun bool is_valid = test_bit_le(0, entry->discard_map);
2075*4882a593Smuzhiyun
2076*4882a593Smuzhiyun find_next:
2077*4882a593Smuzhiyun if (is_valid) {
2078*4882a593Smuzhiyun next_pos = find_next_zero_bit_le(entry->discard_map,
2079*4882a593Smuzhiyun sbi->blocks_per_seg, cur_pos);
2080*4882a593Smuzhiyun len = next_pos - cur_pos;
2081*4882a593Smuzhiyun
2082*4882a593Smuzhiyun if (f2fs_sb_has_blkzoned(sbi) ||
2083*4882a593Smuzhiyun (force && len < cpc->trim_minlen))
2084*4882a593Smuzhiyun goto skip;
2085*4882a593Smuzhiyun
2086*4882a593Smuzhiyun f2fs_issue_discard(sbi, entry->start_blkaddr + cur_pos,
2087*4882a593Smuzhiyun len);
2088*4882a593Smuzhiyun total_len += len;
2089*4882a593Smuzhiyun } else {
2090*4882a593Smuzhiyun next_pos = find_next_bit_le(entry->discard_map,
2091*4882a593Smuzhiyun sbi->blocks_per_seg, cur_pos);
2092*4882a593Smuzhiyun }
2093*4882a593Smuzhiyun skip:
2094*4882a593Smuzhiyun cur_pos = next_pos;
2095*4882a593Smuzhiyun is_valid = !is_valid;
2096*4882a593Smuzhiyun
2097*4882a593Smuzhiyun if (cur_pos < sbi->blocks_per_seg)
2098*4882a593Smuzhiyun goto find_next;
2099*4882a593Smuzhiyun
2100*4882a593Smuzhiyun release_discard_addr(entry);
2101*4882a593Smuzhiyun dcc->nr_discards -= total_len;
2102*4882a593Smuzhiyun }
2103*4882a593Smuzhiyun
2104*4882a593Smuzhiyun wake_up_discard_thread(sbi, false);
2105*4882a593Smuzhiyun }
2106*4882a593Smuzhiyun
create_discard_cmd_control(struct f2fs_sb_info * sbi)2107*4882a593Smuzhiyun static int create_discard_cmd_control(struct f2fs_sb_info *sbi)
2108*4882a593Smuzhiyun {
2109*4882a593Smuzhiyun dev_t dev = sbi->sb->s_bdev->bd_dev;
2110*4882a593Smuzhiyun struct discard_cmd_control *dcc;
2111*4882a593Smuzhiyun int err = 0, i;
2112*4882a593Smuzhiyun
2113*4882a593Smuzhiyun if (SM_I(sbi)->dcc_info) {
2114*4882a593Smuzhiyun dcc = SM_I(sbi)->dcc_info;
2115*4882a593Smuzhiyun goto init_thread;
2116*4882a593Smuzhiyun }
2117*4882a593Smuzhiyun
2118*4882a593Smuzhiyun dcc = f2fs_kzalloc(sbi, sizeof(struct discard_cmd_control), GFP_KERNEL);
2119*4882a593Smuzhiyun if (!dcc)
2120*4882a593Smuzhiyun return -ENOMEM;
2121*4882a593Smuzhiyun
2122*4882a593Smuzhiyun dcc->discard_granularity = DEFAULT_DISCARD_GRANULARITY;
2123*4882a593Smuzhiyun INIT_LIST_HEAD(&dcc->entry_list);
2124*4882a593Smuzhiyun for (i = 0; i < MAX_PLIST_NUM; i++)
2125*4882a593Smuzhiyun INIT_LIST_HEAD(&dcc->pend_list[i]);
2126*4882a593Smuzhiyun INIT_LIST_HEAD(&dcc->wait_list);
2127*4882a593Smuzhiyun INIT_LIST_HEAD(&dcc->fstrim_list);
2128*4882a593Smuzhiyun mutex_init(&dcc->cmd_lock);
2129*4882a593Smuzhiyun atomic_set(&dcc->issued_discard, 0);
2130*4882a593Smuzhiyun atomic_set(&dcc->queued_discard, 0);
2131*4882a593Smuzhiyun atomic_set(&dcc->discard_cmd_cnt, 0);
2132*4882a593Smuzhiyun dcc->nr_discards = 0;
2133*4882a593Smuzhiyun dcc->max_discards = MAIN_SEGS(sbi) << sbi->log_blocks_per_seg;
2134*4882a593Smuzhiyun dcc->undiscard_blks = 0;
2135*4882a593Smuzhiyun dcc->next_pos = 0;
2136*4882a593Smuzhiyun dcc->root = RB_ROOT_CACHED;
2137*4882a593Smuzhiyun dcc->rbtree_check = false;
2138*4882a593Smuzhiyun
2139*4882a593Smuzhiyun init_waitqueue_head(&dcc->discard_wait_queue);
2140*4882a593Smuzhiyun SM_I(sbi)->dcc_info = dcc;
2141*4882a593Smuzhiyun init_thread:
2142*4882a593Smuzhiyun dcc->f2fs_issue_discard = kthread_run(issue_discard_thread, sbi,
2143*4882a593Smuzhiyun "f2fs_discard-%u:%u", MAJOR(dev), MINOR(dev));
2144*4882a593Smuzhiyun if (IS_ERR(dcc->f2fs_issue_discard)) {
2145*4882a593Smuzhiyun err = PTR_ERR(dcc->f2fs_issue_discard);
2146*4882a593Smuzhiyun kfree(dcc);
2147*4882a593Smuzhiyun SM_I(sbi)->dcc_info = NULL;
2148*4882a593Smuzhiyun return err;
2149*4882a593Smuzhiyun }
2150*4882a593Smuzhiyun
2151*4882a593Smuzhiyun return err;
2152*4882a593Smuzhiyun }
2153*4882a593Smuzhiyun
destroy_discard_cmd_control(struct f2fs_sb_info * sbi)2154*4882a593Smuzhiyun static void destroy_discard_cmd_control(struct f2fs_sb_info *sbi)
2155*4882a593Smuzhiyun {
2156*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
2157*4882a593Smuzhiyun
2158*4882a593Smuzhiyun if (!dcc)
2159*4882a593Smuzhiyun return;
2160*4882a593Smuzhiyun
2161*4882a593Smuzhiyun f2fs_stop_discard_thread(sbi);
2162*4882a593Smuzhiyun
2163*4882a593Smuzhiyun /*
2164*4882a593Smuzhiyun * Recovery can cache discard commands, so in error path of
2165*4882a593Smuzhiyun * fill_super(), it needs to give a chance to handle them.
2166*4882a593Smuzhiyun */
2167*4882a593Smuzhiyun if (unlikely(atomic_read(&dcc->discard_cmd_cnt)))
2168*4882a593Smuzhiyun f2fs_issue_discard_timeout(sbi);
2169*4882a593Smuzhiyun
2170*4882a593Smuzhiyun kfree(dcc);
2171*4882a593Smuzhiyun SM_I(sbi)->dcc_info = NULL;
2172*4882a593Smuzhiyun }
2173*4882a593Smuzhiyun
__mark_sit_entry_dirty(struct f2fs_sb_info * sbi,unsigned int segno)2174*4882a593Smuzhiyun static bool __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno)
2175*4882a593Smuzhiyun {
2176*4882a593Smuzhiyun struct sit_info *sit_i = SIT_I(sbi);
2177*4882a593Smuzhiyun
2178*4882a593Smuzhiyun if (!__test_and_set_bit(segno, sit_i->dirty_sentries_bitmap)) {
2179*4882a593Smuzhiyun sit_i->dirty_sentries++;
2180*4882a593Smuzhiyun return false;
2181*4882a593Smuzhiyun }
2182*4882a593Smuzhiyun
2183*4882a593Smuzhiyun return true;
2184*4882a593Smuzhiyun }
2185*4882a593Smuzhiyun
__set_sit_entry_type(struct f2fs_sb_info * sbi,int type,unsigned int segno,int modified)2186*4882a593Smuzhiyun static void __set_sit_entry_type(struct f2fs_sb_info *sbi, int type,
2187*4882a593Smuzhiyun unsigned int segno, int modified)
2188*4882a593Smuzhiyun {
2189*4882a593Smuzhiyun struct seg_entry *se = get_seg_entry(sbi, segno);
2190*4882a593Smuzhiyun
2191*4882a593Smuzhiyun se->type = type;
2192*4882a593Smuzhiyun if (modified)
2193*4882a593Smuzhiyun __mark_sit_entry_dirty(sbi, segno);
2194*4882a593Smuzhiyun }
2195*4882a593Smuzhiyun
get_segment_mtime(struct f2fs_sb_info * sbi,block_t blkaddr)2196*4882a593Smuzhiyun static inline unsigned long long get_segment_mtime(struct f2fs_sb_info *sbi,
2197*4882a593Smuzhiyun block_t blkaddr)
2198*4882a593Smuzhiyun {
2199*4882a593Smuzhiyun unsigned int segno = GET_SEGNO(sbi, blkaddr);
2200*4882a593Smuzhiyun
2201*4882a593Smuzhiyun if (segno == NULL_SEGNO)
2202*4882a593Smuzhiyun return 0;
2203*4882a593Smuzhiyun return get_seg_entry(sbi, segno)->mtime;
2204*4882a593Smuzhiyun }
2205*4882a593Smuzhiyun
update_segment_mtime(struct f2fs_sb_info * sbi,block_t blkaddr,unsigned long long old_mtime)2206*4882a593Smuzhiyun static void update_segment_mtime(struct f2fs_sb_info *sbi, block_t blkaddr,
2207*4882a593Smuzhiyun unsigned long long old_mtime)
2208*4882a593Smuzhiyun {
2209*4882a593Smuzhiyun struct seg_entry *se;
2210*4882a593Smuzhiyun unsigned int segno = GET_SEGNO(sbi, blkaddr);
2211*4882a593Smuzhiyun unsigned long long ctime = get_mtime(sbi, false);
2212*4882a593Smuzhiyun unsigned long long mtime = old_mtime ? old_mtime : ctime;
2213*4882a593Smuzhiyun
2214*4882a593Smuzhiyun if (segno == NULL_SEGNO)
2215*4882a593Smuzhiyun return;
2216*4882a593Smuzhiyun
2217*4882a593Smuzhiyun se = get_seg_entry(sbi, segno);
2218*4882a593Smuzhiyun
2219*4882a593Smuzhiyun if (!se->mtime)
2220*4882a593Smuzhiyun se->mtime = mtime;
2221*4882a593Smuzhiyun else
2222*4882a593Smuzhiyun se->mtime = div_u64(se->mtime * se->valid_blocks + mtime,
2223*4882a593Smuzhiyun se->valid_blocks + 1);
2224*4882a593Smuzhiyun
2225*4882a593Smuzhiyun if (ctime > SIT_I(sbi)->max_mtime)
2226*4882a593Smuzhiyun SIT_I(sbi)->max_mtime = ctime;
2227*4882a593Smuzhiyun }
2228*4882a593Smuzhiyun
update_sit_entry(struct f2fs_sb_info * sbi,block_t blkaddr,int del)2229*4882a593Smuzhiyun static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
2230*4882a593Smuzhiyun {
2231*4882a593Smuzhiyun struct seg_entry *se;
2232*4882a593Smuzhiyun unsigned int segno, offset;
2233*4882a593Smuzhiyun long int new_vblocks;
2234*4882a593Smuzhiyun bool exist;
2235*4882a593Smuzhiyun #ifdef CONFIG_F2FS_CHECK_FS
2236*4882a593Smuzhiyun bool mir_exist;
2237*4882a593Smuzhiyun #endif
2238*4882a593Smuzhiyun
2239*4882a593Smuzhiyun segno = GET_SEGNO(sbi, blkaddr);
2240*4882a593Smuzhiyun
2241*4882a593Smuzhiyun se = get_seg_entry(sbi, segno);
2242*4882a593Smuzhiyun new_vblocks = se->valid_blocks + del;
2243*4882a593Smuzhiyun offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr);
2244*4882a593Smuzhiyun
2245*4882a593Smuzhiyun f2fs_bug_on(sbi, (new_vblocks < 0 ||
2246*4882a593Smuzhiyun (new_vblocks > f2fs_usable_blks_in_seg(sbi, segno))));
2247*4882a593Smuzhiyun
2248*4882a593Smuzhiyun se->valid_blocks = new_vblocks;
2249*4882a593Smuzhiyun
2250*4882a593Smuzhiyun /* Update valid block bitmap */
2251*4882a593Smuzhiyun if (del > 0) {
2252*4882a593Smuzhiyun exist = f2fs_test_and_set_bit(offset, se->cur_valid_map);
2253*4882a593Smuzhiyun #ifdef CONFIG_F2FS_CHECK_FS
2254*4882a593Smuzhiyun mir_exist = f2fs_test_and_set_bit(offset,
2255*4882a593Smuzhiyun se->cur_valid_map_mir);
2256*4882a593Smuzhiyun if (unlikely(exist != mir_exist)) {
2257*4882a593Smuzhiyun f2fs_err(sbi, "Inconsistent error when setting bitmap, blk:%u, old bit:%d",
2258*4882a593Smuzhiyun blkaddr, exist);
2259*4882a593Smuzhiyun f2fs_bug_on(sbi, 1);
2260*4882a593Smuzhiyun }
2261*4882a593Smuzhiyun #endif
2262*4882a593Smuzhiyun if (unlikely(exist)) {
2263*4882a593Smuzhiyun f2fs_err(sbi, "Bitmap was wrongly set, blk:%u",
2264*4882a593Smuzhiyun blkaddr);
2265*4882a593Smuzhiyun f2fs_bug_on(sbi, 1);
2266*4882a593Smuzhiyun se->valid_blocks--;
2267*4882a593Smuzhiyun del = 0;
2268*4882a593Smuzhiyun }
2269*4882a593Smuzhiyun
2270*4882a593Smuzhiyun if (!f2fs_test_and_set_bit(offset, se->discard_map))
2271*4882a593Smuzhiyun sbi->discard_blks--;
2272*4882a593Smuzhiyun
2273*4882a593Smuzhiyun /*
2274*4882a593Smuzhiyun * SSR should never reuse block which is checkpointed
2275*4882a593Smuzhiyun * or newly invalidated.
2276*4882a593Smuzhiyun */
2277*4882a593Smuzhiyun if (!is_sbi_flag_set(sbi, SBI_CP_DISABLED)) {
2278*4882a593Smuzhiyun if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map))
2279*4882a593Smuzhiyun se->ckpt_valid_blocks++;
2280*4882a593Smuzhiyun }
2281*4882a593Smuzhiyun } else {
2282*4882a593Smuzhiyun exist = f2fs_test_and_clear_bit(offset, se->cur_valid_map);
2283*4882a593Smuzhiyun #ifdef CONFIG_F2FS_CHECK_FS
2284*4882a593Smuzhiyun mir_exist = f2fs_test_and_clear_bit(offset,
2285*4882a593Smuzhiyun se->cur_valid_map_mir);
2286*4882a593Smuzhiyun if (unlikely(exist != mir_exist)) {
2287*4882a593Smuzhiyun f2fs_err(sbi, "Inconsistent error when clearing bitmap, blk:%u, old bit:%d",
2288*4882a593Smuzhiyun blkaddr, exist);
2289*4882a593Smuzhiyun f2fs_bug_on(sbi, 1);
2290*4882a593Smuzhiyun }
2291*4882a593Smuzhiyun #endif
2292*4882a593Smuzhiyun if (unlikely(!exist)) {
2293*4882a593Smuzhiyun f2fs_err(sbi, "Bitmap was wrongly cleared, blk:%u",
2294*4882a593Smuzhiyun blkaddr);
2295*4882a593Smuzhiyun f2fs_bug_on(sbi, 1);
2296*4882a593Smuzhiyun se->valid_blocks++;
2297*4882a593Smuzhiyun del = 0;
2298*4882a593Smuzhiyun } else if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
2299*4882a593Smuzhiyun /*
2300*4882a593Smuzhiyun * If checkpoints are off, we must not reuse data that
2301*4882a593Smuzhiyun * was used in the previous checkpoint. If it was used
2302*4882a593Smuzhiyun * before, we must track that to know how much space we
2303*4882a593Smuzhiyun * really have.
2304*4882a593Smuzhiyun */
2305*4882a593Smuzhiyun if (f2fs_test_bit(offset, se->ckpt_valid_map)) {
2306*4882a593Smuzhiyun spin_lock(&sbi->stat_lock);
2307*4882a593Smuzhiyun sbi->unusable_block_count++;
2308*4882a593Smuzhiyun spin_unlock(&sbi->stat_lock);
2309*4882a593Smuzhiyun }
2310*4882a593Smuzhiyun }
2311*4882a593Smuzhiyun
2312*4882a593Smuzhiyun if (f2fs_test_and_clear_bit(offset, se->discard_map))
2313*4882a593Smuzhiyun sbi->discard_blks++;
2314*4882a593Smuzhiyun }
2315*4882a593Smuzhiyun if (!f2fs_test_bit(offset, se->ckpt_valid_map))
2316*4882a593Smuzhiyun se->ckpt_valid_blocks += del;
2317*4882a593Smuzhiyun
2318*4882a593Smuzhiyun __mark_sit_entry_dirty(sbi, segno);
2319*4882a593Smuzhiyun
2320*4882a593Smuzhiyun /* update total number of valid blocks to be written in ckpt area */
2321*4882a593Smuzhiyun SIT_I(sbi)->written_valid_blocks += del;
2322*4882a593Smuzhiyun
2323*4882a593Smuzhiyun if (__is_large_section(sbi))
2324*4882a593Smuzhiyun get_sec_entry(sbi, segno)->valid_blocks += del;
2325*4882a593Smuzhiyun }
2326*4882a593Smuzhiyun
f2fs_invalidate_blocks(struct f2fs_sb_info * sbi,block_t addr)2327*4882a593Smuzhiyun void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)
2328*4882a593Smuzhiyun {
2329*4882a593Smuzhiyun unsigned int segno = GET_SEGNO(sbi, addr);
2330*4882a593Smuzhiyun struct sit_info *sit_i = SIT_I(sbi);
2331*4882a593Smuzhiyun
2332*4882a593Smuzhiyun f2fs_bug_on(sbi, addr == NULL_ADDR);
2333*4882a593Smuzhiyun if (addr == NEW_ADDR || addr == COMPRESS_ADDR)
2334*4882a593Smuzhiyun return;
2335*4882a593Smuzhiyun
2336*4882a593Smuzhiyun invalidate_mapping_pages(META_MAPPING(sbi), addr, addr);
2337*4882a593Smuzhiyun f2fs_invalidate_compress_page(sbi, addr);
2338*4882a593Smuzhiyun
2339*4882a593Smuzhiyun /* add it into sit main buffer */
2340*4882a593Smuzhiyun down_write(&sit_i->sentry_lock);
2341*4882a593Smuzhiyun
2342*4882a593Smuzhiyun update_segment_mtime(sbi, addr, 0);
2343*4882a593Smuzhiyun update_sit_entry(sbi, addr, -1);
2344*4882a593Smuzhiyun
2345*4882a593Smuzhiyun /* add it into dirty seglist */
2346*4882a593Smuzhiyun locate_dirty_segment(sbi, segno);
2347*4882a593Smuzhiyun
2348*4882a593Smuzhiyun up_write(&sit_i->sentry_lock);
2349*4882a593Smuzhiyun }
2350*4882a593Smuzhiyun
f2fs_is_checkpointed_data(struct f2fs_sb_info * sbi,block_t blkaddr)2351*4882a593Smuzhiyun bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr)
2352*4882a593Smuzhiyun {
2353*4882a593Smuzhiyun struct sit_info *sit_i = SIT_I(sbi);
2354*4882a593Smuzhiyun unsigned int segno, offset;
2355*4882a593Smuzhiyun struct seg_entry *se;
2356*4882a593Smuzhiyun bool is_cp = false;
2357*4882a593Smuzhiyun
2358*4882a593Smuzhiyun if (!__is_valid_data_blkaddr(blkaddr))
2359*4882a593Smuzhiyun return true;
2360*4882a593Smuzhiyun
2361*4882a593Smuzhiyun down_read(&sit_i->sentry_lock);
2362*4882a593Smuzhiyun
2363*4882a593Smuzhiyun segno = GET_SEGNO(sbi, blkaddr);
2364*4882a593Smuzhiyun se = get_seg_entry(sbi, segno);
2365*4882a593Smuzhiyun offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr);
2366*4882a593Smuzhiyun
2367*4882a593Smuzhiyun if (f2fs_test_bit(offset, se->ckpt_valid_map))
2368*4882a593Smuzhiyun is_cp = true;
2369*4882a593Smuzhiyun
2370*4882a593Smuzhiyun up_read(&sit_i->sentry_lock);
2371*4882a593Smuzhiyun
2372*4882a593Smuzhiyun return is_cp;
2373*4882a593Smuzhiyun }
2374*4882a593Smuzhiyun
2375*4882a593Smuzhiyun /*
2376*4882a593Smuzhiyun * This function should be resided under the curseg_mutex lock
2377*4882a593Smuzhiyun */
__add_sum_entry(struct f2fs_sb_info * sbi,int type,struct f2fs_summary * sum)2378*4882a593Smuzhiyun static void __add_sum_entry(struct f2fs_sb_info *sbi, int type,
2379*4882a593Smuzhiyun struct f2fs_summary *sum)
2380*4882a593Smuzhiyun {
2381*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, type);
2382*4882a593Smuzhiyun void *addr = curseg->sum_blk;
2383*4882a593Smuzhiyun
2384*4882a593Smuzhiyun addr += curseg->next_blkoff * sizeof(struct f2fs_summary);
2385*4882a593Smuzhiyun memcpy(addr, sum, sizeof(struct f2fs_summary));
2386*4882a593Smuzhiyun }
2387*4882a593Smuzhiyun
2388*4882a593Smuzhiyun /*
2389*4882a593Smuzhiyun * Calculate the number of current summary pages for writing
2390*4882a593Smuzhiyun */
f2fs_npages_for_summary_flush(struct f2fs_sb_info * sbi,bool for_ra)2391*4882a593Smuzhiyun int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra)
2392*4882a593Smuzhiyun {
2393*4882a593Smuzhiyun int valid_sum_count = 0;
2394*4882a593Smuzhiyun int i, sum_in_page;
2395*4882a593Smuzhiyun
2396*4882a593Smuzhiyun for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
2397*4882a593Smuzhiyun if (sbi->ckpt->alloc_type[i] == SSR)
2398*4882a593Smuzhiyun valid_sum_count += sbi->blocks_per_seg;
2399*4882a593Smuzhiyun else {
2400*4882a593Smuzhiyun if (for_ra)
2401*4882a593Smuzhiyun valid_sum_count += le16_to_cpu(
2402*4882a593Smuzhiyun F2FS_CKPT(sbi)->cur_data_blkoff[i]);
2403*4882a593Smuzhiyun else
2404*4882a593Smuzhiyun valid_sum_count += curseg_blkoff(sbi, i);
2405*4882a593Smuzhiyun }
2406*4882a593Smuzhiyun }
2407*4882a593Smuzhiyun
2408*4882a593Smuzhiyun sum_in_page = (PAGE_SIZE - 2 * SUM_JOURNAL_SIZE -
2409*4882a593Smuzhiyun SUM_FOOTER_SIZE) / SUMMARY_SIZE;
2410*4882a593Smuzhiyun if (valid_sum_count <= sum_in_page)
2411*4882a593Smuzhiyun return 1;
2412*4882a593Smuzhiyun else if ((valid_sum_count - sum_in_page) <=
2413*4882a593Smuzhiyun (PAGE_SIZE - SUM_FOOTER_SIZE) / SUMMARY_SIZE)
2414*4882a593Smuzhiyun return 2;
2415*4882a593Smuzhiyun return 3;
2416*4882a593Smuzhiyun }
2417*4882a593Smuzhiyun
2418*4882a593Smuzhiyun /*
2419*4882a593Smuzhiyun * Caller should put this summary page
2420*4882a593Smuzhiyun */
f2fs_get_sum_page(struct f2fs_sb_info * sbi,unsigned int segno)2421*4882a593Smuzhiyun struct page *f2fs_get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno)
2422*4882a593Smuzhiyun {
2423*4882a593Smuzhiyun if (unlikely(f2fs_cp_error(sbi)))
2424*4882a593Smuzhiyun return ERR_PTR(-EIO);
2425*4882a593Smuzhiyun return f2fs_get_meta_page_retry(sbi, GET_SUM_BLOCK(sbi, segno));
2426*4882a593Smuzhiyun }
2427*4882a593Smuzhiyun
f2fs_update_meta_page(struct f2fs_sb_info * sbi,void * src,block_t blk_addr)2428*4882a593Smuzhiyun void f2fs_update_meta_page(struct f2fs_sb_info *sbi,
2429*4882a593Smuzhiyun void *src, block_t blk_addr)
2430*4882a593Smuzhiyun {
2431*4882a593Smuzhiyun struct page *page = f2fs_grab_meta_page(sbi, blk_addr);
2432*4882a593Smuzhiyun
2433*4882a593Smuzhiyun memcpy(page_address(page), src, PAGE_SIZE);
2434*4882a593Smuzhiyun set_page_dirty(page);
2435*4882a593Smuzhiyun f2fs_put_page(page, 1);
2436*4882a593Smuzhiyun }
2437*4882a593Smuzhiyun
write_sum_page(struct f2fs_sb_info * sbi,struct f2fs_summary_block * sum_blk,block_t blk_addr)2438*4882a593Smuzhiyun static void write_sum_page(struct f2fs_sb_info *sbi,
2439*4882a593Smuzhiyun struct f2fs_summary_block *sum_blk, block_t blk_addr)
2440*4882a593Smuzhiyun {
2441*4882a593Smuzhiyun f2fs_update_meta_page(sbi, (void *)sum_blk, blk_addr);
2442*4882a593Smuzhiyun }
2443*4882a593Smuzhiyun
write_current_sum_page(struct f2fs_sb_info * sbi,int type,block_t blk_addr)2444*4882a593Smuzhiyun static void write_current_sum_page(struct f2fs_sb_info *sbi,
2445*4882a593Smuzhiyun int type, block_t blk_addr)
2446*4882a593Smuzhiyun {
2447*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, type);
2448*4882a593Smuzhiyun struct page *page = f2fs_grab_meta_page(sbi, blk_addr);
2449*4882a593Smuzhiyun struct f2fs_summary_block *src = curseg->sum_blk;
2450*4882a593Smuzhiyun struct f2fs_summary_block *dst;
2451*4882a593Smuzhiyun
2452*4882a593Smuzhiyun dst = (struct f2fs_summary_block *)page_address(page);
2453*4882a593Smuzhiyun memset(dst, 0, PAGE_SIZE);
2454*4882a593Smuzhiyun
2455*4882a593Smuzhiyun mutex_lock(&curseg->curseg_mutex);
2456*4882a593Smuzhiyun
2457*4882a593Smuzhiyun down_read(&curseg->journal_rwsem);
2458*4882a593Smuzhiyun memcpy(&dst->journal, curseg->journal, SUM_JOURNAL_SIZE);
2459*4882a593Smuzhiyun up_read(&curseg->journal_rwsem);
2460*4882a593Smuzhiyun
2461*4882a593Smuzhiyun memcpy(dst->entries, src->entries, SUM_ENTRY_SIZE);
2462*4882a593Smuzhiyun memcpy(&dst->footer, &src->footer, SUM_FOOTER_SIZE);
2463*4882a593Smuzhiyun
2464*4882a593Smuzhiyun mutex_unlock(&curseg->curseg_mutex);
2465*4882a593Smuzhiyun
2466*4882a593Smuzhiyun set_page_dirty(page);
2467*4882a593Smuzhiyun f2fs_put_page(page, 1);
2468*4882a593Smuzhiyun }
2469*4882a593Smuzhiyun
is_next_segment_free(struct f2fs_sb_info * sbi,struct curseg_info * curseg,int type)2470*4882a593Smuzhiyun static int is_next_segment_free(struct f2fs_sb_info *sbi,
2471*4882a593Smuzhiyun struct curseg_info *curseg, int type)
2472*4882a593Smuzhiyun {
2473*4882a593Smuzhiyun unsigned int segno = curseg->segno + 1;
2474*4882a593Smuzhiyun struct free_segmap_info *free_i = FREE_I(sbi);
2475*4882a593Smuzhiyun
2476*4882a593Smuzhiyun if (segno < MAIN_SEGS(sbi) && segno % sbi->segs_per_sec)
2477*4882a593Smuzhiyun return !test_bit(segno, free_i->free_segmap);
2478*4882a593Smuzhiyun return 0;
2479*4882a593Smuzhiyun }
2480*4882a593Smuzhiyun
2481*4882a593Smuzhiyun /*
2482*4882a593Smuzhiyun * Find a new segment from the free segments bitmap to right order
2483*4882a593Smuzhiyun * This function should be returned with success, otherwise BUG
2484*4882a593Smuzhiyun */
get_new_segment(struct f2fs_sb_info * sbi,unsigned int * newseg,bool new_sec,int dir)2485*4882a593Smuzhiyun static void get_new_segment(struct f2fs_sb_info *sbi,
2486*4882a593Smuzhiyun unsigned int *newseg, bool new_sec, int dir)
2487*4882a593Smuzhiyun {
2488*4882a593Smuzhiyun struct free_segmap_info *free_i = FREE_I(sbi);
2489*4882a593Smuzhiyun unsigned int segno, secno, zoneno;
2490*4882a593Smuzhiyun unsigned int total_zones = MAIN_SECS(sbi) / sbi->secs_per_zone;
2491*4882a593Smuzhiyun unsigned int hint = GET_SEC_FROM_SEG(sbi, *newseg);
2492*4882a593Smuzhiyun unsigned int old_zoneno = GET_ZONE_FROM_SEG(sbi, *newseg);
2493*4882a593Smuzhiyun unsigned int left_start = hint;
2494*4882a593Smuzhiyun bool init = true;
2495*4882a593Smuzhiyun int go_left = 0;
2496*4882a593Smuzhiyun int i;
2497*4882a593Smuzhiyun
2498*4882a593Smuzhiyun spin_lock(&free_i->segmap_lock);
2499*4882a593Smuzhiyun
2500*4882a593Smuzhiyun if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) {
2501*4882a593Smuzhiyun segno = find_next_zero_bit(free_i->free_segmap,
2502*4882a593Smuzhiyun GET_SEG_FROM_SEC(sbi, hint + 1), *newseg + 1);
2503*4882a593Smuzhiyun if (segno < GET_SEG_FROM_SEC(sbi, hint + 1))
2504*4882a593Smuzhiyun goto got_it;
2505*4882a593Smuzhiyun }
2506*4882a593Smuzhiyun find_other_zone:
2507*4882a593Smuzhiyun secno = find_next_zero_bit(free_i->free_secmap, MAIN_SECS(sbi), hint);
2508*4882a593Smuzhiyun if (secno >= MAIN_SECS(sbi)) {
2509*4882a593Smuzhiyun if (dir == ALLOC_RIGHT) {
2510*4882a593Smuzhiyun secno = find_next_zero_bit(free_i->free_secmap,
2511*4882a593Smuzhiyun MAIN_SECS(sbi), 0);
2512*4882a593Smuzhiyun f2fs_bug_on(sbi, secno >= MAIN_SECS(sbi));
2513*4882a593Smuzhiyun } else {
2514*4882a593Smuzhiyun go_left = 1;
2515*4882a593Smuzhiyun left_start = hint - 1;
2516*4882a593Smuzhiyun }
2517*4882a593Smuzhiyun }
2518*4882a593Smuzhiyun if (go_left == 0)
2519*4882a593Smuzhiyun goto skip_left;
2520*4882a593Smuzhiyun
2521*4882a593Smuzhiyun while (test_bit(left_start, free_i->free_secmap)) {
2522*4882a593Smuzhiyun if (left_start > 0) {
2523*4882a593Smuzhiyun left_start--;
2524*4882a593Smuzhiyun continue;
2525*4882a593Smuzhiyun }
2526*4882a593Smuzhiyun left_start = find_next_zero_bit(free_i->free_secmap,
2527*4882a593Smuzhiyun MAIN_SECS(sbi), 0);
2528*4882a593Smuzhiyun f2fs_bug_on(sbi, left_start >= MAIN_SECS(sbi));
2529*4882a593Smuzhiyun break;
2530*4882a593Smuzhiyun }
2531*4882a593Smuzhiyun secno = left_start;
2532*4882a593Smuzhiyun skip_left:
2533*4882a593Smuzhiyun segno = GET_SEG_FROM_SEC(sbi, secno);
2534*4882a593Smuzhiyun zoneno = GET_ZONE_FROM_SEC(sbi, secno);
2535*4882a593Smuzhiyun
2536*4882a593Smuzhiyun /* give up on finding another zone */
2537*4882a593Smuzhiyun if (!init)
2538*4882a593Smuzhiyun goto got_it;
2539*4882a593Smuzhiyun if (sbi->secs_per_zone == 1)
2540*4882a593Smuzhiyun goto got_it;
2541*4882a593Smuzhiyun if (zoneno == old_zoneno)
2542*4882a593Smuzhiyun goto got_it;
2543*4882a593Smuzhiyun if (dir == ALLOC_LEFT) {
2544*4882a593Smuzhiyun if (!go_left && zoneno + 1 >= total_zones)
2545*4882a593Smuzhiyun goto got_it;
2546*4882a593Smuzhiyun if (go_left && zoneno == 0)
2547*4882a593Smuzhiyun goto got_it;
2548*4882a593Smuzhiyun }
2549*4882a593Smuzhiyun for (i = 0; i < NR_CURSEG_TYPE; i++)
2550*4882a593Smuzhiyun if (CURSEG_I(sbi, i)->zone == zoneno)
2551*4882a593Smuzhiyun break;
2552*4882a593Smuzhiyun
2553*4882a593Smuzhiyun if (i < NR_CURSEG_TYPE) {
2554*4882a593Smuzhiyun /* zone is in user, try another */
2555*4882a593Smuzhiyun if (go_left)
2556*4882a593Smuzhiyun hint = zoneno * sbi->secs_per_zone - 1;
2557*4882a593Smuzhiyun else if (zoneno + 1 >= total_zones)
2558*4882a593Smuzhiyun hint = 0;
2559*4882a593Smuzhiyun else
2560*4882a593Smuzhiyun hint = (zoneno + 1) * sbi->secs_per_zone;
2561*4882a593Smuzhiyun init = false;
2562*4882a593Smuzhiyun goto find_other_zone;
2563*4882a593Smuzhiyun }
2564*4882a593Smuzhiyun got_it:
2565*4882a593Smuzhiyun /* set it as dirty segment in free segmap */
2566*4882a593Smuzhiyun f2fs_bug_on(sbi, test_bit(segno, free_i->free_segmap));
2567*4882a593Smuzhiyun __set_inuse(sbi, segno);
2568*4882a593Smuzhiyun *newseg = segno;
2569*4882a593Smuzhiyun spin_unlock(&free_i->segmap_lock);
2570*4882a593Smuzhiyun }
2571*4882a593Smuzhiyun
reset_curseg(struct f2fs_sb_info * sbi,int type,int modified)2572*4882a593Smuzhiyun static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified)
2573*4882a593Smuzhiyun {
2574*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, type);
2575*4882a593Smuzhiyun struct summary_footer *sum_footer;
2576*4882a593Smuzhiyun unsigned short seg_type = curseg->seg_type;
2577*4882a593Smuzhiyun
2578*4882a593Smuzhiyun curseg->inited = true;
2579*4882a593Smuzhiyun curseg->segno = curseg->next_segno;
2580*4882a593Smuzhiyun curseg->zone = GET_ZONE_FROM_SEG(sbi, curseg->segno);
2581*4882a593Smuzhiyun curseg->next_blkoff = 0;
2582*4882a593Smuzhiyun curseg->next_segno = NULL_SEGNO;
2583*4882a593Smuzhiyun
2584*4882a593Smuzhiyun sum_footer = &(curseg->sum_blk->footer);
2585*4882a593Smuzhiyun memset(sum_footer, 0, sizeof(struct summary_footer));
2586*4882a593Smuzhiyun
2587*4882a593Smuzhiyun sanity_check_seg_type(sbi, seg_type);
2588*4882a593Smuzhiyun
2589*4882a593Smuzhiyun if (IS_DATASEG(seg_type))
2590*4882a593Smuzhiyun SET_SUM_TYPE(sum_footer, SUM_TYPE_DATA);
2591*4882a593Smuzhiyun if (IS_NODESEG(seg_type))
2592*4882a593Smuzhiyun SET_SUM_TYPE(sum_footer, SUM_TYPE_NODE);
2593*4882a593Smuzhiyun __set_sit_entry_type(sbi, seg_type, curseg->segno, modified);
2594*4882a593Smuzhiyun }
2595*4882a593Smuzhiyun
__get_next_segno(struct f2fs_sb_info * sbi,int type)2596*4882a593Smuzhiyun static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
2597*4882a593Smuzhiyun {
2598*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, type);
2599*4882a593Smuzhiyun unsigned short seg_type = curseg->seg_type;
2600*4882a593Smuzhiyun
2601*4882a593Smuzhiyun sanity_check_seg_type(sbi, seg_type);
2602*4882a593Smuzhiyun
2603*4882a593Smuzhiyun /* if segs_per_sec is large than 1, we need to keep original policy. */
2604*4882a593Smuzhiyun if (__is_large_section(sbi))
2605*4882a593Smuzhiyun return curseg->segno;
2606*4882a593Smuzhiyun
2607*4882a593Smuzhiyun /* inmem log may not locate on any segment after mount */
2608*4882a593Smuzhiyun if (!curseg->inited)
2609*4882a593Smuzhiyun return 0;
2610*4882a593Smuzhiyun
2611*4882a593Smuzhiyun if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
2612*4882a593Smuzhiyun return 0;
2613*4882a593Smuzhiyun
2614*4882a593Smuzhiyun if (test_opt(sbi, NOHEAP) &&
2615*4882a593Smuzhiyun (seg_type == CURSEG_HOT_DATA || IS_NODESEG(seg_type)))
2616*4882a593Smuzhiyun return 0;
2617*4882a593Smuzhiyun
2618*4882a593Smuzhiyun if (SIT_I(sbi)->last_victim[ALLOC_NEXT])
2619*4882a593Smuzhiyun return SIT_I(sbi)->last_victim[ALLOC_NEXT];
2620*4882a593Smuzhiyun
2621*4882a593Smuzhiyun /* find segments from 0 to reuse freed segments */
2622*4882a593Smuzhiyun if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE)
2623*4882a593Smuzhiyun return 0;
2624*4882a593Smuzhiyun
2625*4882a593Smuzhiyun return curseg->segno;
2626*4882a593Smuzhiyun }
2627*4882a593Smuzhiyun
2628*4882a593Smuzhiyun /*
2629*4882a593Smuzhiyun * Allocate a current working segment.
2630*4882a593Smuzhiyun * This function always allocates a free segment in LFS manner.
2631*4882a593Smuzhiyun */
new_curseg(struct f2fs_sb_info * sbi,int type,bool new_sec)2632*4882a593Smuzhiyun static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
2633*4882a593Smuzhiyun {
2634*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, type);
2635*4882a593Smuzhiyun unsigned short seg_type = curseg->seg_type;
2636*4882a593Smuzhiyun unsigned int segno = curseg->segno;
2637*4882a593Smuzhiyun int dir = ALLOC_LEFT;
2638*4882a593Smuzhiyun
2639*4882a593Smuzhiyun if (curseg->inited)
2640*4882a593Smuzhiyun write_sum_page(sbi, curseg->sum_blk,
2641*4882a593Smuzhiyun GET_SUM_BLOCK(sbi, segno));
2642*4882a593Smuzhiyun if (seg_type == CURSEG_WARM_DATA || seg_type == CURSEG_COLD_DATA)
2643*4882a593Smuzhiyun dir = ALLOC_RIGHT;
2644*4882a593Smuzhiyun
2645*4882a593Smuzhiyun if (test_opt(sbi, NOHEAP))
2646*4882a593Smuzhiyun dir = ALLOC_RIGHT;
2647*4882a593Smuzhiyun
2648*4882a593Smuzhiyun segno = __get_next_segno(sbi, type);
2649*4882a593Smuzhiyun get_new_segment(sbi, &segno, new_sec, dir);
2650*4882a593Smuzhiyun curseg->next_segno = segno;
2651*4882a593Smuzhiyun reset_curseg(sbi, type, 1);
2652*4882a593Smuzhiyun curseg->alloc_type = LFS;
2653*4882a593Smuzhiyun }
2654*4882a593Smuzhiyun
__next_free_blkoff(struct f2fs_sb_info * sbi,int segno,block_t start)2655*4882a593Smuzhiyun static int __next_free_blkoff(struct f2fs_sb_info *sbi,
2656*4882a593Smuzhiyun int segno, block_t start)
2657*4882a593Smuzhiyun {
2658*4882a593Smuzhiyun struct seg_entry *se = get_seg_entry(sbi, segno);
2659*4882a593Smuzhiyun int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long);
2660*4882a593Smuzhiyun unsigned long *target_map = SIT_I(sbi)->tmp_map;
2661*4882a593Smuzhiyun unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map;
2662*4882a593Smuzhiyun unsigned long *cur_map = (unsigned long *)se->cur_valid_map;
2663*4882a593Smuzhiyun int i;
2664*4882a593Smuzhiyun
2665*4882a593Smuzhiyun for (i = 0; i < entries; i++)
2666*4882a593Smuzhiyun target_map[i] = ckpt_map[i] | cur_map[i];
2667*4882a593Smuzhiyun
2668*4882a593Smuzhiyun return __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, start);
2669*4882a593Smuzhiyun }
2670*4882a593Smuzhiyun
2671*4882a593Smuzhiyun /*
2672*4882a593Smuzhiyun * If a segment is written by LFS manner, next block offset is just obtained
2673*4882a593Smuzhiyun * by increasing the current block offset. However, if a segment is written by
2674*4882a593Smuzhiyun * SSR manner, next block offset obtained by calling __next_free_blkoff
2675*4882a593Smuzhiyun */
__refresh_next_blkoff(struct f2fs_sb_info * sbi,struct curseg_info * seg)2676*4882a593Smuzhiyun static void __refresh_next_blkoff(struct f2fs_sb_info *sbi,
2677*4882a593Smuzhiyun struct curseg_info *seg)
2678*4882a593Smuzhiyun {
2679*4882a593Smuzhiyun if (seg->alloc_type == SSR)
2680*4882a593Smuzhiyun seg->next_blkoff =
2681*4882a593Smuzhiyun __next_free_blkoff(sbi, seg->segno,
2682*4882a593Smuzhiyun seg->next_blkoff + 1);
2683*4882a593Smuzhiyun else
2684*4882a593Smuzhiyun seg->next_blkoff++;
2685*4882a593Smuzhiyun }
2686*4882a593Smuzhiyun
f2fs_segment_has_free_slot(struct f2fs_sb_info * sbi,int segno)2687*4882a593Smuzhiyun bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno)
2688*4882a593Smuzhiyun {
2689*4882a593Smuzhiyun return __next_free_blkoff(sbi, segno, 0) < sbi->blocks_per_seg;
2690*4882a593Smuzhiyun }
2691*4882a593Smuzhiyun
2692*4882a593Smuzhiyun /*
2693*4882a593Smuzhiyun * This function always allocates a used segment(from dirty seglist) by SSR
2694*4882a593Smuzhiyun * manner, so it should recover the existing segment information of valid blocks
2695*4882a593Smuzhiyun */
change_curseg(struct f2fs_sb_info * sbi,int type,bool flush)2696*4882a593Smuzhiyun static void change_curseg(struct f2fs_sb_info *sbi, int type, bool flush)
2697*4882a593Smuzhiyun {
2698*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
2699*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, type);
2700*4882a593Smuzhiyun unsigned int new_segno = curseg->next_segno;
2701*4882a593Smuzhiyun struct f2fs_summary_block *sum_node;
2702*4882a593Smuzhiyun struct page *sum_page;
2703*4882a593Smuzhiyun
2704*4882a593Smuzhiyun if (flush)
2705*4882a593Smuzhiyun write_sum_page(sbi, curseg->sum_blk,
2706*4882a593Smuzhiyun GET_SUM_BLOCK(sbi, curseg->segno));
2707*4882a593Smuzhiyun
2708*4882a593Smuzhiyun __set_test_and_inuse(sbi, new_segno);
2709*4882a593Smuzhiyun
2710*4882a593Smuzhiyun mutex_lock(&dirty_i->seglist_lock);
2711*4882a593Smuzhiyun __remove_dirty_segment(sbi, new_segno, PRE);
2712*4882a593Smuzhiyun __remove_dirty_segment(sbi, new_segno, DIRTY);
2713*4882a593Smuzhiyun mutex_unlock(&dirty_i->seglist_lock);
2714*4882a593Smuzhiyun
2715*4882a593Smuzhiyun reset_curseg(sbi, type, 1);
2716*4882a593Smuzhiyun curseg->alloc_type = SSR;
2717*4882a593Smuzhiyun curseg->next_blkoff = __next_free_blkoff(sbi, curseg->segno, 0);
2718*4882a593Smuzhiyun
2719*4882a593Smuzhiyun sum_page = f2fs_get_sum_page(sbi, new_segno);
2720*4882a593Smuzhiyun if (IS_ERR(sum_page)) {
2721*4882a593Smuzhiyun /* GC won't be able to use stale summary pages by cp_error */
2722*4882a593Smuzhiyun memset(curseg->sum_blk, 0, SUM_ENTRY_SIZE);
2723*4882a593Smuzhiyun return;
2724*4882a593Smuzhiyun }
2725*4882a593Smuzhiyun sum_node = (struct f2fs_summary_block *)page_address(sum_page);
2726*4882a593Smuzhiyun memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE);
2727*4882a593Smuzhiyun f2fs_put_page(sum_page, 1);
2728*4882a593Smuzhiyun }
2729*4882a593Smuzhiyun
2730*4882a593Smuzhiyun static int get_ssr_segment(struct f2fs_sb_info *sbi, int type,
2731*4882a593Smuzhiyun int alloc_mode, unsigned long long age);
2732*4882a593Smuzhiyun
get_atssr_segment(struct f2fs_sb_info * sbi,int type,int target_type,int alloc_mode,unsigned long long age)2733*4882a593Smuzhiyun static void get_atssr_segment(struct f2fs_sb_info *sbi, int type,
2734*4882a593Smuzhiyun int target_type, int alloc_mode,
2735*4882a593Smuzhiyun unsigned long long age)
2736*4882a593Smuzhiyun {
2737*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, type);
2738*4882a593Smuzhiyun
2739*4882a593Smuzhiyun curseg->seg_type = target_type;
2740*4882a593Smuzhiyun
2741*4882a593Smuzhiyun if (get_ssr_segment(sbi, type, alloc_mode, age)) {
2742*4882a593Smuzhiyun struct seg_entry *se = get_seg_entry(sbi, curseg->next_segno);
2743*4882a593Smuzhiyun
2744*4882a593Smuzhiyun curseg->seg_type = se->type;
2745*4882a593Smuzhiyun change_curseg(sbi, type, true);
2746*4882a593Smuzhiyun } else {
2747*4882a593Smuzhiyun /* allocate cold segment by default */
2748*4882a593Smuzhiyun curseg->seg_type = CURSEG_COLD_DATA;
2749*4882a593Smuzhiyun new_curseg(sbi, type, true);
2750*4882a593Smuzhiyun }
2751*4882a593Smuzhiyun stat_inc_seg_type(sbi, curseg);
2752*4882a593Smuzhiyun }
2753*4882a593Smuzhiyun
__f2fs_init_atgc_curseg(struct f2fs_sb_info * sbi)2754*4882a593Smuzhiyun static void __f2fs_init_atgc_curseg(struct f2fs_sb_info *sbi)
2755*4882a593Smuzhiyun {
2756*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_ALL_DATA_ATGC);
2757*4882a593Smuzhiyun
2758*4882a593Smuzhiyun if (!sbi->am.atgc_enabled)
2759*4882a593Smuzhiyun return;
2760*4882a593Smuzhiyun
2761*4882a593Smuzhiyun f2fs_down_read(&SM_I(sbi)->curseg_lock);
2762*4882a593Smuzhiyun
2763*4882a593Smuzhiyun mutex_lock(&curseg->curseg_mutex);
2764*4882a593Smuzhiyun down_write(&SIT_I(sbi)->sentry_lock);
2765*4882a593Smuzhiyun
2766*4882a593Smuzhiyun get_atssr_segment(sbi, CURSEG_ALL_DATA_ATGC, CURSEG_COLD_DATA, SSR, 0);
2767*4882a593Smuzhiyun
2768*4882a593Smuzhiyun up_write(&SIT_I(sbi)->sentry_lock);
2769*4882a593Smuzhiyun mutex_unlock(&curseg->curseg_mutex);
2770*4882a593Smuzhiyun
2771*4882a593Smuzhiyun f2fs_up_read(&SM_I(sbi)->curseg_lock);
2772*4882a593Smuzhiyun
2773*4882a593Smuzhiyun }
f2fs_init_inmem_curseg(struct f2fs_sb_info * sbi)2774*4882a593Smuzhiyun void f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi)
2775*4882a593Smuzhiyun {
2776*4882a593Smuzhiyun __f2fs_init_atgc_curseg(sbi);
2777*4882a593Smuzhiyun }
2778*4882a593Smuzhiyun
__f2fs_save_inmem_curseg(struct f2fs_sb_info * sbi,int type)2779*4882a593Smuzhiyun static void __f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi, int type)
2780*4882a593Smuzhiyun {
2781*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, type);
2782*4882a593Smuzhiyun
2783*4882a593Smuzhiyun mutex_lock(&curseg->curseg_mutex);
2784*4882a593Smuzhiyun if (!curseg->inited)
2785*4882a593Smuzhiyun goto out;
2786*4882a593Smuzhiyun
2787*4882a593Smuzhiyun if (get_valid_blocks(sbi, curseg->segno, false)) {
2788*4882a593Smuzhiyun write_sum_page(sbi, curseg->sum_blk,
2789*4882a593Smuzhiyun GET_SUM_BLOCK(sbi, curseg->segno));
2790*4882a593Smuzhiyun } else {
2791*4882a593Smuzhiyun mutex_lock(&DIRTY_I(sbi)->seglist_lock);
2792*4882a593Smuzhiyun __set_test_and_free(sbi, curseg->segno, true);
2793*4882a593Smuzhiyun mutex_unlock(&DIRTY_I(sbi)->seglist_lock);
2794*4882a593Smuzhiyun }
2795*4882a593Smuzhiyun out:
2796*4882a593Smuzhiyun mutex_unlock(&curseg->curseg_mutex);
2797*4882a593Smuzhiyun }
2798*4882a593Smuzhiyun
f2fs_save_inmem_curseg(struct f2fs_sb_info * sbi)2799*4882a593Smuzhiyun void f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi)
2800*4882a593Smuzhiyun {
2801*4882a593Smuzhiyun __f2fs_save_inmem_curseg(sbi, CURSEG_COLD_DATA_PINNED);
2802*4882a593Smuzhiyun
2803*4882a593Smuzhiyun if (sbi->am.atgc_enabled)
2804*4882a593Smuzhiyun __f2fs_save_inmem_curseg(sbi, CURSEG_ALL_DATA_ATGC);
2805*4882a593Smuzhiyun }
2806*4882a593Smuzhiyun
__f2fs_restore_inmem_curseg(struct f2fs_sb_info * sbi,int type)2807*4882a593Smuzhiyun static void __f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi, int type)
2808*4882a593Smuzhiyun {
2809*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, type);
2810*4882a593Smuzhiyun
2811*4882a593Smuzhiyun mutex_lock(&curseg->curseg_mutex);
2812*4882a593Smuzhiyun if (!curseg->inited)
2813*4882a593Smuzhiyun goto out;
2814*4882a593Smuzhiyun if (get_valid_blocks(sbi, curseg->segno, false))
2815*4882a593Smuzhiyun goto out;
2816*4882a593Smuzhiyun
2817*4882a593Smuzhiyun mutex_lock(&DIRTY_I(sbi)->seglist_lock);
2818*4882a593Smuzhiyun __set_test_and_inuse(sbi, curseg->segno);
2819*4882a593Smuzhiyun mutex_unlock(&DIRTY_I(sbi)->seglist_lock);
2820*4882a593Smuzhiyun out:
2821*4882a593Smuzhiyun mutex_unlock(&curseg->curseg_mutex);
2822*4882a593Smuzhiyun }
2823*4882a593Smuzhiyun
f2fs_restore_inmem_curseg(struct f2fs_sb_info * sbi)2824*4882a593Smuzhiyun void f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi)
2825*4882a593Smuzhiyun {
2826*4882a593Smuzhiyun __f2fs_restore_inmem_curseg(sbi, CURSEG_COLD_DATA_PINNED);
2827*4882a593Smuzhiyun
2828*4882a593Smuzhiyun if (sbi->am.atgc_enabled)
2829*4882a593Smuzhiyun __f2fs_restore_inmem_curseg(sbi, CURSEG_ALL_DATA_ATGC);
2830*4882a593Smuzhiyun }
2831*4882a593Smuzhiyun
get_ssr_segment(struct f2fs_sb_info * sbi,int type,int alloc_mode,unsigned long long age)2832*4882a593Smuzhiyun static int get_ssr_segment(struct f2fs_sb_info *sbi, int type,
2833*4882a593Smuzhiyun int alloc_mode, unsigned long long age)
2834*4882a593Smuzhiyun {
2835*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, type);
2836*4882a593Smuzhiyun const struct victim_selection *v_ops = DIRTY_I(sbi)->v_ops;
2837*4882a593Smuzhiyun unsigned segno = NULL_SEGNO;
2838*4882a593Smuzhiyun unsigned short seg_type = curseg->seg_type;
2839*4882a593Smuzhiyun int i, cnt;
2840*4882a593Smuzhiyun bool reversed = false;
2841*4882a593Smuzhiyun
2842*4882a593Smuzhiyun sanity_check_seg_type(sbi, seg_type);
2843*4882a593Smuzhiyun
2844*4882a593Smuzhiyun /* f2fs_need_SSR() already forces to do this */
2845*4882a593Smuzhiyun if (!v_ops->get_victim(sbi, &segno, BG_GC, seg_type, alloc_mode, age)) {
2846*4882a593Smuzhiyun curseg->next_segno = segno;
2847*4882a593Smuzhiyun return 1;
2848*4882a593Smuzhiyun }
2849*4882a593Smuzhiyun
2850*4882a593Smuzhiyun /* For node segments, let's do SSR more intensively */
2851*4882a593Smuzhiyun if (IS_NODESEG(seg_type)) {
2852*4882a593Smuzhiyun if (seg_type >= CURSEG_WARM_NODE) {
2853*4882a593Smuzhiyun reversed = true;
2854*4882a593Smuzhiyun i = CURSEG_COLD_NODE;
2855*4882a593Smuzhiyun } else {
2856*4882a593Smuzhiyun i = CURSEG_HOT_NODE;
2857*4882a593Smuzhiyun }
2858*4882a593Smuzhiyun cnt = NR_CURSEG_NODE_TYPE;
2859*4882a593Smuzhiyun } else {
2860*4882a593Smuzhiyun if (seg_type >= CURSEG_WARM_DATA) {
2861*4882a593Smuzhiyun reversed = true;
2862*4882a593Smuzhiyun i = CURSEG_COLD_DATA;
2863*4882a593Smuzhiyun } else {
2864*4882a593Smuzhiyun i = CURSEG_HOT_DATA;
2865*4882a593Smuzhiyun }
2866*4882a593Smuzhiyun cnt = NR_CURSEG_DATA_TYPE;
2867*4882a593Smuzhiyun }
2868*4882a593Smuzhiyun
2869*4882a593Smuzhiyun for (; cnt-- > 0; reversed ? i-- : i++) {
2870*4882a593Smuzhiyun if (i == seg_type)
2871*4882a593Smuzhiyun continue;
2872*4882a593Smuzhiyun if (!v_ops->get_victim(sbi, &segno, BG_GC, i, alloc_mode, age)) {
2873*4882a593Smuzhiyun curseg->next_segno = segno;
2874*4882a593Smuzhiyun return 1;
2875*4882a593Smuzhiyun }
2876*4882a593Smuzhiyun }
2877*4882a593Smuzhiyun
2878*4882a593Smuzhiyun /* find valid_blocks=0 in dirty list */
2879*4882a593Smuzhiyun if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
2880*4882a593Smuzhiyun segno = get_free_segment(sbi);
2881*4882a593Smuzhiyun if (segno != NULL_SEGNO) {
2882*4882a593Smuzhiyun curseg->next_segno = segno;
2883*4882a593Smuzhiyun return 1;
2884*4882a593Smuzhiyun }
2885*4882a593Smuzhiyun }
2886*4882a593Smuzhiyun return 0;
2887*4882a593Smuzhiyun }
2888*4882a593Smuzhiyun
2889*4882a593Smuzhiyun /*
2890*4882a593Smuzhiyun * flush out current segment and replace it with new segment
2891*4882a593Smuzhiyun * This function should be returned with success, otherwise BUG
2892*4882a593Smuzhiyun */
allocate_segment_by_default(struct f2fs_sb_info * sbi,int type,bool force)2893*4882a593Smuzhiyun static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
2894*4882a593Smuzhiyun int type, bool force)
2895*4882a593Smuzhiyun {
2896*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, type);
2897*4882a593Smuzhiyun
2898*4882a593Smuzhiyun if (force)
2899*4882a593Smuzhiyun new_curseg(sbi, type, true);
2900*4882a593Smuzhiyun else if (!is_set_ckpt_flags(sbi, CP_CRC_RECOVERY_FLAG) &&
2901*4882a593Smuzhiyun curseg->seg_type == CURSEG_WARM_NODE)
2902*4882a593Smuzhiyun new_curseg(sbi, type, false);
2903*4882a593Smuzhiyun else if (curseg->alloc_type == LFS &&
2904*4882a593Smuzhiyun is_next_segment_free(sbi, curseg, type) &&
2905*4882a593Smuzhiyun likely(!is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
2906*4882a593Smuzhiyun new_curseg(sbi, type, false);
2907*4882a593Smuzhiyun else if (f2fs_need_SSR(sbi) &&
2908*4882a593Smuzhiyun get_ssr_segment(sbi, type, SSR, 0))
2909*4882a593Smuzhiyun change_curseg(sbi, type, true);
2910*4882a593Smuzhiyun else
2911*4882a593Smuzhiyun new_curseg(sbi, type, false);
2912*4882a593Smuzhiyun
2913*4882a593Smuzhiyun stat_inc_seg_type(sbi, curseg);
2914*4882a593Smuzhiyun }
2915*4882a593Smuzhiyun
f2fs_allocate_segment_for_resize(struct f2fs_sb_info * sbi,int type,unsigned int start,unsigned int end)2916*4882a593Smuzhiyun void f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type,
2917*4882a593Smuzhiyun unsigned int start, unsigned int end)
2918*4882a593Smuzhiyun {
2919*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, type);
2920*4882a593Smuzhiyun unsigned int segno;
2921*4882a593Smuzhiyun
2922*4882a593Smuzhiyun f2fs_down_read(&SM_I(sbi)->curseg_lock);
2923*4882a593Smuzhiyun mutex_lock(&curseg->curseg_mutex);
2924*4882a593Smuzhiyun down_write(&SIT_I(sbi)->sentry_lock);
2925*4882a593Smuzhiyun
2926*4882a593Smuzhiyun segno = CURSEG_I(sbi, type)->segno;
2927*4882a593Smuzhiyun if (segno < start || segno > end)
2928*4882a593Smuzhiyun goto unlock;
2929*4882a593Smuzhiyun
2930*4882a593Smuzhiyun if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type, SSR, 0))
2931*4882a593Smuzhiyun change_curseg(sbi, type, true);
2932*4882a593Smuzhiyun else
2933*4882a593Smuzhiyun new_curseg(sbi, type, true);
2934*4882a593Smuzhiyun
2935*4882a593Smuzhiyun stat_inc_seg_type(sbi, curseg);
2936*4882a593Smuzhiyun
2937*4882a593Smuzhiyun locate_dirty_segment(sbi, segno);
2938*4882a593Smuzhiyun unlock:
2939*4882a593Smuzhiyun up_write(&SIT_I(sbi)->sentry_lock);
2940*4882a593Smuzhiyun
2941*4882a593Smuzhiyun if (segno != curseg->segno)
2942*4882a593Smuzhiyun f2fs_notice(sbi, "For resize: curseg of type %d: %u ==> %u",
2943*4882a593Smuzhiyun type, segno, curseg->segno);
2944*4882a593Smuzhiyun
2945*4882a593Smuzhiyun mutex_unlock(&curseg->curseg_mutex);
2946*4882a593Smuzhiyun f2fs_up_read(&SM_I(sbi)->curseg_lock);
2947*4882a593Smuzhiyun }
2948*4882a593Smuzhiyun
__allocate_new_segment(struct f2fs_sb_info * sbi,int type,bool new_sec,bool force)2949*4882a593Smuzhiyun static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type,
2950*4882a593Smuzhiyun bool new_sec, bool force)
2951*4882a593Smuzhiyun {
2952*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, type);
2953*4882a593Smuzhiyun unsigned int old_segno;
2954*4882a593Smuzhiyun
2955*4882a593Smuzhiyun if (!curseg->inited)
2956*4882a593Smuzhiyun goto alloc;
2957*4882a593Smuzhiyun
2958*4882a593Smuzhiyun if (force || curseg->next_blkoff ||
2959*4882a593Smuzhiyun get_valid_blocks(sbi, curseg->segno, new_sec))
2960*4882a593Smuzhiyun goto alloc;
2961*4882a593Smuzhiyun
2962*4882a593Smuzhiyun if (!get_ckpt_valid_blocks(sbi, curseg->segno, new_sec))
2963*4882a593Smuzhiyun return;
2964*4882a593Smuzhiyun alloc:
2965*4882a593Smuzhiyun old_segno = curseg->segno;
2966*4882a593Smuzhiyun SIT_I(sbi)->s_ops->allocate_segment(sbi, type, true);
2967*4882a593Smuzhiyun locate_dirty_segment(sbi, old_segno);
2968*4882a593Smuzhiyun }
2969*4882a593Smuzhiyun
__allocate_new_section(struct f2fs_sb_info * sbi,int type,bool force)2970*4882a593Smuzhiyun static void __allocate_new_section(struct f2fs_sb_info *sbi,
2971*4882a593Smuzhiyun int type, bool force)
2972*4882a593Smuzhiyun {
2973*4882a593Smuzhiyun __allocate_new_segment(sbi, type, true, force);
2974*4882a593Smuzhiyun }
2975*4882a593Smuzhiyun
f2fs_allocate_new_section(struct f2fs_sb_info * sbi,int type,bool force)2976*4882a593Smuzhiyun void f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force)
2977*4882a593Smuzhiyun {
2978*4882a593Smuzhiyun f2fs_down_read(&SM_I(sbi)->curseg_lock);
2979*4882a593Smuzhiyun down_write(&SIT_I(sbi)->sentry_lock);
2980*4882a593Smuzhiyun __allocate_new_section(sbi, type, force);
2981*4882a593Smuzhiyun up_write(&SIT_I(sbi)->sentry_lock);
2982*4882a593Smuzhiyun f2fs_up_read(&SM_I(sbi)->curseg_lock);
2983*4882a593Smuzhiyun }
2984*4882a593Smuzhiyun
f2fs_allocate_new_segments(struct f2fs_sb_info * sbi)2985*4882a593Smuzhiyun void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi)
2986*4882a593Smuzhiyun {
2987*4882a593Smuzhiyun int i;
2988*4882a593Smuzhiyun
2989*4882a593Smuzhiyun f2fs_down_read(&SM_I(sbi)->curseg_lock);
2990*4882a593Smuzhiyun down_write(&SIT_I(sbi)->sentry_lock);
2991*4882a593Smuzhiyun for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++)
2992*4882a593Smuzhiyun __allocate_new_segment(sbi, i, false, false);
2993*4882a593Smuzhiyun up_write(&SIT_I(sbi)->sentry_lock);
2994*4882a593Smuzhiyun f2fs_up_read(&SM_I(sbi)->curseg_lock);
2995*4882a593Smuzhiyun }
2996*4882a593Smuzhiyun
2997*4882a593Smuzhiyun static const struct segment_allocation default_salloc_ops = {
2998*4882a593Smuzhiyun .allocate_segment = allocate_segment_by_default,
2999*4882a593Smuzhiyun };
3000*4882a593Smuzhiyun
f2fs_exist_trim_candidates(struct f2fs_sb_info * sbi,struct cp_control * cpc)3001*4882a593Smuzhiyun bool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi,
3002*4882a593Smuzhiyun struct cp_control *cpc)
3003*4882a593Smuzhiyun {
3004*4882a593Smuzhiyun __u64 trim_start = cpc->trim_start;
3005*4882a593Smuzhiyun bool has_candidate = false;
3006*4882a593Smuzhiyun
3007*4882a593Smuzhiyun down_write(&SIT_I(sbi)->sentry_lock);
3008*4882a593Smuzhiyun for (; cpc->trim_start <= cpc->trim_end; cpc->trim_start++) {
3009*4882a593Smuzhiyun if (add_discard_addrs(sbi, cpc, true)) {
3010*4882a593Smuzhiyun has_candidate = true;
3011*4882a593Smuzhiyun break;
3012*4882a593Smuzhiyun }
3013*4882a593Smuzhiyun }
3014*4882a593Smuzhiyun up_write(&SIT_I(sbi)->sentry_lock);
3015*4882a593Smuzhiyun
3016*4882a593Smuzhiyun cpc->trim_start = trim_start;
3017*4882a593Smuzhiyun return has_candidate;
3018*4882a593Smuzhiyun }
3019*4882a593Smuzhiyun
__issue_discard_cmd_range(struct f2fs_sb_info * sbi,struct discard_policy * dpolicy,unsigned int start,unsigned int end)3020*4882a593Smuzhiyun static unsigned int __issue_discard_cmd_range(struct f2fs_sb_info *sbi,
3021*4882a593Smuzhiyun struct discard_policy *dpolicy,
3022*4882a593Smuzhiyun unsigned int start, unsigned int end)
3023*4882a593Smuzhiyun {
3024*4882a593Smuzhiyun struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
3025*4882a593Smuzhiyun struct discard_cmd *prev_dc = NULL, *next_dc = NULL;
3026*4882a593Smuzhiyun struct rb_node **insert_p = NULL, *insert_parent = NULL;
3027*4882a593Smuzhiyun struct discard_cmd *dc;
3028*4882a593Smuzhiyun struct blk_plug plug;
3029*4882a593Smuzhiyun int issued;
3030*4882a593Smuzhiyun unsigned int trimmed = 0;
3031*4882a593Smuzhiyun
3032*4882a593Smuzhiyun next:
3033*4882a593Smuzhiyun issued = 0;
3034*4882a593Smuzhiyun
3035*4882a593Smuzhiyun mutex_lock(&dcc->cmd_lock);
3036*4882a593Smuzhiyun if (unlikely(dcc->rbtree_check))
3037*4882a593Smuzhiyun f2fs_bug_on(sbi, !f2fs_check_rb_tree_consistence(sbi,
3038*4882a593Smuzhiyun &dcc->root, false));
3039*4882a593Smuzhiyun
3040*4882a593Smuzhiyun dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root,
3041*4882a593Smuzhiyun NULL, start,
3042*4882a593Smuzhiyun (struct rb_entry **)&prev_dc,
3043*4882a593Smuzhiyun (struct rb_entry **)&next_dc,
3044*4882a593Smuzhiyun &insert_p, &insert_parent, true, NULL);
3045*4882a593Smuzhiyun if (!dc)
3046*4882a593Smuzhiyun dc = next_dc;
3047*4882a593Smuzhiyun
3048*4882a593Smuzhiyun blk_start_plug(&plug);
3049*4882a593Smuzhiyun
3050*4882a593Smuzhiyun while (dc && dc->lstart <= end) {
3051*4882a593Smuzhiyun struct rb_node *node;
3052*4882a593Smuzhiyun int err = 0;
3053*4882a593Smuzhiyun
3054*4882a593Smuzhiyun if (dc->len < dpolicy->granularity)
3055*4882a593Smuzhiyun goto skip;
3056*4882a593Smuzhiyun
3057*4882a593Smuzhiyun if (dc->state != D_PREP) {
3058*4882a593Smuzhiyun list_move_tail(&dc->list, &dcc->fstrim_list);
3059*4882a593Smuzhiyun goto skip;
3060*4882a593Smuzhiyun }
3061*4882a593Smuzhiyun
3062*4882a593Smuzhiyun err = __submit_discard_cmd(sbi, dpolicy, dc, &issued);
3063*4882a593Smuzhiyun
3064*4882a593Smuzhiyun if (issued >= dpolicy->max_requests) {
3065*4882a593Smuzhiyun start = dc->lstart + dc->len;
3066*4882a593Smuzhiyun
3067*4882a593Smuzhiyun if (err)
3068*4882a593Smuzhiyun __remove_discard_cmd(sbi, dc);
3069*4882a593Smuzhiyun
3070*4882a593Smuzhiyun blk_finish_plug(&plug);
3071*4882a593Smuzhiyun mutex_unlock(&dcc->cmd_lock);
3072*4882a593Smuzhiyun trimmed += __wait_all_discard_cmd(sbi, NULL);
3073*4882a593Smuzhiyun congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT);
3074*4882a593Smuzhiyun goto next;
3075*4882a593Smuzhiyun }
3076*4882a593Smuzhiyun skip:
3077*4882a593Smuzhiyun node = rb_next(&dc->rb_node);
3078*4882a593Smuzhiyun if (err)
3079*4882a593Smuzhiyun __remove_discard_cmd(sbi, dc);
3080*4882a593Smuzhiyun dc = rb_entry_safe(node, struct discard_cmd, rb_node);
3081*4882a593Smuzhiyun
3082*4882a593Smuzhiyun if (fatal_signal_pending(current))
3083*4882a593Smuzhiyun break;
3084*4882a593Smuzhiyun }
3085*4882a593Smuzhiyun
3086*4882a593Smuzhiyun blk_finish_plug(&plug);
3087*4882a593Smuzhiyun mutex_unlock(&dcc->cmd_lock);
3088*4882a593Smuzhiyun
3089*4882a593Smuzhiyun return trimmed;
3090*4882a593Smuzhiyun }
3091*4882a593Smuzhiyun
f2fs_trim_fs(struct f2fs_sb_info * sbi,struct fstrim_range * range)3092*4882a593Smuzhiyun int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
3093*4882a593Smuzhiyun {
3094*4882a593Smuzhiyun __u64 start = F2FS_BYTES_TO_BLK(range->start);
3095*4882a593Smuzhiyun __u64 end = start + F2FS_BYTES_TO_BLK(range->len) - 1;
3096*4882a593Smuzhiyun unsigned int start_segno, end_segno;
3097*4882a593Smuzhiyun block_t start_block, end_block;
3098*4882a593Smuzhiyun struct cp_control cpc;
3099*4882a593Smuzhiyun struct discard_policy dpolicy;
3100*4882a593Smuzhiyun unsigned long long trimmed = 0;
3101*4882a593Smuzhiyun int err = 0;
3102*4882a593Smuzhiyun bool need_align = f2fs_lfs_mode(sbi) && __is_large_section(sbi);
3103*4882a593Smuzhiyun
3104*4882a593Smuzhiyun if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize)
3105*4882a593Smuzhiyun return -EINVAL;
3106*4882a593Smuzhiyun
3107*4882a593Smuzhiyun if (end < MAIN_BLKADDR(sbi))
3108*4882a593Smuzhiyun goto out;
3109*4882a593Smuzhiyun
3110*4882a593Smuzhiyun if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) {
3111*4882a593Smuzhiyun f2fs_warn(sbi, "Found FS corruption, run fsck to fix.");
3112*4882a593Smuzhiyun return -EFSCORRUPTED;
3113*4882a593Smuzhiyun }
3114*4882a593Smuzhiyun
3115*4882a593Smuzhiyun /* start/end segment number in main_area */
3116*4882a593Smuzhiyun start_segno = (start <= MAIN_BLKADDR(sbi)) ? 0 : GET_SEGNO(sbi, start);
3117*4882a593Smuzhiyun end_segno = (end >= MAX_BLKADDR(sbi)) ? MAIN_SEGS(sbi) - 1 :
3118*4882a593Smuzhiyun GET_SEGNO(sbi, end);
3119*4882a593Smuzhiyun if (need_align) {
3120*4882a593Smuzhiyun start_segno = rounddown(start_segno, sbi->segs_per_sec);
3121*4882a593Smuzhiyun end_segno = roundup(end_segno + 1, sbi->segs_per_sec) - 1;
3122*4882a593Smuzhiyun }
3123*4882a593Smuzhiyun
3124*4882a593Smuzhiyun cpc.reason = CP_DISCARD;
3125*4882a593Smuzhiyun cpc.trim_minlen = max_t(__u64, 1, F2FS_BYTES_TO_BLK(range->minlen));
3126*4882a593Smuzhiyun cpc.trim_start = start_segno;
3127*4882a593Smuzhiyun cpc.trim_end = end_segno;
3128*4882a593Smuzhiyun
3129*4882a593Smuzhiyun if (sbi->discard_blks == 0)
3130*4882a593Smuzhiyun goto out;
3131*4882a593Smuzhiyun
3132*4882a593Smuzhiyun f2fs_down_write(&sbi->gc_lock);
3133*4882a593Smuzhiyun err = f2fs_write_checkpoint(sbi, &cpc);
3134*4882a593Smuzhiyun f2fs_up_write(&sbi->gc_lock);
3135*4882a593Smuzhiyun if (err)
3136*4882a593Smuzhiyun goto out;
3137*4882a593Smuzhiyun
3138*4882a593Smuzhiyun /*
3139*4882a593Smuzhiyun * We filed discard candidates, but actually we don't need to wait for
3140*4882a593Smuzhiyun * all of them, since they'll be issued in idle time along with runtime
3141*4882a593Smuzhiyun * discard option. User configuration looks like using runtime discard
3142*4882a593Smuzhiyun * or periodic fstrim instead of it.
3143*4882a593Smuzhiyun */
3144*4882a593Smuzhiyun if (f2fs_realtime_discard_enable(sbi))
3145*4882a593Smuzhiyun goto out;
3146*4882a593Smuzhiyun
3147*4882a593Smuzhiyun start_block = START_BLOCK(sbi, start_segno);
3148*4882a593Smuzhiyun end_block = START_BLOCK(sbi, end_segno + 1);
3149*4882a593Smuzhiyun
3150*4882a593Smuzhiyun __init_discard_policy(sbi, &dpolicy, DPOLICY_FSTRIM, cpc.trim_minlen);
3151*4882a593Smuzhiyun trimmed = __issue_discard_cmd_range(sbi, &dpolicy,
3152*4882a593Smuzhiyun start_block, end_block);
3153*4882a593Smuzhiyun
3154*4882a593Smuzhiyun trimmed += __wait_discard_cmd_range(sbi, &dpolicy,
3155*4882a593Smuzhiyun start_block, end_block);
3156*4882a593Smuzhiyun out:
3157*4882a593Smuzhiyun if (!err)
3158*4882a593Smuzhiyun range->len = F2FS_BLK_TO_BYTES(trimmed);
3159*4882a593Smuzhiyun return err;
3160*4882a593Smuzhiyun }
3161*4882a593Smuzhiyun
__has_curseg_space(struct f2fs_sb_info * sbi,struct curseg_info * curseg)3162*4882a593Smuzhiyun static bool __has_curseg_space(struct f2fs_sb_info *sbi,
3163*4882a593Smuzhiyun struct curseg_info *curseg)
3164*4882a593Smuzhiyun {
3165*4882a593Smuzhiyun return curseg->next_blkoff < f2fs_usable_blks_in_seg(sbi,
3166*4882a593Smuzhiyun curseg->segno);
3167*4882a593Smuzhiyun }
3168*4882a593Smuzhiyun
f2fs_rw_hint_to_seg_type(enum rw_hint hint)3169*4882a593Smuzhiyun int f2fs_rw_hint_to_seg_type(enum rw_hint hint)
3170*4882a593Smuzhiyun {
3171*4882a593Smuzhiyun switch (hint) {
3172*4882a593Smuzhiyun case WRITE_LIFE_SHORT:
3173*4882a593Smuzhiyun return CURSEG_HOT_DATA;
3174*4882a593Smuzhiyun case WRITE_LIFE_EXTREME:
3175*4882a593Smuzhiyun return CURSEG_COLD_DATA;
3176*4882a593Smuzhiyun default:
3177*4882a593Smuzhiyun return CURSEG_WARM_DATA;
3178*4882a593Smuzhiyun }
3179*4882a593Smuzhiyun }
3180*4882a593Smuzhiyun
3181*4882a593Smuzhiyun /* This returns write hints for each segment type. This hints will be
3182*4882a593Smuzhiyun * passed down to block layer. There are mapping tables which depend on
3183*4882a593Smuzhiyun * the mount option 'whint_mode'.
3184*4882a593Smuzhiyun *
3185*4882a593Smuzhiyun * 1) whint_mode=off. F2FS only passes down WRITE_LIFE_NOT_SET.
3186*4882a593Smuzhiyun *
3187*4882a593Smuzhiyun * 2) whint_mode=user-based. F2FS tries to pass down hints given by users.
3188*4882a593Smuzhiyun *
3189*4882a593Smuzhiyun * User F2FS Block
3190*4882a593Smuzhiyun * ---- ---- -----
3191*4882a593Smuzhiyun * META WRITE_LIFE_NOT_SET
3192*4882a593Smuzhiyun * HOT_NODE "
3193*4882a593Smuzhiyun * WARM_NODE "
3194*4882a593Smuzhiyun * COLD_NODE "
3195*4882a593Smuzhiyun * ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME
3196*4882a593Smuzhiyun * extension list " "
3197*4882a593Smuzhiyun *
3198*4882a593Smuzhiyun * -- buffered io
3199*4882a593Smuzhiyun * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
3200*4882a593Smuzhiyun * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
3201*4882a593Smuzhiyun * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET
3202*4882a593Smuzhiyun * WRITE_LIFE_NONE " "
3203*4882a593Smuzhiyun * WRITE_LIFE_MEDIUM " "
3204*4882a593Smuzhiyun * WRITE_LIFE_LONG " "
3205*4882a593Smuzhiyun *
3206*4882a593Smuzhiyun * -- direct io
3207*4882a593Smuzhiyun * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
3208*4882a593Smuzhiyun * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
3209*4882a593Smuzhiyun * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET
3210*4882a593Smuzhiyun * WRITE_LIFE_NONE " WRITE_LIFE_NONE
3211*4882a593Smuzhiyun * WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM
3212*4882a593Smuzhiyun * WRITE_LIFE_LONG " WRITE_LIFE_LONG
3213*4882a593Smuzhiyun *
3214*4882a593Smuzhiyun * 3) whint_mode=fs-based. F2FS passes down hints with its policy.
3215*4882a593Smuzhiyun *
3216*4882a593Smuzhiyun * User F2FS Block
3217*4882a593Smuzhiyun * ---- ---- -----
3218*4882a593Smuzhiyun * META WRITE_LIFE_MEDIUM;
3219*4882a593Smuzhiyun * HOT_NODE WRITE_LIFE_NOT_SET
3220*4882a593Smuzhiyun * WARM_NODE "
3221*4882a593Smuzhiyun * COLD_NODE WRITE_LIFE_NONE
3222*4882a593Smuzhiyun * ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME
3223*4882a593Smuzhiyun * extension list " "
3224*4882a593Smuzhiyun *
3225*4882a593Smuzhiyun * -- buffered io
3226*4882a593Smuzhiyun * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
3227*4882a593Smuzhiyun * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
3228*4882a593Smuzhiyun * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_LONG
3229*4882a593Smuzhiyun * WRITE_LIFE_NONE " "
3230*4882a593Smuzhiyun * WRITE_LIFE_MEDIUM " "
3231*4882a593Smuzhiyun * WRITE_LIFE_LONG " "
3232*4882a593Smuzhiyun *
3233*4882a593Smuzhiyun * -- direct io
3234*4882a593Smuzhiyun * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
3235*4882a593Smuzhiyun * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
3236*4882a593Smuzhiyun * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET
3237*4882a593Smuzhiyun * WRITE_LIFE_NONE " WRITE_LIFE_NONE
3238*4882a593Smuzhiyun * WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM
3239*4882a593Smuzhiyun * WRITE_LIFE_LONG " WRITE_LIFE_LONG
3240*4882a593Smuzhiyun */
3241*4882a593Smuzhiyun
f2fs_io_type_to_rw_hint(struct f2fs_sb_info * sbi,enum page_type type,enum temp_type temp)3242*4882a593Smuzhiyun enum rw_hint f2fs_io_type_to_rw_hint(struct f2fs_sb_info *sbi,
3243*4882a593Smuzhiyun enum page_type type, enum temp_type temp)
3244*4882a593Smuzhiyun {
3245*4882a593Smuzhiyun if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_USER) {
3246*4882a593Smuzhiyun if (type == DATA) {
3247*4882a593Smuzhiyun if (temp == WARM)
3248*4882a593Smuzhiyun return WRITE_LIFE_NOT_SET;
3249*4882a593Smuzhiyun else if (temp == HOT)
3250*4882a593Smuzhiyun return WRITE_LIFE_SHORT;
3251*4882a593Smuzhiyun else if (temp == COLD)
3252*4882a593Smuzhiyun return WRITE_LIFE_EXTREME;
3253*4882a593Smuzhiyun } else {
3254*4882a593Smuzhiyun return WRITE_LIFE_NOT_SET;
3255*4882a593Smuzhiyun }
3256*4882a593Smuzhiyun } else if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_FS) {
3257*4882a593Smuzhiyun if (type == DATA) {
3258*4882a593Smuzhiyun if (temp == WARM)
3259*4882a593Smuzhiyun return WRITE_LIFE_LONG;
3260*4882a593Smuzhiyun else if (temp == HOT)
3261*4882a593Smuzhiyun return WRITE_LIFE_SHORT;
3262*4882a593Smuzhiyun else if (temp == COLD)
3263*4882a593Smuzhiyun return WRITE_LIFE_EXTREME;
3264*4882a593Smuzhiyun } else if (type == NODE) {
3265*4882a593Smuzhiyun if (temp == WARM || temp == HOT)
3266*4882a593Smuzhiyun return WRITE_LIFE_NOT_SET;
3267*4882a593Smuzhiyun else if (temp == COLD)
3268*4882a593Smuzhiyun return WRITE_LIFE_NONE;
3269*4882a593Smuzhiyun } else if (type == META) {
3270*4882a593Smuzhiyun return WRITE_LIFE_MEDIUM;
3271*4882a593Smuzhiyun }
3272*4882a593Smuzhiyun }
3273*4882a593Smuzhiyun return WRITE_LIFE_NOT_SET;
3274*4882a593Smuzhiyun }
3275*4882a593Smuzhiyun
__get_segment_type_2(struct f2fs_io_info * fio)3276*4882a593Smuzhiyun static int __get_segment_type_2(struct f2fs_io_info *fio)
3277*4882a593Smuzhiyun {
3278*4882a593Smuzhiyun if (fio->type == DATA)
3279*4882a593Smuzhiyun return CURSEG_HOT_DATA;
3280*4882a593Smuzhiyun else
3281*4882a593Smuzhiyun return CURSEG_HOT_NODE;
3282*4882a593Smuzhiyun }
3283*4882a593Smuzhiyun
__get_segment_type_4(struct f2fs_io_info * fio)3284*4882a593Smuzhiyun static int __get_segment_type_4(struct f2fs_io_info *fio)
3285*4882a593Smuzhiyun {
3286*4882a593Smuzhiyun if (fio->type == DATA) {
3287*4882a593Smuzhiyun struct inode *inode = fio->page->mapping->host;
3288*4882a593Smuzhiyun
3289*4882a593Smuzhiyun if (S_ISDIR(inode->i_mode))
3290*4882a593Smuzhiyun return CURSEG_HOT_DATA;
3291*4882a593Smuzhiyun else
3292*4882a593Smuzhiyun return CURSEG_COLD_DATA;
3293*4882a593Smuzhiyun } else {
3294*4882a593Smuzhiyun if (IS_DNODE(fio->page) && is_cold_node(fio->page))
3295*4882a593Smuzhiyun return CURSEG_WARM_NODE;
3296*4882a593Smuzhiyun else
3297*4882a593Smuzhiyun return CURSEG_COLD_NODE;
3298*4882a593Smuzhiyun }
3299*4882a593Smuzhiyun }
3300*4882a593Smuzhiyun
__get_age_segment_type(struct inode * inode,pgoff_t pgofs)3301*4882a593Smuzhiyun static int __get_age_segment_type(struct inode *inode, pgoff_t pgofs)
3302*4882a593Smuzhiyun {
3303*4882a593Smuzhiyun struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3304*4882a593Smuzhiyun struct extent_info ei = {};
3305*4882a593Smuzhiyun
3306*4882a593Smuzhiyun if (f2fs_lookup_age_extent_cache(inode, pgofs, &ei)) {
3307*4882a593Smuzhiyun if (!ei.age)
3308*4882a593Smuzhiyun return NO_CHECK_TYPE;
3309*4882a593Smuzhiyun if (ei.age <= sbi->hot_data_age_threshold)
3310*4882a593Smuzhiyun return CURSEG_HOT_DATA;
3311*4882a593Smuzhiyun if (ei.age <= sbi->warm_data_age_threshold)
3312*4882a593Smuzhiyun return CURSEG_WARM_DATA;
3313*4882a593Smuzhiyun return CURSEG_COLD_DATA;
3314*4882a593Smuzhiyun }
3315*4882a593Smuzhiyun return NO_CHECK_TYPE;
3316*4882a593Smuzhiyun }
3317*4882a593Smuzhiyun
__get_segment_type_6(struct f2fs_io_info * fio)3318*4882a593Smuzhiyun static int __get_segment_type_6(struct f2fs_io_info *fio)
3319*4882a593Smuzhiyun {
3320*4882a593Smuzhiyun if (fio->type == DATA) {
3321*4882a593Smuzhiyun struct inode *inode = fio->page->mapping->host;
3322*4882a593Smuzhiyun int type;
3323*4882a593Smuzhiyun
3324*4882a593Smuzhiyun if (is_inode_flag_set(inode, FI_ALIGNED_WRITE))
3325*4882a593Smuzhiyun return CURSEG_COLD_DATA_PINNED;
3326*4882a593Smuzhiyun
3327*4882a593Smuzhiyun if (page_private_gcing(fio->page)) {
3328*4882a593Smuzhiyun if (fio->sbi->am.atgc_enabled &&
3329*4882a593Smuzhiyun (fio->io_type == FS_DATA_IO) &&
3330*4882a593Smuzhiyun (fio->sbi->gc_mode != GC_URGENT_HIGH))
3331*4882a593Smuzhiyun return CURSEG_ALL_DATA_ATGC;
3332*4882a593Smuzhiyun else
3333*4882a593Smuzhiyun return CURSEG_COLD_DATA;
3334*4882a593Smuzhiyun }
3335*4882a593Smuzhiyun if (file_is_cold(inode) || f2fs_need_compress_data(inode))
3336*4882a593Smuzhiyun return CURSEG_COLD_DATA;
3337*4882a593Smuzhiyun
3338*4882a593Smuzhiyun type = __get_age_segment_type(inode, fio->page->index);
3339*4882a593Smuzhiyun if (type != NO_CHECK_TYPE)
3340*4882a593Smuzhiyun return type;
3341*4882a593Smuzhiyun
3342*4882a593Smuzhiyun if (file_is_hot(inode) ||
3343*4882a593Smuzhiyun is_inode_flag_set(inode, FI_HOT_DATA) ||
3344*4882a593Smuzhiyun f2fs_is_atomic_file(inode) ||
3345*4882a593Smuzhiyun f2fs_is_volatile_file(inode))
3346*4882a593Smuzhiyun return CURSEG_HOT_DATA;
3347*4882a593Smuzhiyun return f2fs_rw_hint_to_seg_type(inode->i_write_hint);
3348*4882a593Smuzhiyun } else {
3349*4882a593Smuzhiyun if (IS_DNODE(fio->page))
3350*4882a593Smuzhiyun return is_cold_node(fio->page) ? CURSEG_WARM_NODE :
3351*4882a593Smuzhiyun CURSEG_HOT_NODE;
3352*4882a593Smuzhiyun return CURSEG_COLD_NODE;
3353*4882a593Smuzhiyun }
3354*4882a593Smuzhiyun }
3355*4882a593Smuzhiyun
__get_segment_type(struct f2fs_io_info * fio)3356*4882a593Smuzhiyun static int __get_segment_type(struct f2fs_io_info *fio)
3357*4882a593Smuzhiyun {
3358*4882a593Smuzhiyun int type = 0;
3359*4882a593Smuzhiyun
3360*4882a593Smuzhiyun switch (F2FS_OPTION(fio->sbi).active_logs) {
3361*4882a593Smuzhiyun case 2:
3362*4882a593Smuzhiyun type = __get_segment_type_2(fio);
3363*4882a593Smuzhiyun break;
3364*4882a593Smuzhiyun case 4:
3365*4882a593Smuzhiyun type = __get_segment_type_4(fio);
3366*4882a593Smuzhiyun break;
3367*4882a593Smuzhiyun case 6:
3368*4882a593Smuzhiyun type = __get_segment_type_6(fio);
3369*4882a593Smuzhiyun break;
3370*4882a593Smuzhiyun default:
3371*4882a593Smuzhiyun f2fs_bug_on(fio->sbi, true);
3372*4882a593Smuzhiyun }
3373*4882a593Smuzhiyun
3374*4882a593Smuzhiyun if (IS_HOT(type))
3375*4882a593Smuzhiyun fio->temp = HOT;
3376*4882a593Smuzhiyun else if (IS_WARM(type))
3377*4882a593Smuzhiyun fio->temp = WARM;
3378*4882a593Smuzhiyun else
3379*4882a593Smuzhiyun fio->temp = COLD;
3380*4882a593Smuzhiyun return type;
3381*4882a593Smuzhiyun }
3382*4882a593Smuzhiyun
f2fs_allocate_data_block(struct f2fs_sb_info * sbi,struct page * page,block_t old_blkaddr,block_t * new_blkaddr,struct f2fs_summary * sum,int type,struct f2fs_io_info * fio)3383*4882a593Smuzhiyun void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
3384*4882a593Smuzhiyun block_t old_blkaddr, block_t *new_blkaddr,
3385*4882a593Smuzhiyun struct f2fs_summary *sum, int type,
3386*4882a593Smuzhiyun struct f2fs_io_info *fio)
3387*4882a593Smuzhiyun {
3388*4882a593Smuzhiyun struct sit_info *sit_i = SIT_I(sbi);
3389*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, type);
3390*4882a593Smuzhiyun unsigned long long old_mtime;
3391*4882a593Smuzhiyun bool from_gc = (type == CURSEG_ALL_DATA_ATGC);
3392*4882a593Smuzhiyun struct seg_entry *se = NULL;
3393*4882a593Smuzhiyun
3394*4882a593Smuzhiyun f2fs_down_read(&SM_I(sbi)->curseg_lock);
3395*4882a593Smuzhiyun
3396*4882a593Smuzhiyun mutex_lock(&curseg->curseg_mutex);
3397*4882a593Smuzhiyun down_write(&sit_i->sentry_lock);
3398*4882a593Smuzhiyun
3399*4882a593Smuzhiyun if (from_gc) {
3400*4882a593Smuzhiyun f2fs_bug_on(sbi, GET_SEGNO(sbi, old_blkaddr) == NULL_SEGNO);
3401*4882a593Smuzhiyun se = get_seg_entry(sbi, GET_SEGNO(sbi, old_blkaddr));
3402*4882a593Smuzhiyun sanity_check_seg_type(sbi, se->type);
3403*4882a593Smuzhiyun f2fs_bug_on(sbi, IS_NODESEG(se->type));
3404*4882a593Smuzhiyun }
3405*4882a593Smuzhiyun *new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
3406*4882a593Smuzhiyun
3407*4882a593Smuzhiyun f2fs_bug_on(sbi, curseg->next_blkoff >= sbi->blocks_per_seg);
3408*4882a593Smuzhiyun
3409*4882a593Smuzhiyun f2fs_wait_discard_bio(sbi, *new_blkaddr);
3410*4882a593Smuzhiyun
3411*4882a593Smuzhiyun /*
3412*4882a593Smuzhiyun * __add_sum_entry should be resided under the curseg_mutex
3413*4882a593Smuzhiyun * because, this function updates a summary entry in the
3414*4882a593Smuzhiyun * current summary block.
3415*4882a593Smuzhiyun */
3416*4882a593Smuzhiyun __add_sum_entry(sbi, type, sum);
3417*4882a593Smuzhiyun
3418*4882a593Smuzhiyun __refresh_next_blkoff(sbi, curseg);
3419*4882a593Smuzhiyun
3420*4882a593Smuzhiyun stat_inc_block_count(sbi, curseg);
3421*4882a593Smuzhiyun
3422*4882a593Smuzhiyun if (from_gc) {
3423*4882a593Smuzhiyun old_mtime = get_segment_mtime(sbi, old_blkaddr);
3424*4882a593Smuzhiyun } else {
3425*4882a593Smuzhiyun update_segment_mtime(sbi, old_blkaddr, 0);
3426*4882a593Smuzhiyun old_mtime = 0;
3427*4882a593Smuzhiyun }
3428*4882a593Smuzhiyun update_segment_mtime(sbi, *new_blkaddr, old_mtime);
3429*4882a593Smuzhiyun
3430*4882a593Smuzhiyun /*
3431*4882a593Smuzhiyun * SIT information should be updated before segment allocation,
3432*4882a593Smuzhiyun * since SSR needs latest valid block information.
3433*4882a593Smuzhiyun */
3434*4882a593Smuzhiyun update_sit_entry(sbi, *new_blkaddr, 1);
3435*4882a593Smuzhiyun if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)
3436*4882a593Smuzhiyun update_sit_entry(sbi, old_blkaddr, -1);
3437*4882a593Smuzhiyun
3438*4882a593Smuzhiyun if (!__has_curseg_space(sbi, curseg)) {
3439*4882a593Smuzhiyun if (from_gc)
3440*4882a593Smuzhiyun get_atssr_segment(sbi, type, se->type,
3441*4882a593Smuzhiyun AT_SSR, se->mtime);
3442*4882a593Smuzhiyun else
3443*4882a593Smuzhiyun sit_i->s_ops->allocate_segment(sbi, type, false);
3444*4882a593Smuzhiyun }
3445*4882a593Smuzhiyun /*
3446*4882a593Smuzhiyun * segment dirty status should be updated after segment allocation,
3447*4882a593Smuzhiyun * so we just need to update status only one time after previous
3448*4882a593Smuzhiyun * segment being closed.
3449*4882a593Smuzhiyun */
3450*4882a593Smuzhiyun locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
3451*4882a593Smuzhiyun locate_dirty_segment(sbi, GET_SEGNO(sbi, *new_blkaddr));
3452*4882a593Smuzhiyun
3453*4882a593Smuzhiyun if (IS_DATASEG(type))
3454*4882a593Smuzhiyun atomic64_inc(&sbi->allocated_data_blocks);
3455*4882a593Smuzhiyun
3456*4882a593Smuzhiyun up_write(&sit_i->sentry_lock);
3457*4882a593Smuzhiyun
3458*4882a593Smuzhiyun if (page && IS_NODESEG(type)) {
3459*4882a593Smuzhiyun fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg));
3460*4882a593Smuzhiyun
3461*4882a593Smuzhiyun f2fs_inode_chksum_set(sbi, page);
3462*4882a593Smuzhiyun }
3463*4882a593Smuzhiyun
3464*4882a593Smuzhiyun if (fio) {
3465*4882a593Smuzhiyun struct f2fs_bio_info *io;
3466*4882a593Smuzhiyun
3467*4882a593Smuzhiyun if (F2FS_IO_ALIGNED(sbi))
3468*4882a593Smuzhiyun fio->retry = false;
3469*4882a593Smuzhiyun
3470*4882a593Smuzhiyun INIT_LIST_HEAD(&fio->list);
3471*4882a593Smuzhiyun fio->in_list = true;
3472*4882a593Smuzhiyun io = sbi->write_io[fio->type] + fio->temp;
3473*4882a593Smuzhiyun spin_lock(&io->io_lock);
3474*4882a593Smuzhiyun list_add_tail(&fio->list, &io->io_list);
3475*4882a593Smuzhiyun spin_unlock(&io->io_lock);
3476*4882a593Smuzhiyun }
3477*4882a593Smuzhiyun
3478*4882a593Smuzhiyun mutex_unlock(&curseg->curseg_mutex);
3479*4882a593Smuzhiyun
3480*4882a593Smuzhiyun f2fs_up_read(&SM_I(sbi)->curseg_lock);
3481*4882a593Smuzhiyun }
3482*4882a593Smuzhiyun
update_device_state(struct f2fs_io_info * fio)3483*4882a593Smuzhiyun static void update_device_state(struct f2fs_io_info *fio)
3484*4882a593Smuzhiyun {
3485*4882a593Smuzhiyun struct f2fs_sb_info *sbi = fio->sbi;
3486*4882a593Smuzhiyun unsigned int devidx;
3487*4882a593Smuzhiyun
3488*4882a593Smuzhiyun if (!f2fs_is_multi_device(sbi))
3489*4882a593Smuzhiyun return;
3490*4882a593Smuzhiyun
3491*4882a593Smuzhiyun devidx = f2fs_target_device_index(sbi, fio->new_blkaddr);
3492*4882a593Smuzhiyun
3493*4882a593Smuzhiyun /* update device state for fsync */
3494*4882a593Smuzhiyun f2fs_set_dirty_device(sbi, fio->ino, devidx, FLUSH_INO);
3495*4882a593Smuzhiyun
3496*4882a593Smuzhiyun /* update device state for checkpoint */
3497*4882a593Smuzhiyun if (!f2fs_test_bit(devidx, (char *)&sbi->dirty_device)) {
3498*4882a593Smuzhiyun spin_lock(&sbi->dev_lock);
3499*4882a593Smuzhiyun f2fs_set_bit(devidx, (char *)&sbi->dirty_device);
3500*4882a593Smuzhiyun spin_unlock(&sbi->dev_lock);
3501*4882a593Smuzhiyun }
3502*4882a593Smuzhiyun }
3503*4882a593Smuzhiyun
do_write_page(struct f2fs_summary * sum,struct f2fs_io_info * fio)3504*4882a593Smuzhiyun static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
3505*4882a593Smuzhiyun {
3506*4882a593Smuzhiyun int type = __get_segment_type(fio);
3507*4882a593Smuzhiyun bool keep_order = (f2fs_lfs_mode(fio->sbi) && type == CURSEG_COLD_DATA);
3508*4882a593Smuzhiyun
3509*4882a593Smuzhiyun if (keep_order)
3510*4882a593Smuzhiyun f2fs_down_read(&fio->sbi->io_order_lock);
3511*4882a593Smuzhiyun reallocate:
3512*4882a593Smuzhiyun f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
3513*4882a593Smuzhiyun &fio->new_blkaddr, sum, type, fio);
3514*4882a593Smuzhiyun if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO) {
3515*4882a593Smuzhiyun invalidate_mapping_pages(META_MAPPING(fio->sbi),
3516*4882a593Smuzhiyun fio->old_blkaddr, fio->old_blkaddr);
3517*4882a593Smuzhiyun f2fs_invalidate_compress_page(fio->sbi, fio->old_blkaddr);
3518*4882a593Smuzhiyun }
3519*4882a593Smuzhiyun
3520*4882a593Smuzhiyun /* writeout dirty page into bdev */
3521*4882a593Smuzhiyun f2fs_submit_page_write(fio);
3522*4882a593Smuzhiyun if (fio->retry) {
3523*4882a593Smuzhiyun fio->old_blkaddr = fio->new_blkaddr;
3524*4882a593Smuzhiyun goto reallocate;
3525*4882a593Smuzhiyun }
3526*4882a593Smuzhiyun
3527*4882a593Smuzhiyun update_device_state(fio);
3528*4882a593Smuzhiyun
3529*4882a593Smuzhiyun if (keep_order)
3530*4882a593Smuzhiyun f2fs_up_read(&fio->sbi->io_order_lock);
3531*4882a593Smuzhiyun }
3532*4882a593Smuzhiyun
f2fs_do_write_meta_page(struct f2fs_sb_info * sbi,struct page * page,enum iostat_type io_type)3533*4882a593Smuzhiyun void f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page,
3534*4882a593Smuzhiyun enum iostat_type io_type)
3535*4882a593Smuzhiyun {
3536*4882a593Smuzhiyun struct f2fs_io_info fio = {
3537*4882a593Smuzhiyun .sbi = sbi,
3538*4882a593Smuzhiyun .type = META,
3539*4882a593Smuzhiyun .temp = HOT,
3540*4882a593Smuzhiyun .op = REQ_OP_WRITE,
3541*4882a593Smuzhiyun .op_flags = REQ_SYNC | REQ_META | REQ_PRIO,
3542*4882a593Smuzhiyun .old_blkaddr = page->index,
3543*4882a593Smuzhiyun .new_blkaddr = page->index,
3544*4882a593Smuzhiyun .page = page,
3545*4882a593Smuzhiyun .encrypted_page = NULL,
3546*4882a593Smuzhiyun .in_list = false,
3547*4882a593Smuzhiyun };
3548*4882a593Smuzhiyun
3549*4882a593Smuzhiyun if (unlikely(page->index >= MAIN_BLKADDR(sbi)))
3550*4882a593Smuzhiyun fio.op_flags &= ~REQ_META;
3551*4882a593Smuzhiyun
3552*4882a593Smuzhiyun set_page_writeback(page);
3553*4882a593Smuzhiyun ClearPageError(page);
3554*4882a593Smuzhiyun f2fs_submit_page_write(&fio);
3555*4882a593Smuzhiyun
3556*4882a593Smuzhiyun stat_inc_meta_count(sbi, page->index);
3557*4882a593Smuzhiyun f2fs_update_iostat(sbi, io_type, F2FS_BLKSIZE);
3558*4882a593Smuzhiyun }
3559*4882a593Smuzhiyun
f2fs_do_write_node_page(unsigned int nid,struct f2fs_io_info * fio)3560*4882a593Smuzhiyun void f2fs_do_write_node_page(unsigned int nid, struct f2fs_io_info *fio)
3561*4882a593Smuzhiyun {
3562*4882a593Smuzhiyun struct f2fs_summary sum;
3563*4882a593Smuzhiyun
3564*4882a593Smuzhiyun set_summary(&sum, nid, 0, 0);
3565*4882a593Smuzhiyun do_write_page(&sum, fio);
3566*4882a593Smuzhiyun
3567*4882a593Smuzhiyun f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE);
3568*4882a593Smuzhiyun }
3569*4882a593Smuzhiyun
f2fs_outplace_write_data(struct dnode_of_data * dn,struct f2fs_io_info * fio)3570*4882a593Smuzhiyun void f2fs_outplace_write_data(struct dnode_of_data *dn,
3571*4882a593Smuzhiyun struct f2fs_io_info *fio)
3572*4882a593Smuzhiyun {
3573*4882a593Smuzhiyun struct f2fs_sb_info *sbi = fio->sbi;
3574*4882a593Smuzhiyun struct f2fs_summary sum;
3575*4882a593Smuzhiyun
3576*4882a593Smuzhiyun f2fs_bug_on(sbi, dn->data_blkaddr == NULL_ADDR);
3577*4882a593Smuzhiyun if (fio->io_type == FS_DATA_IO || fio->io_type == FS_CP_DATA_IO)
3578*4882a593Smuzhiyun f2fs_update_age_extent_cache(dn);
3579*4882a593Smuzhiyun set_summary(&sum, dn->nid, dn->ofs_in_node, fio->version);
3580*4882a593Smuzhiyun do_write_page(&sum, fio);
3581*4882a593Smuzhiyun f2fs_update_data_blkaddr(dn, fio->new_blkaddr);
3582*4882a593Smuzhiyun
3583*4882a593Smuzhiyun f2fs_update_iostat(sbi, fio->io_type, F2FS_BLKSIZE);
3584*4882a593Smuzhiyun }
3585*4882a593Smuzhiyun
f2fs_inplace_write_data(struct f2fs_io_info * fio)3586*4882a593Smuzhiyun int f2fs_inplace_write_data(struct f2fs_io_info *fio)
3587*4882a593Smuzhiyun {
3588*4882a593Smuzhiyun int err;
3589*4882a593Smuzhiyun struct f2fs_sb_info *sbi = fio->sbi;
3590*4882a593Smuzhiyun unsigned int segno;
3591*4882a593Smuzhiyun
3592*4882a593Smuzhiyun fio->new_blkaddr = fio->old_blkaddr;
3593*4882a593Smuzhiyun /* i/o temperature is needed for passing down write hints */
3594*4882a593Smuzhiyun __get_segment_type(fio);
3595*4882a593Smuzhiyun
3596*4882a593Smuzhiyun segno = GET_SEGNO(sbi, fio->new_blkaddr);
3597*4882a593Smuzhiyun
3598*4882a593Smuzhiyun if (!IS_DATASEG(get_seg_entry(sbi, segno)->type)) {
3599*4882a593Smuzhiyun set_sbi_flag(sbi, SBI_NEED_FSCK);
3600*4882a593Smuzhiyun f2fs_warn(sbi, "%s: incorrect segment(%u) type, run fsck to fix.",
3601*4882a593Smuzhiyun __func__, segno);
3602*4882a593Smuzhiyun err = -EFSCORRUPTED;
3603*4882a593Smuzhiyun goto drop_bio;
3604*4882a593Smuzhiyun }
3605*4882a593Smuzhiyun
3606*4882a593Smuzhiyun if (f2fs_cp_error(sbi)) {
3607*4882a593Smuzhiyun err = -EIO;
3608*4882a593Smuzhiyun goto drop_bio;
3609*4882a593Smuzhiyun }
3610*4882a593Smuzhiyun
3611*4882a593Smuzhiyun if (fio->post_read)
3612*4882a593Smuzhiyun invalidate_mapping_pages(META_MAPPING(sbi),
3613*4882a593Smuzhiyun fio->new_blkaddr, fio->new_blkaddr);
3614*4882a593Smuzhiyun
3615*4882a593Smuzhiyun stat_inc_inplace_blocks(fio->sbi);
3616*4882a593Smuzhiyun
3617*4882a593Smuzhiyun if (fio->bio && !(SM_I(sbi)->ipu_policy & (1 << F2FS_IPU_NOCACHE)))
3618*4882a593Smuzhiyun err = f2fs_merge_page_bio(fio);
3619*4882a593Smuzhiyun else
3620*4882a593Smuzhiyun err = f2fs_submit_page_bio(fio);
3621*4882a593Smuzhiyun if (!err) {
3622*4882a593Smuzhiyun update_device_state(fio);
3623*4882a593Smuzhiyun f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE);
3624*4882a593Smuzhiyun }
3625*4882a593Smuzhiyun
3626*4882a593Smuzhiyun return err;
3627*4882a593Smuzhiyun drop_bio:
3628*4882a593Smuzhiyun if (fio->bio && *(fio->bio)) {
3629*4882a593Smuzhiyun struct bio *bio = *(fio->bio);
3630*4882a593Smuzhiyun
3631*4882a593Smuzhiyun bio->bi_status = BLK_STS_IOERR;
3632*4882a593Smuzhiyun bio_endio(bio);
3633*4882a593Smuzhiyun *(fio->bio) = NULL;
3634*4882a593Smuzhiyun }
3635*4882a593Smuzhiyun return err;
3636*4882a593Smuzhiyun }
3637*4882a593Smuzhiyun
__f2fs_get_curseg(struct f2fs_sb_info * sbi,unsigned int segno)3638*4882a593Smuzhiyun static inline int __f2fs_get_curseg(struct f2fs_sb_info *sbi,
3639*4882a593Smuzhiyun unsigned int segno)
3640*4882a593Smuzhiyun {
3641*4882a593Smuzhiyun int i;
3642*4882a593Smuzhiyun
3643*4882a593Smuzhiyun for (i = CURSEG_HOT_DATA; i < NO_CHECK_TYPE; i++) {
3644*4882a593Smuzhiyun if (CURSEG_I(sbi, i)->segno == segno)
3645*4882a593Smuzhiyun break;
3646*4882a593Smuzhiyun }
3647*4882a593Smuzhiyun return i;
3648*4882a593Smuzhiyun }
3649*4882a593Smuzhiyun
f2fs_do_replace_block(struct f2fs_sb_info * sbi,struct f2fs_summary * sum,block_t old_blkaddr,block_t new_blkaddr,bool recover_curseg,bool recover_newaddr,bool from_gc)3650*4882a593Smuzhiyun void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
3651*4882a593Smuzhiyun block_t old_blkaddr, block_t new_blkaddr,
3652*4882a593Smuzhiyun bool recover_curseg, bool recover_newaddr,
3653*4882a593Smuzhiyun bool from_gc)
3654*4882a593Smuzhiyun {
3655*4882a593Smuzhiyun struct sit_info *sit_i = SIT_I(sbi);
3656*4882a593Smuzhiyun struct curseg_info *curseg;
3657*4882a593Smuzhiyun unsigned int segno, old_cursegno;
3658*4882a593Smuzhiyun struct seg_entry *se;
3659*4882a593Smuzhiyun int type;
3660*4882a593Smuzhiyun unsigned short old_blkoff;
3661*4882a593Smuzhiyun unsigned char old_alloc_type;
3662*4882a593Smuzhiyun
3663*4882a593Smuzhiyun segno = GET_SEGNO(sbi, new_blkaddr);
3664*4882a593Smuzhiyun se = get_seg_entry(sbi, segno);
3665*4882a593Smuzhiyun type = se->type;
3666*4882a593Smuzhiyun
3667*4882a593Smuzhiyun f2fs_down_write(&SM_I(sbi)->curseg_lock);
3668*4882a593Smuzhiyun
3669*4882a593Smuzhiyun if (!recover_curseg) {
3670*4882a593Smuzhiyun /* for recovery flow */
3671*4882a593Smuzhiyun if (se->valid_blocks == 0 && !IS_CURSEG(sbi, segno)) {
3672*4882a593Smuzhiyun if (old_blkaddr == NULL_ADDR)
3673*4882a593Smuzhiyun type = CURSEG_COLD_DATA;
3674*4882a593Smuzhiyun else
3675*4882a593Smuzhiyun type = CURSEG_WARM_DATA;
3676*4882a593Smuzhiyun }
3677*4882a593Smuzhiyun } else {
3678*4882a593Smuzhiyun if (IS_CURSEG(sbi, segno)) {
3679*4882a593Smuzhiyun /* se->type is volatile as SSR allocation */
3680*4882a593Smuzhiyun type = __f2fs_get_curseg(sbi, segno);
3681*4882a593Smuzhiyun f2fs_bug_on(sbi, type == NO_CHECK_TYPE);
3682*4882a593Smuzhiyun } else {
3683*4882a593Smuzhiyun type = CURSEG_WARM_DATA;
3684*4882a593Smuzhiyun }
3685*4882a593Smuzhiyun }
3686*4882a593Smuzhiyun
3687*4882a593Smuzhiyun f2fs_bug_on(sbi, !IS_DATASEG(type));
3688*4882a593Smuzhiyun curseg = CURSEG_I(sbi, type);
3689*4882a593Smuzhiyun
3690*4882a593Smuzhiyun mutex_lock(&curseg->curseg_mutex);
3691*4882a593Smuzhiyun down_write(&sit_i->sentry_lock);
3692*4882a593Smuzhiyun
3693*4882a593Smuzhiyun old_cursegno = curseg->segno;
3694*4882a593Smuzhiyun old_blkoff = curseg->next_blkoff;
3695*4882a593Smuzhiyun old_alloc_type = curseg->alloc_type;
3696*4882a593Smuzhiyun
3697*4882a593Smuzhiyun /* change the current segment */
3698*4882a593Smuzhiyun if (segno != curseg->segno) {
3699*4882a593Smuzhiyun curseg->next_segno = segno;
3700*4882a593Smuzhiyun change_curseg(sbi, type, true);
3701*4882a593Smuzhiyun }
3702*4882a593Smuzhiyun
3703*4882a593Smuzhiyun curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr);
3704*4882a593Smuzhiyun __add_sum_entry(sbi, type, sum);
3705*4882a593Smuzhiyun
3706*4882a593Smuzhiyun if (!recover_curseg || recover_newaddr) {
3707*4882a593Smuzhiyun if (!from_gc)
3708*4882a593Smuzhiyun update_segment_mtime(sbi, new_blkaddr, 0);
3709*4882a593Smuzhiyun update_sit_entry(sbi, new_blkaddr, 1);
3710*4882a593Smuzhiyun }
3711*4882a593Smuzhiyun if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) {
3712*4882a593Smuzhiyun invalidate_mapping_pages(META_MAPPING(sbi),
3713*4882a593Smuzhiyun old_blkaddr, old_blkaddr);
3714*4882a593Smuzhiyun f2fs_invalidate_compress_page(sbi, old_blkaddr);
3715*4882a593Smuzhiyun if (!from_gc)
3716*4882a593Smuzhiyun update_segment_mtime(sbi, old_blkaddr, 0);
3717*4882a593Smuzhiyun update_sit_entry(sbi, old_blkaddr, -1);
3718*4882a593Smuzhiyun }
3719*4882a593Smuzhiyun
3720*4882a593Smuzhiyun locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
3721*4882a593Smuzhiyun locate_dirty_segment(sbi, GET_SEGNO(sbi, new_blkaddr));
3722*4882a593Smuzhiyun
3723*4882a593Smuzhiyun locate_dirty_segment(sbi, old_cursegno);
3724*4882a593Smuzhiyun
3725*4882a593Smuzhiyun if (recover_curseg) {
3726*4882a593Smuzhiyun if (old_cursegno != curseg->segno) {
3727*4882a593Smuzhiyun curseg->next_segno = old_cursegno;
3728*4882a593Smuzhiyun change_curseg(sbi, type, true);
3729*4882a593Smuzhiyun }
3730*4882a593Smuzhiyun curseg->next_blkoff = old_blkoff;
3731*4882a593Smuzhiyun curseg->alloc_type = old_alloc_type;
3732*4882a593Smuzhiyun }
3733*4882a593Smuzhiyun
3734*4882a593Smuzhiyun up_write(&sit_i->sentry_lock);
3735*4882a593Smuzhiyun mutex_unlock(&curseg->curseg_mutex);
3736*4882a593Smuzhiyun f2fs_up_write(&SM_I(sbi)->curseg_lock);
3737*4882a593Smuzhiyun }
3738*4882a593Smuzhiyun
f2fs_replace_block(struct f2fs_sb_info * sbi,struct dnode_of_data * dn,block_t old_addr,block_t new_addr,unsigned char version,bool recover_curseg,bool recover_newaddr)3739*4882a593Smuzhiyun void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
3740*4882a593Smuzhiyun block_t old_addr, block_t new_addr,
3741*4882a593Smuzhiyun unsigned char version, bool recover_curseg,
3742*4882a593Smuzhiyun bool recover_newaddr)
3743*4882a593Smuzhiyun {
3744*4882a593Smuzhiyun struct f2fs_summary sum;
3745*4882a593Smuzhiyun
3746*4882a593Smuzhiyun set_summary(&sum, dn->nid, dn->ofs_in_node, version);
3747*4882a593Smuzhiyun
3748*4882a593Smuzhiyun f2fs_do_replace_block(sbi, &sum, old_addr, new_addr,
3749*4882a593Smuzhiyun recover_curseg, recover_newaddr, false);
3750*4882a593Smuzhiyun
3751*4882a593Smuzhiyun f2fs_update_data_blkaddr(dn, new_addr);
3752*4882a593Smuzhiyun }
3753*4882a593Smuzhiyun
f2fs_wait_on_page_writeback(struct page * page,enum page_type type,bool ordered,bool locked)3754*4882a593Smuzhiyun void f2fs_wait_on_page_writeback(struct page *page,
3755*4882a593Smuzhiyun enum page_type type, bool ordered, bool locked)
3756*4882a593Smuzhiyun {
3757*4882a593Smuzhiyun if (PageWriteback(page)) {
3758*4882a593Smuzhiyun struct f2fs_sb_info *sbi = F2FS_P_SB(page);
3759*4882a593Smuzhiyun
3760*4882a593Smuzhiyun /* submit cached LFS IO */
3761*4882a593Smuzhiyun f2fs_submit_merged_write_cond(sbi, NULL, page, 0, type);
3762*4882a593Smuzhiyun /* sbumit cached IPU IO */
3763*4882a593Smuzhiyun f2fs_submit_merged_ipu_write(sbi, NULL, page);
3764*4882a593Smuzhiyun if (ordered) {
3765*4882a593Smuzhiyun wait_on_page_writeback(page);
3766*4882a593Smuzhiyun f2fs_bug_on(sbi, locked && PageWriteback(page));
3767*4882a593Smuzhiyun } else {
3768*4882a593Smuzhiyun wait_for_stable_page(page);
3769*4882a593Smuzhiyun }
3770*4882a593Smuzhiyun }
3771*4882a593Smuzhiyun }
3772*4882a593Smuzhiyun
f2fs_wait_on_block_writeback(struct inode * inode,block_t blkaddr)3773*4882a593Smuzhiyun void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr)
3774*4882a593Smuzhiyun {
3775*4882a593Smuzhiyun struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3776*4882a593Smuzhiyun struct page *cpage;
3777*4882a593Smuzhiyun
3778*4882a593Smuzhiyun if (!f2fs_post_read_required(inode))
3779*4882a593Smuzhiyun return;
3780*4882a593Smuzhiyun
3781*4882a593Smuzhiyun if (!__is_valid_data_blkaddr(blkaddr))
3782*4882a593Smuzhiyun return;
3783*4882a593Smuzhiyun
3784*4882a593Smuzhiyun cpage = find_lock_page(META_MAPPING(sbi), blkaddr);
3785*4882a593Smuzhiyun if (cpage) {
3786*4882a593Smuzhiyun f2fs_wait_on_page_writeback(cpage, DATA, true, true);
3787*4882a593Smuzhiyun f2fs_put_page(cpage, 1);
3788*4882a593Smuzhiyun }
3789*4882a593Smuzhiyun }
3790*4882a593Smuzhiyun
f2fs_wait_on_block_writeback_range(struct inode * inode,block_t blkaddr,block_t len)3791*4882a593Smuzhiyun void f2fs_wait_on_block_writeback_range(struct inode *inode, block_t blkaddr,
3792*4882a593Smuzhiyun block_t len)
3793*4882a593Smuzhiyun {
3794*4882a593Smuzhiyun struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3795*4882a593Smuzhiyun block_t i;
3796*4882a593Smuzhiyun
3797*4882a593Smuzhiyun if (!f2fs_post_read_required(inode))
3798*4882a593Smuzhiyun return;
3799*4882a593Smuzhiyun
3800*4882a593Smuzhiyun for (i = 0; i < len; i++)
3801*4882a593Smuzhiyun f2fs_wait_on_block_writeback(inode, blkaddr + i);
3802*4882a593Smuzhiyun
3803*4882a593Smuzhiyun invalidate_mapping_pages(META_MAPPING(sbi), blkaddr, blkaddr + len - 1);
3804*4882a593Smuzhiyun }
3805*4882a593Smuzhiyun
read_compacted_summaries(struct f2fs_sb_info * sbi)3806*4882a593Smuzhiyun static int read_compacted_summaries(struct f2fs_sb_info *sbi)
3807*4882a593Smuzhiyun {
3808*4882a593Smuzhiyun struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
3809*4882a593Smuzhiyun struct curseg_info *seg_i;
3810*4882a593Smuzhiyun unsigned char *kaddr;
3811*4882a593Smuzhiyun struct page *page;
3812*4882a593Smuzhiyun block_t start;
3813*4882a593Smuzhiyun int i, j, offset;
3814*4882a593Smuzhiyun
3815*4882a593Smuzhiyun start = start_sum_block(sbi);
3816*4882a593Smuzhiyun
3817*4882a593Smuzhiyun page = f2fs_get_meta_page(sbi, start++);
3818*4882a593Smuzhiyun if (IS_ERR(page))
3819*4882a593Smuzhiyun return PTR_ERR(page);
3820*4882a593Smuzhiyun kaddr = (unsigned char *)page_address(page);
3821*4882a593Smuzhiyun
3822*4882a593Smuzhiyun /* Step 1: restore nat cache */
3823*4882a593Smuzhiyun seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA);
3824*4882a593Smuzhiyun memcpy(seg_i->journal, kaddr, SUM_JOURNAL_SIZE);
3825*4882a593Smuzhiyun
3826*4882a593Smuzhiyun /* Step 2: restore sit cache */
3827*4882a593Smuzhiyun seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA);
3828*4882a593Smuzhiyun memcpy(seg_i->journal, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE);
3829*4882a593Smuzhiyun offset = 2 * SUM_JOURNAL_SIZE;
3830*4882a593Smuzhiyun
3831*4882a593Smuzhiyun /* Step 3: restore summary entries */
3832*4882a593Smuzhiyun for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
3833*4882a593Smuzhiyun unsigned short blk_off;
3834*4882a593Smuzhiyun unsigned int segno;
3835*4882a593Smuzhiyun
3836*4882a593Smuzhiyun seg_i = CURSEG_I(sbi, i);
3837*4882a593Smuzhiyun segno = le32_to_cpu(ckpt->cur_data_segno[i]);
3838*4882a593Smuzhiyun blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]);
3839*4882a593Smuzhiyun seg_i->next_segno = segno;
3840*4882a593Smuzhiyun reset_curseg(sbi, i, 0);
3841*4882a593Smuzhiyun seg_i->alloc_type = ckpt->alloc_type[i];
3842*4882a593Smuzhiyun seg_i->next_blkoff = blk_off;
3843*4882a593Smuzhiyun
3844*4882a593Smuzhiyun if (seg_i->alloc_type == SSR)
3845*4882a593Smuzhiyun blk_off = sbi->blocks_per_seg;
3846*4882a593Smuzhiyun
3847*4882a593Smuzhiyun for (j = 0; j < blk_off; j++) {
3848*4882a593Smuzhiyun struct f2fs_summary *s;
3849*4882a593Smuzhiyun
3850*4882a593Smuzhiyun s = (struct f2fs_summary *)(kaddr + offset);
3851*4882a593Smuzhiyun seg_i->sum_blk->entries[j] = *s;
3852*4882a593Smuzhiyun offset += SUMMARY_SIZE;
3853*4882a593Smuzhiyun if (offset + SUMMARY_SIZE <= PAGE_SIZE -
3854*4882a593Smuzhiyun SUM_FOOTER_SIZE)
3855*4882a593Smuzhiyun continue;
3856*4882a593Smuzhiyun
3857*4882a593Smuzhiyun f2fs_put_page(page, 1);
3858*4882a593Smuzhiyun page = NULL;
3859*4882a593Smuzhiyun
3860*4882a593Smuzhiyun page = f2fs_get_meta_page(sbi, start++);
3861*4882a593Smuzhiyun if (IS_ERR(page))
3862*4882a593Smuzhiyun return PTR_ERR(page);
3863*4882a593Smuzhiyun kaddr = (unsigned char *)page_address(page);
3864*4882a593Smuzhiyun offset = 0;
3865*4882a593Smuzhiyun }
3866*4882a593Smuzhiyun }
3867*4882a593Smuzhiyun f2fs_put_page(page, 1);
3868*4882a593Smuzhiyun return 0;
3869*4882a593Smuzhiyun }
3870*4882a593Smuzhiyun
read_normal_summaries(struct f2fs_sb_info * sbi,int type)3871*4882a593Smuzhiyun static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
3872*4882a593Smuzhiyun {
3873*4882a593Smuzhiyun struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
3874*4882a593Smuzhiyun struct f2fs_summary_block *sum;
3875*4882a593Smuzhiyun struct curseg_info *curseg;
3876*4882a593Smuzhiyun struct page *new;
3877*4882a593Smuzhiyun unsigned short blk_off;
3878*4882a593Smuzhiyun unsigned int segno = 0;
3879*4882a593Smuzhiyun block_t blk_addr = 0;
3880*4882a593Smuzhiyun int err = 0;
3881*4882a593Smuzhiyun
3882*4882a593Smuzhiyun /* get segment number and block addr */
3883*4882a593Smuzhiyun if (IS_DATASEG(type)) {
3884*4882a593Smuzhiyun segno = le32_to_cpu(ckpt->cur_data_segno[type]);
3885*4882a593Smuzhiyun blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type -
3886*4882a593Smuzhiyun CURSEG_HOT_DATA]);
3887*4882a593Smuzhiyun if (__exist_node_summaries(sbi))
3888*4882a593Smuzhiyun blk_addr = sum_blk_addr(sbi, NR_CURSEG_PERSIST_TYPE, type);
3889*4882a593Smuzhiyun else
3890*4882a593Smuzhiyun blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type);
3891*4882a593Smuzhiyun } else {
3892*4882a593Smuzhiyun segno = le32_to_cpu(ckpt->cur_node_segno[type -
3893*4882a593Smuzhiyun CURSEG_HOT_NODE]);
3894*4882a593Smuzhiyun blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type -
3895*4882a593Smuzhiyun CURSEG_HOT_NODE]);
3896*4882a593Smuzhiyun if (__exist_node_summaries(sbi))
3897*4882a593Smuzhiyun blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE,
3898*4882a593Smuzhiyun type - CURSEG_HOT_NODE);
3899*4882a593Smuzhiyun else
3900*4882a593Smuzhiyun blk_addr = GET_SUM_BLOCK(sbi, segno);
3901*4882a593Smuzhiyun }
3902*4882a593Smuzhiyun
3903*4882a593Smuzhiyun new = f2fs_get_meta_page(sbi, blk_addr);
3904*4882a593Smuzhiyun if (IS_ERR(new))
3905*4882a593Smuzhiyun return PTR_ERR(new);
3906*4882a593Smuzhiyun sum = (struct f2fs_summary_block *)page_address(new);
3907*4882a593Smuzhiyun
3908*4882a593Smuzhiyun if (IS_NODESEG(type)) {
3909*4882a593Smuzhiyun if (__exist_node_summaries(sbi)) {
3910*4882a593Smuzhiyun struct f2fs_summary *ns = &sum->entries[0];
3911*4882a593Smuzhiyun int i;
3912*4882a593Smuzhiyun
3913*4882a593Smuzhiyun for (i = 0; i < sbi->blocks_per_seg; i++, ns++) {
3914*4882a593Smuzhiyun ns->version = 0;
3915*4882a593Smuzhiyun ns->ofs_in_node = 0;
3916*4882a593Smuzhiyun }
3917*4882a593Smuzhiyun } else {
3918*4882a593Smuzhiyun err = f2fs_restore_node_summary(sbi, segno, sum);
3919*4882a593Smuzhiyun if (err)
3920*4882a593Smuzhiyun goto out;
3921*4882a593Smuzhiyun }
3922*4882a593Smuzhiyun }
3923*4882a593Smuzhiyun
3924*4882a593Smuzhiyun /* set uncompleted segment to curseg */
3925*4882a593Smuzhiyun curseg = CURSEG_I(sbi, type);
3926*4882a593Smuzhiyun mutex_lock(&curseg->curseg_mutex);
3927*4882a593Smuzhiyun
3928*4882a593Smuzhiyun /* update journal info */
3929*4882a593Smuzhiyun down_write(&curseg->journal_rwsem);
3930*4882a593Smuzhiyun memcpy(curseg->journal, &sum->journal, SUM_JOURNAL_SIZE);
3931*4882a593Smuzhiyun up_write(&curseg->journal_rwsem);
3932*4882a593Smuzhiyun
3933*4882a593Smuzhiyun memcpy(curseg->sum_blk->entries, sum->entries, SUM_ENTRY_SIZE);
3934*4882a593Smuzhiyun memcpy(&curseg->sum_blk->footer, &sum->footer, SUM_FOOTER_SIZE);
3935*4882a593Smuzhiyun curseg->next_segno = segno;
3936*4882a593Smuzhiyun reset_curseg(sbi, type, 0);
3937*4882a593Smuzhiyun curseg->alloc_type = ckpt->alloc_type[type];
3938*4882a593Smuzhiyun curseg->next_blkoff = blk_off;
3939*4882a593Smuzhiyun mutex_unlock(&curseg->curseg_mutex);
3940*4882a593Smuzhiyun out:
3941*4882a593Smuzhiyun f2fs_put_page(new, 1);
3942*4882a593Smuzhiyun return err;
3943*4882a593Smuzhiyun }
3944*4882a593Smuzhiyun
restore_curseg_summaries(struct f2fs_sb_info * sbi)3945*4882a593Smuzhiyun static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
3946*4882a593Smuzhiyun {
3947*4882a593Smuzhiyun struct f2fs_journal *sit_j = CURSEG_I(sbi, CURSEG_COLD_DATA)->journal;
3948*4882a593Smuzhiyun struct f2fs_journal *nat_j = CURSEG_I(sbi, CURSEG_HOT_DATA)->journal;
3949*4882a593Smuzhiyun int type = CURSEG_HOT_DATA;
3950*4882a593Smuzhiyun int err;
3951*4882a593Smuzhiyun
3952*4882a593Smuzhiyun if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG)) {
3953*4882a593Smuzhiyun int npages = f2fs_npages_for_summary_flush(sbi, true);
3954*4882a593Smuzhiyun
3955*4882a593Smuzhiyun if (npages >= 2)
3956*4882a593Smuzhiyun f2fs_ra_meta_pages(sbi, start_sum_block(sbi), npages,
3957*4882a593Smuzhiyun META_CP, true);
3958*4882a593Smuzhiyun
3959*4882a593Smuzhiyun /* restore for compacted data summary */
3960*4882a593Smuzhiyun err = read_compacted_summaries(sbi);
3961*4882a593Smuzhiyun if (err)
3962*4882a593Smuzhiyun return err;
3963*4882a593Smuzhiyun type = CURSEG_HOT_NODE;
3964*4882a593Smuzhiyun }
3965*4882a593Smuzhiyun
3966*4882a593Smuzhiyun if (__exist_node_summaries(sbi))
3967*4882a593Smuzhiyun f2fs_ra_meta_pages(sbi,
3968*4882a593Smuzhiyun sum_blk_addr(sbi, NR_CURSEG_PERSIST_TYPE, type),
3969*4882a593Smuzhiyun NR_CURSEG_PERSIST_TYPE - type, META_CP, true);
3970*4882a593Smuzhiyun
3971*4882a593Smuzhiyun for (; type <= CURSEG_COLD_NODE; type++) {
3972*4882a593Smuzhiyun err = read_normal_summaries(sbi, type);
3973*4882a593Smuzhiyun if (err)
3974*4882a593Smuzhiyun return err;
3975*4882a593Smuzhiyun }
3976*4882a593Smuzhiyun
3977*4882a593Smuzhiyun /* sanity check for summary blocks */
3978*4882a593Smuzhiyun if (nats_in_cursum(nat_j) > NAT_JOURNAL_ENTRIES ||
3979*4882a593Smuzhiyun sits_in_cursum(sit_j) > SIT_JOURNAL_ENTRIES) {
3980*4882a593Smuzhiyun f2fs_err(sbi, "invalid journal entries nats %u sits %u",
3981*4882a593Smuzhiyun nats_in_cursum(nat_j), sits_in_cursum(sit_j));
3982*4882a593Smuzhiyun return -EINVAL;
3983*4882a593Smuzhiyun }
3984*4882a593Smuzhiyun
3985*4882a593Smuzhiyun return 0;
3986*4882a593Smuzhiyun }
3987*4882a593Smuzhiyun
write_compacted_summaries(struct f2fs_sb_info * sbi,block_t blkaddr)3988*4882a593Smuzhiyun static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr)
3989*4882a593Smuzhiyun {
3990*4882a593Smuzhiyun struct page *page;
3991*4882a593Smuzhiyun unsigned char *kaddr;
3992*4882a593Smuzhiyun struct f2fs_summary *summary;
3993*4882a593Smuzhiyun struct curseg_info *seg_i;
3994*4882a593Smuzhiyun int written_size = 0;
3995*4882a593Smuzhiyun int i, j;
3996*4882a593Smuzhiyun
3997*4882a593Smuzhiyun page = f2fs_grab_meta_page(sbi, blkaddr++);
3998*4882a593Smuzhiyun kaddr = (unsigned char *)page_address(page);
3999*4882a593Smuzhiyun memset(kaddr, 0, PAGE_SIZE);
4000*4882a593Smuzhiyun
4001*4882a593Smuzhiyun /* Step 1: write nat cache */
4002*4882a593Smuzhiyun seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA);
4003*4882a593Smuzhiyun memcpy(kaddr, seg_i->journal, SUM_JOURNAL_SIZE);
4004*4882a593Smuzhiyun written_size += SUM_JOURNAL_SIZE;
4005*4882a593Smuzhiyun
4006*4882a593Smuzhiyun /* Step 2: write sit cache */
4007*4882a593Smuzhiyun seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA);
4008*4882a593Smuzhiyun memcpy(kaddr + written_size, seg_i->journal, SUM_JOURNAL_SIZE);
4009*4882a593Smuzhiyun written_size += SUM_JOURNAL_SIZE;
4010*4882a593Smuzhiyun
4011*4882a593Smuzhiyun /* Step 3: write summary entries */
4012*4882a593Smuzhiyun for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
4013*4882a593Smuzhiyun unsigned short blkoff;
4014*4882a593Smuzhiyun
4015*4882a593Smuzhiyun seg_i = CURSEG_I(sbi, i);
4016*4882a593Smuzhiyun if (sbi->ckpt->alloc_type[i] == SSR)
4017*4882a593Smuzhiyun blkoff = sbi->blocks_per_seg;
4018*4882a593Smuzhiyun else
4019*4882a593Smuzhiyun blkoff = curseg_blkoff(sbi, i);
4020*4882a593Smuzhiyun
4021*4882a593Smuzhiyun for (j = 0; j < blkoff; j++) {
4022*4882a593Smuzhiyun if (!page) {
4023*4882a593Smuzhiyun page = f2fs_grab_meta_page(sbi, blkaddr++);
4024*4882a593Smuzhiyun kaddr = (unsigned char *)page_address(page);
4025*4882a593Smuzhiyun memset(kaddr, 0, PAGE_SIZE);
4026*4882a593Smuzhiyun written_size = 0;
4027*4882a593Smuzhiyun }
4028*4882a593Smuzhiyun summary = (struct f2fs_summary *)(kaddr + written_size);
4029*4882a593Smuzhiyun *summary = seg_i->sum_blk->entries[j];
4030*4882a593Smuzhiyun written_size += SUMMARY_SIZE;
4031*4882a593Smuzhiyun
4032*4882a593Smuzhiyun if (written_size + SUMMARY_SIZE <= PAGE_SIZE -
4033*4882a593Smuzhiyun SUM_FOOTER_SIZE)
4034*4882a593Smuzhiyun continue;
4035*4882a593Smuzhiyun
4036*4882a593Smuzhiyun set_page_dirty(page);
4037*4882a593Smuzhiyun f2fs_put_page(page, 1);
4038*4882a593Smuzhiyun page = NULL;
4039*4882a593Smuzhiyun }
4040*4882a593Smuzhiyun }
4041*4882a593Smuzhiyun if (page) {
4042*4882a593Smuzhiyun set_page_dirty(page);
4043*4882a593Smuzhiyun f2fs_put_page(page, 1);
4044*4882a593Smuzhiyun }
4045*4882a593Smuzhiyun }
4046*4882a593Smuzhiyun
write_normal_summaries(struct f2fs_sb_info * sbi,block_t blkaddr,int type)4047*4882a593Smuzhiyun static void write_normal_summaries(struct f2fs_sb_info *sbi,
4048*4882a593Smuzhiyun block_t blkaddr, int type)
4049*4882a593Smuzhiyun {
4050*4882a593Smuzhiyun int i, end;
4051*4882a593Smuzhiyun
4052*4882a593Smuzhiyun if (IS_DATASEG(type))
4053*4882a593Smuzhiyun end = type + NR_CURSEG_DATA_TYPE;
4054*4882a593Smuzhiyun else
4055*4882a593Smuzhiyun end = type + NR_CURSEG_NODE_TYPE;
4056*4882a593Smuzhiyun
4057*4882a593Smuzhiyun for (i = type; i < end; i++)
4058*4882a593Smuzhiyun write_current_sum_page(sbi, i, blkaddr + (i - type));
4059*4882a593Smuzhiyun }
4060*4882a593Smuzhiyun
f2fs_write_data_summaries(struct f2fs_sb_info * sbi,block_t start_blk)4061*4882a593Smuzhiyun void f2fs_write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
4062*4882a593Smuzhiyun {
4063*4882a593Smuzhiyun if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG))
4064*4882a593Smuzhiyun write_compacted_summaries(sbi, start_blk);
4065*4882a593Smuzhiyun else
4066*4882a593Smuzhiyun write_normal_summaries(sbi, start_blk, CURSEG_HOT_DATA);
4067*4882a593Smuzhiyun }
4068*4882a593Smuzhiyun
f2fs_write_node_summaries(struct f2fs_sb_info * sbi,block_t start_blk)4069*4882a593Smuzhiyun void f2fs_write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
4070*4882a593Smuzhiyun {
4071*4882a593Smuzhiyun write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE);
4072*4882a593Smuzhiyun }
4073*4882a593Smuzhiyun
f2fs_lookup_journal_in_cursum(struct f2fs_journal * journal,int type,unsigned int val,int alloc)4074*4882a593Smuzhiyun int f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type,
4075*4882a593Smuzhiyun unsigned int val, int alloc)
4076*4882a593Smuzhiyun {
4077*4882a593Smuzhiyun int i;
4078*4882a593Smuzhiyun
4079*4882a593Smuzhiyun if (type == NAT_JOURNAL) {
4080*4882a593Smuzhiyun for (i = 0; i < nats_in_cursum(journal); i++) {
4081*4882a593Smuzhiyun if (le32_to_cpu(nid_in_journal(journal, i)) == val)
4082*4882a593Smuzhiyun return i;
4083*4882a593Smuzhiyun }
4084*4882a593Smuzhiyun if (alloc && __has_cursum_space(journal, 1, NAT_JOURNAL))
4085*4882a593Smuzhiyun return update_nats_in_cursum(journal, 1);
4086*4882a593Smuzhiyun } else if (type == SIT_JOURNAL) {
4087*4882a593Smuzhiyun for (i = 0; i < sits_in_cursum(journal); i++)
4088*4882a593Smuzhiyun if (le32_to_cpu(segno_in_journal(journal, i)) == val)
4089*4882a593Smuzhiyun return i;
4090*4882a593Smuzhiyun if (alloc && __has_cursum_space(journal, 1, SIT_JOURNAL))
4091*4882a593Smuzhiyun return update_sits_in_cursum(journal, 1);
4092*4882a593Smuzhiyun }
4093*4882a593Smuzhiyun return -1;
4094*4882a593Smuzhiyun }
4095*4882a593Smuzhiyun
get_current_sit_page(struct f2fs_sb_info * sbi,unsigned int segno)4096*4882a593Smuzhiyun static struct page *get_current_sit_page(struct f2fs_sb_info *sbi,
4097*4882a593Smuzhiyun unsigned int segno)
4098*4882a593Smuzhiyun {
4099*4882a593Smuzhiyun return f2fs_get_meta_page(sbi, current_sit_addr(sbi, segno));
4100*4882a593Smuzhiyun }
4101*4882a593Smuzhiyun
get_next_sit_page(struct f2fs_sb_info * sbi,unsigned int start)4102*4882a593Smuzhiyun static struct page *get_next_sit_page(struct f2fs_sb_info *sbi,
4103*4882a593Smuzhiyun unsigned int start)
4104*4882a593Smuzhiyun {
4105*4882a593Smuzhiyun struct sit_info *sit_i = SIT_I(sbi);
4106*4882a593Smuzhiyun struct page *page;
4107*4882a593Smuzhiyun pgoff_t src_off, dst_off;
4108*4882a593Smuzhiyun
4109*4882a593Smuzhiyun src_off = current_sit_addr(sbi, start);
4110*4882a593Smuzhiyun dst_off = next_sit_addr(sbi, src_off);
4111*4882a593Smuzhiyun
4112*4882a593Smuzhiyun page = f2fs_grab_meta_page(sbi, dst_off);
4113*4882a593Smuzhiyun seg_info_to_sit_page(sbi, page, start);
4114*4882a593Smuzhiyun
4115*4882a593Smuzhiyun set_page_dirty(page);
4116*4882a593Smuzhiyun set_to_next_sit(sit_i, start);
4117*4882a593Smuzhiyun
4118*4882a593Smuzhiyun return page;
4119*4882a593Smuzhiyun }
4120*4882a593Smuzhiyun
grab_sit_entry_set(void)4121*4882a593Smuzhiyun static struct sit_entry_set *grab_sit_entry_set(void)
4122*4882a593Smuzhiyun {
4123*4882a593Smuzhiyun struct sit_entry_set *ses =
4124*4882a593Smuzhiyun f2fs_kmem_cache_alloc(sit_entry_set_slab, GFP_NOFS);
4125*4882a593Smuzhiyun
4126*4882a593Smuzhiyun ses->entry_cnt = 0;
4127*4882a593Smuzhiyun INIT_LIST_HEAD(&ses->set_list);
4128*4882a593Smuzhiyun return ses;
4129*4882a593Smuzhiyun }
4130*4882a593Smuzhiyun
release_sit_entry_set(struct sit_entry_set * ses)4131*4882a593Smuzhiyun static void release_sit_entry_set(struct sit_entry_set *ses)
4132*4882a593Smuzhiyun {
4133*4882a593Smuzhiyun list_del(&ses->set_list);
4134*4882a593Smuzhiyun kmem_cache_free(sit_entry_set_slab, ses);
4135*4882a593Smuzhiyun }
4136*4882a593Smuzhiyun
adjust_sit_entry_set(struct sit_entry_set * ses,struct list_head * head)4137*4882a593Smuzhiyun static void adjust_sit_entry_set(struct sit_entry_set *ses,
4138*4882a593Smuzhiyun struct list_head *head)
4139*4882a593Smuzhiyun {
4140*4882a593Smuzhiyun struct sit_entry_set *next = ses;
4141*4882a593Smuzhiyun
4142*4882a593Smuzhiyun if (list_is_last(&ses->set_list, head))
4143*4882a593Smuzhiyun return;
4144*4882a593Smuzhiyun
4145*4882a593Smuzhiyun list_for_each_entry_continue(next, head, set_list)
4146*4882a593Smuzhiyun if (ses->entry_cnt <= next->entry_cnt)
4147*4882a593Smuzhiyun break;
4148*4882a593Smuzhiyun
4149*4882a593Smuzhiyun list_move_tail(&ses->set_list, &next->set_list);
4150*4882a593Smuzhiyun }
4151*4882a593Smuzhiyun
add_sit_entry(unsigned int segno,struct list_head * head)4152*4882a593Smuzhiyun static void add_sit_entry(unsigned int segno, struct list_head *head)
4153*4882a593Smuzhiyun {
4154*4882a593Smuzhiyun struct sit_entry_set *ses;
4155*4882a593Smuzhiyun unsigned int start_segno = START_SEGNO(segno);
4156*4882a593Smuzhiyun
4157*4882a593Smuzhiyun list_for_each_entry(ses, head, set_list) {
4158*4882a593Smuzhiyun if (ses->start_segno == start_segno) {
4159*4882a593Smuzhiyun ses->entry_cnt++;
4160*4882a593Smuzhiyun adjust_sit_entry_set(ses, head);
4161*4882a593Smuzhiyun return;
4162*4882a593Smuzhiyun }
4163*4882a593Smuzhiyun }
4164*4882a593Smuzhiyun
4165*4882a593Smuzhiyun ses = grab_sit_entry_set();
4166*4882a593Smuzhiyun
4167*4882a593Smuzhiyun ses->start_segno = start_segno;
4168*4882a593Smuzhiyun ses->entry_cnt++;
4169*4882a593Smuzhiyun list_add(&ses->set_list, head);
4170*4882a593Smuzhiyun }
4171*4882a593Smuzhiyun
add_sits_in_set(struct f2fs_sb_info * sbi)4172*4882a593Smuzhiyun static void add_sits_in_set(struct f2fs_sb_info *sbi)
4173*4882a593Smuzhiyun {
4174*4882a593Smuzhiyun struct f2fs_sm_info *sm_info = SM_I(sbi);
4175*4882a593Smuzhiyun struct list_head *set_list = &sm_info->sit_entry_set;
4176*4882a593Smuzhiyun unsigned long *bitmap = SIT_I(sbi)->dirty_sentries_bitmap;
4177*4882a593Smuzhiyun unsigned int segno;
4178*4882a593Smuzhiyun
4179*4882a593Smuzhiyun for_each_set_bit(segno, bitmap, MAIN_SEGS(sbi))
4180*4882a593Smuzhiyun add_sit_entry(segno, set_list);
4181*4882a593Smuzhiyun }
4182*4882a593Smuzhiyun
remove_sits_in_journal(struct f2fs_sb_info * sbi)4183*4882a593Smuzhiyun static void remove_sits_in_journal(struct f2fs_sb_info *sbi)
4184*4882a593Smuzhiyun {
4185*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
4186*4882a593Smuzhiyun struct f2fs_journal *journal = curseg->journal;
4187*4882a593Smuzhiyun int i;
4188*4882a593Smuzhiyun
4189*4882a593Smuzhiyun down_write(&curseg->journal_rwsem);
4190*4882a593Smuzhiyun for (i = 0; i < sits_in_cursum(journal); i++) {
4191*4882a593Smuzhiyun unsigned int segno;
4192*4882a593Smuzhiyun bool dirtied;
4193*4882a593Smuzhiyun
4194*4882a593Smuzhiyun segno = le32_to_cpu(segno_in_journal(journal, i));
4195*4882a593Smuzhiyun dirtied = __mark_sit_entry_dirty(sbi, segno);
4196*4882a593Smuzhiyun
4197*4882a593Smuzhiyun if (!dirtied)
4198*4882a593Smuzhiyun add_sit_entry(segno, &SM_I(sbi)->sit_entry_set);
4199*4882a593Smuzhiyun }
4200*4882a593Smuzhiyun update_sits_in_cursum(journal, -i);
4201*4882a593Smuzhiyun up_write(&curseg->journal_rwsem);
4202*4882a593Smuzhiyun }
4203*4882a593Smuzhiyun
4204*4882a593Smuzhiyun /*
4205*4882a593Smuzhiyun * CP calls this function, which flushes SIT entries including sit_journal,
4206*4882a593Smuzhiyun * and moves prefree segs to free segs.
4207*4882a593Smuzhiyun */
f2fs_flush_sit_entries(struct f2fs_sb_info * sbi,struct cp_control * cpc)4208*4882a593Smuzhiyun void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
4209*4882a593Smuzhiyun {
4210*4882a593Smuzhiyun struct sit_info *sit_i = SIT_I(sbi);
4211*4882a593Smuzhiyun unsigned long *bitmap = sit_i->dirty_sentries_bitmap;
4212*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
4213*4882a593Smuzhiyun struct f2fs_journal *journal = curseg->journal;
4214*4882a593Smuzhiyun struct sit_entry_set *ses, *tmp;
4215*4882a593Smuzhiyun struct list_head *head = &SM_I(sbi)->sit_entry_set;
4216*4882a593Smuzhiyun bool to_journal = !is_sbi_flag_set(sbi, SBI_IS_RESIZEFS);
4217*4882a593Smuzhiyun struct seg_entry *se;
4218*4882a593Smuzhiyun
4219*4882a593Smuzhiyun down_write(&sit_i->sentry_lock);
4220*4882a593Smuzhiyun
4221*4882a593Smuzhiyun if (!sit_i->dirty_sentries)
4222*4882a593Smuzhiyun goto out;
4223*4882a593Smuzhiyun
4224*4882a593Smuzhiyun /*
4225*4882a593Smuzhiyun * add and account sit entries of dirty bitmap in sit entry
4226*4882a593Smuzhiyun * set temporarily
4227*4882a593Smuzhiyun */
4228*4882a593Smuzhiyun add_sits_in_set(sbi);
4229*4882a593Smuzhiyun
4230*4882a593Smuzhiyun /*
4231*4882a593Smuzhiyun * if there are no enough space in journal to store dirty sit
4232*4882a593Smuzhiyun * entries, remove all entries from journal and add and account
4233*4882a593Smuzhiyun * them in sit entry set.
4234*4882a593Smuzhiyun */
4235*4882a593Smuzhiyun if (!__has_cursum_space(journal, sit_i->dirty_sentries, SIT_JOURNAL) ||
4236*4882a593Smuzhiyun !to_journal)
4237*4882a593Smuzhiyun remove_sits_in_journal(sbi);
4238*4882a593Smuzhiyun
4239*4882a593Smuzhiyun /*
4240*4882a593Smuzhiyun * there are two steps to flush sit entries:
4241*4882a593Smuzhiyun * #1, flush sit entries to journal in current cold data summary block.
4242*4882a593Smuzhiyun * #2, flush sit entries to sit page.
4243*4882a593Smuzhiyun */
4244*4882a593Smuzhiyun list_for_each_entry_safe(ses, tmp, head, set_list) {
4245*4882a593Smuzhiyun struct page *page = NULL;
4246*4882a593Smuzhiyun struct f2fs_sit_block *raw_sit = NULL;
4247*4882a593Smuzhiyun unsigned int start_segno = ses->start_segno;
4248*4882a593Smuzhiyun unsigned int end = min(start_segno + SIT_ENTRY_PER_BLOCK,
4249*4882a593Smuzhiyun (unsigned long)MAIN_SEGS(sbi));
4250*4882a593Smuzhiyun unsigned int segno = start_segno;
4251*4882a593Smuzhiyun
4252*4882a593Smuzhiyun if (to_journal &&
4253*4882a593Smuzhiyun !__has_cursum_space(journal, ses->entry_cnt, SIT_JOURNAL))
4254*4882a593Smuzhiyun to_journal = false;
4255*4882a593Smuzhiyun
4256*4882a593Smuzhiyun if (to_journal) {
4257*4882a593Smuzhiyun down_write(&curseg->journal_rwsem);
4258*4882a593Smuzhiyun } else {
4259*4882a593Smuzhiyun page = get_next_sit_page(sbi, start_segno);
4260*4882a593Smuzhiyun raw_sit = page_address(page);
4261*4882a593Smuzhiyun }
4262*4882a593Smuzhiyun
4263*4882a593Smuzhiyun /* flush dirty sit entries in region of current sit set */
4264*4882a593Smuzhiyun for_each_set_bit_from(segno, bitmap, end) {
4265*4882a593Smuzhiyun int offset, sit_offset;
4266*4882a593Smuzhiyun
4267*4882a593Smuzhiyun se = get_seg_entry(sbi, segno);
4268*4882a593Smuzhiyun #ifdef CONFIG_F2FS_CHECK_FS
4269*4882a593Smuzhiyun if (memcmp(se->cur_valid_map, se->cur_valid_map_mir,
4270*4882a593Smuzhiyun SIT_VBLOCK_MAP_SIZE))
4271*4882a593Smuzhiyun f2fs_bug_on(sbi, 1);
4272*4882a593Smuzhiyun #endif
4273*4882a593Smuzhiyun
4274*4882a593Smuzhiyun /* add discard candidates */
4275*4882a593Smuzhiyun if (!(cpc->reason & CP_DISCARD)) {
4276*4882a593Smuzhiyun cpc->trim_start = segno;
4277*4882a593Smuzhiyun add_discard_addrs(sbi, cpc, false);
4278*4882a593Smuzhiyun }
4279*4882a593Smuzhiyun
4280*4882a593Smuzhiyun if (to_journal) {
4281*4882a593Smuzhiyun offset = f2fs_lookup_journal_in_cursum(journal,
4282*4882a593Smuzhiyun SIT_JOURNAL, segno, 1);
4283*4882a593Smuzhiyun f2fs_bug_on(sbi, offset < 0);
4284*4882a593Smuzhiyun segno_in_journal(journal, offset) =
4285*4882a593Smuzhiyun cpu_to_le32(segno);
4286*4882a593Smuzhiyun seg_info_to_raw_sit(se,
4287*4882a593Smuzhiyun &sit_in_journal(journal, offset));
4288*4882a593Smuzhiyun check_block_count(sbi, segno,
4289*4882a593Smuzhiyun &sit_in_journal(journal, offset));
4290*4882a593Smuzhiyun } else {
4291*4882a593Smuzhiyun sit_offset = SIT_ENTRY_OFFSET(sit_i, segno);
4292*4882a593Smuzhiyun seg_info_to_raw_sit(se,
4293*4882a593Smuzhiyun &raw_sit->entries[sit_offset]);
4294*4882a593Smuzhiyun check_block_count(sbi, segno,
4295*4882a593Smuzhiyun &raw_sit->entries[sit_offset]);
4296*4882a593Smuzhiyun }
4297*4882a593Smuzhiyun
4298*4882a593Smuzhiyun __clear_bit(segno, bitmap);
4299*4882a593Smuzhiyun sit_i->dirty_sentries--;
4300*4882a593Smuzhiyun ses->entry_cnt--;
4301*4882a593Smuzhiyun }
4302*4882a593Smuzhiyun
4303*4882a593Smuzhiyun if (to_journal)
4304*4882a593Smuzhiyun up_write(&curseg->journal_rwsem);
4305*4882a593Smuzhiyun else
4306*4882a593Smuzhiyun f2fs_put_page(page, 1);
4307*4882a593Smuzhiyun
4308*4882a593Smuzhiyun f2fs_bug_on(sbi, ses->entry_cnt);
4309*4882a593Smuzhiyun release_sit_entry_set(ses);
4310*4882a593Smuzhiyun }
4311*4882a593Smuzhiyun
4312*4882a593Smuzhiyun f2fs_bug_on(sbi, !list_empty(head));
4313*4882a593Smuzhiyun f2fs_bug_on(sbi, sit_i->dirty_sentries);
4314*4882a593Smuzhiyun out:
4315*4882a593Smuzhiyun if (cpc->reason & CP_DISCARD) {
4316*4882a593Smuzhiyun __u64 trim_start = cpc->trim_start;
4317*4882a593Smuzhiyun
4318*4882a593Smuzhiyun for (; cpc->trim_start <= cpc->trim_end; cpc->trim_start++)
4319*4882a593Smuzhiyun add_discard_addrs(sbi, cpc, false);
4320*4882a593Smuzhiyun
4321*4882a593Smuzhiyun cpc->trim_start = trim_start;
4322*4882a593Smuzhiyun }
4323*4882a593Smuzhiyun up_write(&sit_i->sentry_lock);
4324*4882a593Smuzhiyun
4325*4882a593Smuzhiyun set_prefree_as_free_segments(sbi);
4326*4882a593Smuzhiyun }
4327*4882a593Smuzhiyun
build_sit_info(struct f2fs_sb_info * sbi)4328*4882a593Smuzhiyun static int build_sit_info(struct f2fs_sb_info *sbi)
4329*4882a593Smuzhiyun {
4330*4882a593Smuzhiyun struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
4331*4882a593Smuzhiyun struct sit_info *sit_i;
4332*4882a593Smuzhiyun unsigned int sit_segs, start;
4333*4882a593Smuzhiyun char *src_bitmap, *bitmap;
4334*4882a593Smuzhiyun unsigned int bitmap_size, main_bitmap_size, sit_bitmap_size;
4335*4882a593Smuzhiyun
4336*4882a593Smuzhiyun /* allocate memory for SIT information */
4337*4882a593Smuzhiyun sit_i = f2fs_kzalloc(sbi, sizeof(struct sit_info), GFP_KERNEL);
4338*4882a593Smuzhiyun if (!sit_i)
4339*4882a593Smuzhiyun return -ENOMEM;
4340*4882a593Smuzhiyun
4341*4882a593Smuzhiyun SM_I(sbi)->sit_info = sit_i;
4342*4882a593Smuzhiyun
4343*4882a593Smuzhiyun sit_i->sentries =
4344*4882a593Smuzhiyun f2fs_kvzalloc(sbi, array_size(sizeof(struct seg_entry),
4345*4882a593Smuzhiyun MAIN_SEGS(sbi)),
4346*4882a593Smuzhiyun GFP_KERNEL);
4347*4882a593Smuzhiyun if (!sit_i->sentries)
4348*4882a593Smuzhiyun return -ENOMEM;
4349*4882a593Smuzhiyun
4350*4882a593Smuzhiyun main_bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
4351*4882a593Smuzhiyun sit_i->dirty_sentries_bitmap = f2fs_kvzalloc(sbi, main_bitmap_size,
4352*4882a593Smuzhiyun GFP_KERNEL);
4353*4882a593Smuzhiyun if (!sit_i->dirty_sentries_bitmap)
4354*4882a593Smuzhiyun return -ENOMEM;
4355*4882a593Smuzhiyun
4356*4882a593Smuzhiyun #ifdef CONFIG_F2FS_CHECK_FS
4357*4882a593Smuzhiyun bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * 4;
4358*4882a593Smuzhiyun #else
4359*4882a593Smuzhiyun bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * 3;
4360*4882a593Smuzhiyun #endif
4361*4882a593Smuzhiyun sit_i->bitmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
4362*4882a593Smuzhiyun if (!sit_i->bitmap)
4363*4882a593Smuzhiyun return -ENOMEM;
4364*4882a593Smuzhiyun
4365*4882a593Smuzhiyun bitmap = sit_i->bitmap;
4366*4882a593Smuzhiyun
4367*4882a593Smuzhiyun for (start = 0; start < MAIN_SEGS(sbi); start++) {
4368*4882a593Smuzhiyun sit_i->sentries[start].cur_valid_map = bitmap;
4369*4882a593Smuzhiyun bitmap += SIT_VBLOCK_MAP_SIZE;
4370*4882a593Smuzhiyun
4371*4882a593Smuzhiyun sit_i->sentries[start].ckpt_valid_map = bitmap;
4372*4882a593Smuzhiyun bitmap += SIT_VBLOCK_MAP_SIZE;
4373*4882a593Smuzhiyun
4374*4882a593Smuzhiyun #ifdef CONFIG_F2FS_CHECK_FS
4375*4882a593Smuzhiyun sit_i->sentries[start].cur_valid_map_mir = bitmap;
4376*4882a593Smuzhiyun bitmap += SIT_VBLOCK_MAP_SIZE;
4377*4882a593Smuzhiyun #endif
4378*4882a593Smuzhiyun
4379*4882a593Smuzhiyun sit_i->sentries[start].discard_map = bitmap;
4380*4882a593Smuzhiyun bitmap += SIT_VBLOCK_MAP_SIZE;
4381*4882a593Smuzhiyun }
4382*4882a593Smuzhiyun
4383*4882a593Smuzhiyun sit_i->tmp_map = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
4384*4882a593Smuzhiyun if (!sit_i->tmp_map)
4385*4882a593Smuzhiyun return -ENOMEM;
4386*4882a593Smuzhiyun
4387*4882a593Smuzhiyun if (__is_large_section(sbi)) {
4388*4882a593Smuzhiyun sit_i->sec_entries =
4389*4882a593Smuzhiyun f2fs_kvzalloc(sbi, array_size(sizeof(struct sec_entry),
4390*4882a593Smuzhiyun MAIN_SECS(sbi)),
4391*4882a593Smuzhiyun GFP_KERNEL);
4392*4882a593Smuzhiyun if (!sit_i->sec_entries)
4393*4882a593Smuzhiyun return -ENOMEM;
4394*4882a593Smuzhiyun }
4395*4882a593Smuzhiyun
4396*4882a593Smuzhiyun /* get information related with SIT */
4397*4882a593Smuzhiyun sit_segs = le32_to_cpu(raw_super->segment_count_sit) >> 1;
4398*4882a593Smuzhiyun
4399*4882a593Smuzhiyun /* setup SIT bitmap from ckeckpoint pack */
4400*4882a593Smuzhiyun sit_bitmap_size = __bitmap_size(sbi, SIT_BITMAP);
4401*4882a593Smuzhiyun src_bitmap = __bitmap_ptr(sbi, SIT_BITMAP);
4402*4882a593Smuzhiyun
4403*4882a593Smuzhiyun sit_i->sit_bitmap = kmemdup(src_bitmap, sit_bitmap_size, GFP_KERNEL);
4404*4882a593Smuzhiyun if (!sit_i->sit_bitmap)
4405*4882a593Smuzhiyun return -ENOMEM;
4406*4882a593Smuzhiyun
4407*4882a593Smuzhiyun #ifdef CONFIG_F2FS_CHECK_FS
4408*4882a593Smuzhiyun sit_i->sit_bitmap_mir = kmemdup(src_bitmap,
4409*4882a593Smuzhiyun sit_bitmap_size, GFP_KERNEL);
4410*4882a593Smuzhiyun if (!sit_i->sit_bitmap_mir)
4411*4882a593Smuzhiyun return -ENOMEM;
4412*4882a593Smuzhiyun
4413*4882a593Smuzhiyun sit_i->invalid_segmap = f2fs_kvzalloc(sbi,
4414*4882a593Smuzhiyun main_bitmap_size, GFP_KERNEL);
4415*4882a593Smuzhiyun if (!sit_i->invalid_segmap)
4416*4882a593Smuzhiyun return -ENOMEM;
4417*4882a593Smuzhiyun #endif
4418*4882a593Smuzhiyun
4419*4882a593Smuzhiyun /* init SIT information */
4420*4882a593Smuzhiyun sit_i->s_ops = &default_salloc_ops;
4421*4882a593Smuzhiyun
4422*4882a593Smuzhiyun sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr);
4423*4882a593Smuzhiyun sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg;
4424*4882a593Smuzhiyun sit_i->written_valid_blocks = 0;
4425*4882a593Smuzhiyun sit_i->bitmap_size = sit_bitmap_size;
4426*4882a593Smuzhiyun sit_i->dirty_sentries = 0;
4427*4882a593Smuzhiyun sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK;
4428*4882a593Smuzhiyun sit_i->elapsed_time = le64_to_cpu(sbi->ckpt->elapsed_time);
4429*4882a593Smuzhiyun sit_i->mounted_time = ktime_get_boottime_seconds();
4430*4882a593Smuzhiyun init_rwsem(&sit_i->sentry_lock);
4431*4882a593Smuzhiyun return 0;
4432*4882a593Smuzhiyun }
4433*4882a593Smuzhiyun
build_free_segmap(struct f2fs_sb_info * sbi)4434*4882a593Smuzhiyun static int build_free_segmap(struct f2fs_sb_info *sbi)
4435*4882a593Smuzhiyun {
4436*4882a593Smuzhiyun struct free_segmap_info *free_i;
4437*4882a593Smuzhiyun unsigned int bitmap_size, sec_bitmap_size;
4438*4882a593Smuzhiyun
4439*4882a593Smuzhiyun /* allocate memory for free segmap information */
4440*4882a593Smuzhiyun free_i = f2fs_kzalloc(sbi, sizeof(struct free_segmap_info), GFP_KERNEL);
4441*4882a593Smuzhiyun if (!free_i)
4442*4882a593Smuzhiyun return -ENOMEM;
4443*4882a593Smuzhiyun
4444*4882a593Smuzhiyun SM_I(sbi)->free_info = free_i;
4445*4882a593Smuzhiyun
4446*4882a593Smuzhiyun bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
4447*4882a593Smuzhiyun free_i->free_segmap = f2fs_kvmalloc(sbi, bitmap_size, GFP_KERNEL);
4448*4882a593Smuzhiyun if (!free_i->free_segmap)
4449*4882a593Smuzhiyun return -ENOMEM;
4450*4882a593Smuzhiyun
4451*4882a593Smuzhiyun sec_bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi));
4452*4882a593Smuzhiyun free_i->free_secmap = f2fs_kvmalloc(sbi, sec_bitmap_size, GFP_KERNEL);
4453*4882a593Smuzhiyun if (!free_i->free_secmap)
4454*4882a593Smuzhiyun return -ENOMEM;
4455*4882a593Smuzhiyun
4456*4882a593Smuzhiyun /* set all segments as dirty temporarily */
4457*4882a593Smuzhiyun memset(free_i->free_segmap, 0xff, bitmap_size);
4458*4882a593Smuzhiyun memset(free_i->free_secmap, 0xff, sec_bitmap_size);
4459*4882a593Smuzhiyun
4460*4882a593Smuzhiyun /* init free segmap information */
4461*4882a593Smuzhiyun free_i->start_segno = GET_SEGNO_FROM_SEG0(sbi, MAIN_BLKADDR(sbi));
4462*4882a593Smuzhiyun free_i->free_segments = 0;
4463*4882a593Smuzhiyun free_i->free_sections = 0;
4464*4882a593Smuzhiyun spin_lock_init(&free_i->segmap_lock);
4465*4882a593Smuzhiyun return 0;
4466*4882a593Smuzhiyun }
4467*4882a593Smuzhiyun
build_curseg(struct f2fs_sb_info * sbi)4468*4882a593Smuzhiyun static int build_curseg(struct f2fs_sb_info *sbi)
4469*4882a593Smuzhiyun {
4470*4882a593Smuzhiyun struct curseg_info *array;
4471*4882a593Smuzhiyun int i;
4472*4882a593Smuzhiyun
4473*4882a593Smuzhiyun array = f2fs_kzalloc(sbi, array_size(NR_CURSEG_TYPE,
4474*4882a593Smuzhiyun sizeof(*array)), GFP_KERNEL);
4475*4882a593Smuzhiyun if (!array)
4476*4882a593Smuzhiyun return -ENOMEM;
4477*4882a593Smuzhiyun
4478*4882a593Smuzhiyun SM_I(sbi)->curseg_array = array;
4479*4882a593Smuzhiyun
4480*4882a593Smuzhiyun for (i = 0; i < NO_CHECK_TYPE; i++) {
4481*4882a593Smuzhiyun mutex_init(&array[i].curseg_mutex);
4482*4882a593Smuzhiyun array[i].sum_blk = f2fs_kzalloc(sbi, PAGE_SIZE, GFP_KERNEL);
4483*4882a593Smuzhiyun if (!array[i].sum_blk)
4484*4882a593Smuzhiyun return -ENOMEM;
4485*4882a593Smuzhiyun init_rwsem(&array[i].journal_rwsem);
4486*4882a593Smuzhiyun array[i].journal = f2fs_kzalloc(sbi,
4487*4882a593Smuzhiyun sizeof(struct f2fs_journal), GFP_KERNEL);
4488*4882a593Smuzhiyun if (!array[i].journal)
4489*4882a593Smuzhiyun return -ENOMEM;
4490*4882a593Smuzhiyun if (i < NR_PERSISTENT_LOG)
4491*4882a593Smuzhiyun array[i].seg_type = CURSEG_HOT_DATA + i;
4492*4882a593Smuzhiyun else if (i == CURSEG_COLD_DATA_PINNED)
4493*4882a593Smuzhiyun array[i].seg_type = CURSEG_COLD_DATA;
4494*4882a593Smuzhiyun else if (i == CURSEG_ALL_DATA_ATGC)
4495*4882a593Smuzhiyun array[i].seg_type = CURSEG_COLD_DATA;
4496*4882a593Smuzhiyun array[i].segno = NULL_SEGNO;
4497*4882a593Smuzhiyun array[i].next_blkoff = 0;
4498*4882a593Smuzhiyun array[i].inited = false;
4499*4882a593Smuzhiyun }
4500*4882a593Smuzhiyun return restore_curseg_summaries(sbi);
4501*4882a593Smuzhiyun }
4502*4882a593Smuzhiyun
build_sit_entries(struct f2fs_sb_info * sbi)4503*4882a593Smuzhiyun static int build_sit_entries(struct f2fs_sb_info *sbi)
4504*4882a593Smuzhiyun {
4505*4882a593Smuzhiyun struct sit_info *sit_i = SIT_I(sbi);
4506*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
4507*4882a593Smuzhiyun struct f2fs_journal *journal = curseg->journal;
4508*4882a593Smuzhiyun struct seg_entry *se;
4509*4882a593Smuzhiyun struct f2fs_sit_entry sit;
4510*4882a593Smuzhiyun int sit_blk_cnt = SIT_BLK_CNT(sbi);
4511*4882a593Smuzhiyun unsigned int i, start, end;
4512*4882a593Smuzhiyun unsigned int readed, start_blk = 0;
4513*4882a593Smuzhiyun int err = 0;
4514*4882a593Smuzhiyun block_t sit_valid_blocks[2] = {0, 0};
4515*4882a593Smuzhiyun
4516*4882a593Smuzhiyun do {
4517*4882a593Smuzhiyun readed = f2fs_ra_meta_pages(sbi, start_blk, BIO_MAX_PAGES,
4518*4882a593Smuzhiyun META_SIT, true);
4519*4882a593Smuzhiyun
4520*4882a593Smuzhiyun start = start_blk * sit_i->sents_per_block;
4521*4882a593Smuzhiyun end = (start_blk + readed) * sit_i->sents_per_block;
4522*4882a593Smuzhiyun
4523*4882a593Smuzhiyun for (; start < end && start < MAIN_SEGS(sbi); start++) {
4524*4882a593Smuzhiyun struct f2fs_sit_block *sit_blk;
4525*4882a593Smuzhiyun struct page *page;
4526*4882a593Smuzhiyun
4527*4882a593Smuzhiyun se = &sit_i->sentries[start];
4528*4882a593Smuzhiyun page = get_current_sit_page(sbi, start);
4529*4882a593Smuzhiyun if (IS_ERR(page))
4530*4882a593Smuzhiyun return PTR_ERR(page);
4531*4882a593Smuzhiyun sit_blk = (struct f2fs_sit_block *)page_address(page);
4532*4882a593Smuzhiyun sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)];
4533*4882a593Smuzhiyun f2fs_put_page(page, 1);
4534*4882a593Smuzhiyun
4535*4882a593Smuzhiyun err = check_block_count(sbi, start, &sit);
4536*4882a593Smuzhiyun if (err)
4537*4882a593Smuzhiyun return err;
4538*4882a593Smuzhiyun seg_info_from_raw_sit(se, &sit);
4539*4882a593Smuzhiyun
4540*4882a593Smuzhiyun if (se->type >= NR_PERSISTENT_LOG) {
4541*4882a593Smuzhiyun f2fs_err(sbi, "Invalid segment type: %u, segno: %u",
4542*4882a593Smuzhiyun se->type, start);
4543*4882a593Smuzhiyun return -EFSCORRUPTED;
4544*4882a593Smuzhiyun }
4545*4882a593Smuzhiyun
4546*4882a593Smuzhiyun sit_valid_blocks[SE_PAGETYPE(se)] += se->valid_blocks;
4547*4882a593Smuzhiyun
4548*4882a593Smuzhiyun /* build discard map only one time */
4549*4882a593Smuzhiyun if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
4550*4882a593Smuzhiyun memset(se->discard_map, 0xff,
4551*4882a593Smuzhiyun SIT_VBLOCK_MAP_SIZE);
4552*4882a593Smuzhiyun } else {
4553*4882a593Smuzhiyun memcpy(se->discard_map,
4554*4882a593Smuzhiyun se->cur_valid_map,
4555*4882a593Smuzhiyun SIT_VBLOCK_MAP_SIZE);
4556*4882a593Smuzhiyun sbi->discard_blks +=
4557*4882a593Smuzhiyun sbi->blocks_per_seg -
4558*4882a593Smuzhiyun se->valid_blocks;
4559*4882a593Smuzhiyun }
4560*4882a593Smuzhiyun
4561*4882a593Smuzhiyun if (__is_large_section(sbi))
4562*4882a593Smuzhiyun get_sec_entry(sbi, start)->valid_blocks +=
4563*4882a593Smuzhiyun se->valid_blocks;
4564*4882a593Smuzhiyun }
4565*4882a593Smuzhiyun start_blk += readed;
4566*4882a593Smuzhiyun } while (start_blk < sit_blk_cnt);
4567*4882a593Smuzhiyun
4568*4882a593Smuzhiyun down_read(&curseg->journal_rwsem);
4569*4882a593Smuzhiyun for (i = 0; i < sits_in_cursum(journal); i++) {
4570*4882a593Smuzhiyun unsigned int old_valid_blocks;
4571*4882a593Smuzhiyun
4572*4882a593Smuzhiyun start = le32_to_cpu(segno_in_journal(journal, i));
4573*4882a593Smuzhiyun if (start >= MAIN_SEGS(sbi)) {
4574*4882a593Smuzhiyun f2fs_err(sbi, "Wrong journal entry on segno %u",
4575*4882a593Smuzhiyun start);
4576*4882a593Smuzhiyun err = -EFSCORRUPTED;
4577*4882a593Smuzhiyun break;
4578*4882a593Smuzhiyun }
4579*4882a593Smuzhiyun
4580*4882a593Smuzhiyun se = &sit_i->sentries[start];
4581*4882a593Smuzhiyun sit = sit_in_journal(journal, i);
4582*4882a593Smuzhiyun
4583*4882a593Smuzhiyun old_valid_blocks = se->valid_blocks;
4584*4882a593Smuzhiyun
4585*4882a593Smuzhiyun sit_valid_blocks[SE_PAGETYPE(se)] -= old_valid_blocks;
4586*4882a593Smuzhiyun
4587*4882a593Smuzhiyun err = check_block_count(sbi, start, &sit);
4588*4882a593Smuzhiyun if (err)
4589*4882a593Smuzhiyun break;
4590*4882a593Smuzhiyun seg_info_from_raw_sit(se, &sit);
4591*4882a593Smuzhiyun
4592*4882a593Smuzhiyun if (se->type >= NR_PERSISTENT_LOG) {
4593*4882a593Smuzhiyun f2fs_err(sbi, "Invalid segment type: %u, segno: %u",
4594*4882a593Smuzhiyun se->type, start);
4595*4882a593Smuzhiyun err = -EFSCORRUPTED;
4596*4882a593Smuzhiyun break;
4597*4882a593Smuzhiyun }
4598*4882a593Smuzhiyun
4599*4882a593Smuzhiyun sit_valid_blocks[SE_PAGETYPE(se)] += se->valid_blocks;
4600*4882a593Smuzhiyun
4601*4882a593Smuzhiyun if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
4602*4882a593Smuzhiyun memset(se->discard_map, 0xff, SIT_VBLOCK_MAP_SIZE);
4603*4882a593Smuzhiyun } else {
4604*4882a593Smuzhiyun memcpy(se->discard_map, se->cur_valid_map,
4605*4882a593Smuzhiyun SIT_VBLOCK_MAP_SIZE);
4606*4882a593Smuzhiyun sbi->discard_blks += old_valid_blocks;
4607*4882a593Smuzhiyun sbi->discard_blks -= se->valid_blocks;
4608*4882a593Smuzhiyun }
4609*4882a593Smuzhiyun
4610*4882a593Smuzhiyun if (__is_large_section(sbi)) {
4611*4882a593Smuzhiyun get_sec_entry(sbi, start)->valid_blocks +=
4612*4882a593Smuzhiyun se->valid_blocks;
4613*4882a593Smuzhiyun get_sec_entry(sbi, start)->valid_blocks -=
4614*4882a593Smuzhiyun old_valid_blocks;
4615*4882a593Smuzhiyun }
4616*4882a593Smuzhiyun }
4617*4882a593Smuzhiyun up_read(&curseg->journal_rwsem);
4618*4882a593Smuzhiyun
4619*4882a593Smuzhiyun if (err)
4620*4882a593Smuzhiyun return err;
4621*4882a593Smuzhiyun
4622*4882a593Smuzhiyun if (sit_valid_blocks[NODE] != valid_node_count(sbi)) {
4623*4882a593Smuzhiyun f2fs_err(sbi, "SIT is corrupted node# %u vs %u",
4624*4882a593Smuzhiyun sit_valid_blocks[NODE], valid_node_count(sbi));
4625*4882a593Smuzhiyun return -EFSCORRUPTED;
4626*4882a593Smuzhiyun }
4627*4882a593Smuzhiyun
4628*4882a593Smuzhiyun if (sit_valid_blocks[DATA] + sit_valid_blocks[NODE] >
4629*4882a593Smuzhiyun valid_user_blocks(sbi)) {
4630*4882a593Smuzhiyun f2fs_err(sbi, "SIT is corrupted data# %u %u vs %u",
4631*4882a593Smuzhiyun sit_valid_blocks[DATA], sit_valid_blocks[NODE],
4632*4882a593Smuzhiyun valid_user_blocks(sbi));
4633*4882a593Smuzhiyun return -EFSCORRUPTED;
4634*4882a593Smuzhiyun }
4635*4882a593Smuzhiyun
4636*4882a593Smuzhiyun return 0;
4637*4882a593Smuzhiyun }
4638*4882a593Smuzhiyun
init_free_segmap(struct f2fs_sb_info * sbi)4639*4882a593Smuzhiyun static void init_free_segmap(struct f2fs_sb_info *sbi)
4640*4882a593Smuzhiyun {
4641*4882a593Smuzhiyun unsigned int start;
4642*4882a593Smuzhiyun int type;
4643*4882a593Smuzhiyun struct seg_entry *sentry;
4644*4882a593Smuzhiyun
4645*4882a593Smuzhiyun for (start = 0; start < MAIN_SEGS(sbi); start++) {
4646*4882a593Smuzhiyun if (f2fs_usable_blks_in_seg(sbi, start) == 0)
4647*4882a593Smuzhiyun continue;
4648*4882a593Smuzhiyun sentry = get_seg_entry(sbi, start);
4649*4882a593Smuzhiyun if (!sentry->valid_blocks)
4650*4882a593Smuzhiyun __set_free(sbi, start);
4651*4882a593Smuzhiyun else
4652*4882a593Smuzhiyun SIT_I(sbi)->written_valid_blocks +=
4653*4882a593Smuzhiyun sentry->valid_blocks;
4654*4882a593Smuzhiyun }
4655*4882a593Smuzhiyun
4656*4882a593Smuzhiyun /* set use the current segments */
4657*4882a593Smuzhiyun for (type = CURSEG_HOT_DATA; type <= CURSEG_COLD_NODE; type++) {
4658*4882a593Smuzhiyun struct curseg_info *curseg_t = CURSEG_I(sbi, type);
4659*4882a593Smuzhiyun
4660*4882a593Smuzhiyun __set_test_and_inuse(sbi, curseg_t->segno);
4661*4882a593Smuzhiyun }
4662*4882a593Smuzhiyun }
4663*4882a593Smuzhiyun
init_dirty_segmap(struct f2fs_sb_info * sbi)4664*4882a593Smuzhiyun static void init_dirty_segmap(struct f2fs_sb_info *sbi)
4665*4882a593Smuzhiyun {
4666*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
4667*4882a593Smuzhiyun struct free_segmap_info *free_i = FREE_I(sbi);
4668*4882a593Smuzhiyun unsigned int segno = 0, offset = 0, secno;
4669*4882a593Smuzhiyun block_t valid_blocks, usable_blks_in_seg;
4670*4882a593Smuzhiyun block_t blks_per_sec = BLKS_PER_SEC(sbi);
4671*4882a593Smuzhiyun
4672*4882a593Smuzhiyun while (1) {
4673*4882a593Smuzhiyun /* find dirty segment based on free segmap */
4674*4882a593Smuzhiyun segno = find_next_inuse(free_i, MAIN_SEGS(sbi), offset);
4675*4882a593Smuzhiyun if (segno >= MAIN_SEGS(sbi))
4676*4882a593Smuzhiyun break;
4677*4882a593Smuzhiyun offset = segno + 1;
4678*4882a593Smuzhiyun valid_blocks = get_valid_blocks(sbi, segno, false);
4679*4882a593Smuzhiyun usable_blks_in_seg = f2fs_usable_blks_in_seg(sbi, segno);
4680*4882a593Smuzhiyun if (valid_blocks == usable_blks_in_seg || !valid_blocks)
4681*4882a593Smuzhiyun continue;
4682*4882a593Smuzhiyun if (valid_blocks > usable_blks_in_seg) {
4683*4882a593Smuzhiyun f2fs_bug_on(sbi, 1);
4684*4882a593Smuzhiyun continue;
4685*4882a593Smuzhiyun }
4686*4882a593Smuzhiyun mutex_lock(&dirty_i->seglist_lock);
4687*4882a593Smuzhiyun __locate_dirty_segment(sbi, segno, DIRTY);
4688*4882a593Smuzhiyun mutex_unlock(&dirty_i->seglist_lock);
4689*4882a593Smuzhiyun }
4690*4882a593Smuzhiyun
4691*4882a593Smuzhiyun if (!__is_large_section(sbi))
4692*4882a593Smuzhiyun return;
4693*4882a593Smuzhiyun
4694*4882a593Smuzhiyun mutex_lock(&dirty_i->seglist_lock);
4695*4882a593Smuzhiyun for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
4696*4882a593Smuzhiyun valid_blocks = get_valid_blocks(sbi, segno, true);
4697*4882a593Smuzhiyun secno = GET_SEC_FROM_SEG(sbi, segno);
4698*4882a593Smuzhiyun
4699*4882a593Smuzhiyun if (!valid_blocks || valid_blocks == blks_per_sec)
4700*4882a593Smuzhiyun continue;
4701*4882a593Smuzhiyun if (IS_CURSEC(sbi, secno))
4702*4882a593Smuzhiyun continue;
4703*4882a593Smuzhiyun set_bit(secno, dirty_i->dirty_secmap);
4704*4882a593Smuzhiyun }
4705*4882a593Smuzhiyun mutex_unlock(&dirty_i->seglist_lock);
4706*4882a593Smuzhiyun }
4707*4882a593Smuzhiyun
init_victim_secmap(struct f2fs_sb_info * sbi)4708*4882a593Smuzhiyun static int init_victim_secmap(struct f2fs_sb_info *sbi)
4709*4882a593Smuzhiyun {
4710*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
4711*4882a593Smuzhiyun unsigned int bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi));
4712*4882a593Smuzhiyun
4713*4882a593Smuzhiyun dirty_i->victim_secmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
4714*4882a593Smuzhiyun if (!dirty_i->victim_secmap)
4715*4882a593Smuzhiyun return -ENOMEM;
4716*4882a593Smuzhiyun return 0;
4717*4882a593Smuzhiyun }
4718*4882a593Smuzhiyun
build_dirty_segmap(struct f2fs_sb_info * sbi)4719*4882a593Smuzhiyun static int build_dirty_segmap(struct f2fs_sb_info *sbi)
4720*4882a593Smuzhiyun {
4721*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i;
4722*4882a593Smuzhiyun unsigned int bitmap_size, i;
4723*4882a593Smuzhiyun
4724*4882a593Smuzhiyun /* allocate memory for dirty segments list information */
4725*4882a593Smuzhiyun dirty_i = f2fs_kzalloc(sbi, sizeof(struct dirty_seglist_info),
4726*4882a593Smuzhiyun GFP_KERNEL);
4727*4882a593Smuzhiyun if (!dirty_i)
4728*4882a593Smuzhiyun return -ENOMEM;
4729*4882a593Smuzhiyun
4730*4882a593Smuzhiyun SM_I(sbi)->dirty_info = dirty_i;
4731*4882a593Smuzhiyun mutex_init(&dirty_i->seglist_lock);
4732*4882a593Smuzhiyun
4733*4882a593Smuzhiyun bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
4734*4882a593Smuzhiyun
4735*4882a593Smuzhiyun for (i = 0; i < NR_DIRTY_TYPE; i++) {
4736*4882a593Smuzhiyun dirty_i->dirty_segmap[i] = f2fs_kvzalloc(sbi, bitmap_size,
4737*4882a593Smuzhiyun GFP_KERNEL);
4738*4882a593Smuzhiyun if (!dirty_i->dirty_segmap[i])
4739*4882a593Smuzhiyun return -ENOMEM;
4740*4882a593Smuzhiyun }
4741*4882a593Smuzhiyun
4742*4882a593Smuzhiyun if (__is_large_section(sbi)) {
4743*4882a593Smuzhiyun bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi));
4744*4882a593Smuzhiyun dirty_i->dirty_secmap = f2fs_kvzalloc(sbi,
4745*4882a593Smuzhiyun bitmap_size, GFP_KERNEL);
4746*4882a593Smuzhiyun if (!dirty_i->dirty_secmap)
4747*4882a593Smuzhiyun return -ENOMEM;
4748*4882a593Smuzhiyun }
4749*4882a593Smuzhiyun
4750*4882a593Smuzhiyun init_dirty_segmap(sbi);
4751*4882a593Smuzhiyun return init_victim_secmap(sbi);
4752*4882a593Smuzhiyun }
4753*4882a593Smuzhiyun
sanity_check_curseg(struct f2fs_sb_info * sbi)4754*4882a593Smuzhiyun static int sanity_check_curseg(struct f2fs_sb_info *sbi)
4755*4882a593Smuzhiyun {
4756*4882a593Smuzhiyun int i;
4757*4882a593Smuzhiyun
4758*4882a593Smuzhiyun /*
4759*4882a593Smuzhiyun * In LFS/SSR curseg, .next_blkoff should point to an unused blkaddr;
4760*4882a593Smuzhiyun * In LFS curseg, all blkaddr after .next_blkoff should be unused.
4761*4882a593Smuzhiyun */
4762*4882a593Smuzhiyun for (i = 0; i < NR_PERSISTENT_LOG; i++) {
4763*4882a593Smuzhiyun struct curseg_info *curseg = CURSEG_I(sbi, i);
4764*4882a593Smuzhiyun struct seg_entry *se = get_seg_entry(sbi, curseg->segno);
4765*4882a593Smuzhiyun unsigned int blkofs = curseg->next_blkoff;
4766*4882a593Smuzhiyun
4767*4882a593Smuzhiyun if (f2fs_sb_has_readonly(sbi) &&
4768*4882a593Smuzhiyun i != CURSEG_HOT_DATA && i != CURSEG_HOT_NODE)
4769*4882a593Smuzhiyun continue;
4770*4882a593Smuzhiyun
4771*4882a593Smuzhiyun sanity_check_seg_type(sbi, curseg->seg_type);
4772*4882a593Smuzhiyun
4773*4882a593Smuzhiyun if (curseg->alloc_type != LFS && curseg->alloc_type != SSR) {
4774*4882a593Smuzhiyun f2fs_err(sbi,
4775*4882a593Smuzhiyun "Current segment has invalid alloc_type:%d",
4776*4882a593Smuzhiyun curseg->alloc_type);
4777*4882a593Smuzhiyun return -EFSCORRUPTED;
4778*4882a593Smuzhiyun }
4779*4882a593Smuzhiyun
4780*4882a593Smuzhiyun if (f2fs_test_bit(blkofs, se->cur_valid_map))
4781*4882a593Smuzhiyun goto out;
4782*4882a593Smuzhiyun
4783*4882a593Smuzhiyun if (curseg->alloc_type == SSR)
4784*4882a593Smuzhiyun continue;
4785*4882a593Smuzhiyun
4786*4882a593Smuzhiyun for (blkofs += 1; blkofs < sbi->blocks_per_seg; blkofs++) {
4787*4882a593Smuzhiyun if (!f2fs_test_bit(blkofs, se->cur_valid_map))
4788*4882a593Smuzhiyun continue;
4789*4882a593Smuzhiyun out:
4790*4882a593Smuzhiyun f2fs_err(sbi,
4791*4882a593Smuzhiyun "Current segment's next free block offset is inconsistent with bitmap, logtype:%u, segno:%u, type:%u, next_blkoff:%u, blkofs:%u",
4792*4882a593Smuzhiyun i, curseg->segno, curseg->alloc_type,
4793*4882a593Smuzhiyun curseg->next_blkoff, blkofs);
4794*4882a593Smuzhiyun return -EFSCORRUPTED;
4795*4882a593Smuzhiyun }
4796*4882a593Smuzhiyun }
4797*4882a593Smuzhiyun return 0;
4798*4882a593Smuzhiyun }
4799*4882a593Smuzhiyun
4800*4882a593Smuzhiyun #ifdef CONFIG_BLK_DEV_ZONED
4801*4882a593Smuzhiyun
check_zone_write_pointer(struct f2fs_sb_info * sbi,struct f2fs_dev_info * fdev,struct blk_zone * zone)4802*4882a593Smuzhiyun static int check_zone_write_pointer(struct f2fs_sb_info *sbi,
4803*4882a593Smuzhiyun struct f2fs_dev_info *fdev,
4804*4882a593Smuzhiyun struct blk_zone *zone)
4805*4882a593Smuzhiyun {
4806*4882a593Smuzhiyun unsigned int wp_segno, wp_blkoff, zone_secno, zone_segno, segno;
4807*4882a593Smuzhiyun block_t zone_block, wp_block, last_valid_block;
4808*4882a593Smuzhiyun unsigned int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT;
4809*4882a593Smuzhiyun int i, s, b, ret;
4810*4882a593Smuzhiyun struct seg_entry *se;
4811*4882a593Smuzhiyun
4812*4882a593Smuzhiyun if (zone->type != BLK_ZONE_TYPE_SEQWRITE_REQ)
4813*4882a593Smuzhiyun return 0;
4814*4882a593Smuzhiyun
4815*4882a593Smuzhiyun wp_block = fdev->start_blk + (zone->wp >> log_sectors_per_block);
4816*4882a593Smuzhiyun wp_segno = GET_SEGNO(sbi, wp_block);
4817*4882a593Smuzhiyun wp_blkoff = wp_block - START_BLOCK(sbi, wp_segno);
4818*4882a593Smuzhiyun zone_block = fdev->start_blk + (zone->start >> log_sectors_per_block);
4819*4882a593Smuzhiyun zone_segno = GET_SEGNO(sbi, zone_block);
4820*4882a593Smuzhiyun zone_secno = GET_SEC_FROM_SEG(sbi, zone_segno);
4821*4882a593Smuzhiyun
4822*4882a593Smuzhiyun if (zone_segno >= MAIN_SEGS(sbi))
4823*4882a593Smuzhiyun return 0;
4824*4882a593Smuzhiyun
4825*4882a593Smuzhiyun /*
4826*4882a593Smuzhiyun * Skip check of zones cursegs point to, since
4827*4882a593Smuzhiyun * fix_curseg_write_pointer() checks them.
4828*4882a593Smuzhiyun */
4829*4882a593Smuzhiyun for (i = 0; i < NO_CHECK_TYPE; i++)
4830*4882a593Smuzhiyun if (zone_secno == GET_SEC_FROM_SEG(sbi,
4831*4882a593Smuzhiyun CURSEG_I(sbi, i)->segno))
4832*4882a593Smuzhiyun return 0;
4833*4882a593Smuzhiyun
4834*4882a593Smuzhiyun /*
4835*4882a593Smuzhiyun * Get last valid block of the zone.
4836*4882a593Smuzhiyun */
4837*4882a593Smuzhiyun last_valid_block = zone_block - 1;
4838*4882a593Smuzhiyun for (s = sbi->segs_per_sec - 1; s >= 0; s--) {
4839*4882a593Smuzhiyun segno = zone_segno + s;
4840*4882a593Smuzhiyun se = get_seg_entry(sbi, segno);
4841*4882a593Smuzhiyun for (b = sbi->blocks_per_seg - 1; b >= 0; b--)
4842*4882a593Smuzhiyun if (f2fs_test_bit(b, se->cur_valid_map)) {
4843*4882a593Smuzhiyun last_valid_block = START_BLOCK(sbi, segno) + b;
4844*4882a593Smuzhiyun break;
4845*4882a593Smuzhiyun }
4846*4882a593Smuzhiyun if (last_valid_block >= zone_block)
4847*4882a593Smuzhiyun break;
4848*4882a593Smuzhiyun }
4849*4882a593Smuzhiyun
4850*4882a593Smuzhiyun /*
4851*4882a593Smuzhiyun * If last valid block is beyond the write pointer, report the
4852*4882a593Smuzhiyun * inconsistency. This inconsistency does not cause write error
4853*4882a593Smuzhiyun * because the zone will not be selected for write operation until
4854*4882a593Smuzhiyun * it get discarded. Just report it.
4855*4882a593Smuzhiyun */
4856*4882a593Smuzhiyun if (last_valid_block >= wp_block) {
4857*4882a593Smuzhiyun f2fs_notice(sbi, "Valid block beyond write pointer: "
4858*4882a593Smuzhiyun "valid block[0x%x,0x%x] wp[0x%x,0x%x]",
4859*4882a593Smuzhiyun GET_SEGNO(sbi, last_valid_block),
4860*4882a593Smuzhiyun GET_BLKOFF_FROM_SEG0(sbi, last_valid_block),
4861*4882a593Smuzhiyun wp_segno, wp_blkoff);
4862*4882a593Smuzhiyun return 0;
4863*4882a593Smuzhiyun }
4864*4882a593Smuzhiyun
4865*4882a593Smuzhiyun /*
4866*4882a593Smuzhiyun * If there is no valid block in the zone and if write pointer is
4867*4882a593Smuzhiyun * not at zone start, reset the write pointer.
4868*4882a593Smuzhiyun */
4869*4882a593Smuzhiyun if (last_valid_block + 1 == zone_block && zone->wp != zone->start) {
4870*4882a593Smuzhiyun f2fs_notice(sbi,
4871*4882a593Smuzhiyun "Zone without valid block has non-zero write "
4872*4882a593Smuzhiyun "pointer. Reset the write pointer: wp[0x%x,0x%x]",
4873*4882a593Smuzhiyun wp_segno, wp_blkoff);
4874*4882a593Smuzhiyun ret = __f2fs_issue_discard_zone(sbi, fdev->bdev, zone_block,
4875*4882a593Smuzhiyun zone->len >> log_sectors_per_block);
4876*4882a593Smuzhiyun if (ret) {
4877*4882a593Smuzhiyun f2fs_err(sbi, "Discard zone failed: %s (errno=%d)",
4878*4882a593Smuzhiyun fdev->path, ret);
4879*4882a593Smuzhiyun return ret;
4880*4882a593Smuzhiyun }
4881*4882a593Smuzhiyun }
4882*4882a593Smuzhiyun
4883*4882a593Smuzhiyun return 0;
4884*4882a593Smuzhiyun }
4885*4882a593Smuzhiyun
get_target_zoned_dev(struct f2fs_sb_info * sbi,block_t zone_blkaddr)4886*4882a593Smuzhiyun static struct f2fs_dev_info *get_target_zoned_dev(struct f2fs_sb_info *sbi,
4887*4882a593Smuzhiyun block_t zone_blkaddr)
4888*4882a593Smuzhiyun {
4889*4882a593Smuzhiyun int i;
4890*4882a593Smuzhiyun
4891*4882a593Smuzhiyun for (i = 0; i < sbi->s_ndevs; i++) {
4892*4882a593Smuzhiyun if (!bdev_is_zoned(FDEV(i).bdev))
4893*4882a593Smuzhiyun continue;
4894*4882a593Smuzhiyun if (sbi->s_ndevs == 1 || (FDEV(i).start_blk <= zone_blkaddr &&
4895*4882a593Smuzhiyun zone_blkaddr <= FDEV(i).end_blk))
4896*4882a593Smuzhiyun return &FDEV(i);
4897*4882a593Smuzhiyun }
4898*4882a593Smuzhiyun
4899*4882a593Smuzhiyun return NULL;
4900*4882a593Smuzhiyun }
4901*4882a593Smuzhiyun
report_one_zone_cb(struct blk_zone * zone,unsigned int idx,void * data)4902*4882a593Smuzhiyun static int report_one_zone_cb(struct blk_zone *zone, unsigned int idx,
4903*4882a593Smuzhiyun void *data)
4904*4882a593Smuzhiyun {
4905*4882a593Smuzhiyun memcpy(data, zone, sizeof(struct blk_zone));
4906*4882a593Smuzhiyun return 0;
4907*4882a593Smuzhiyun }
4908*4882a593Smuzhiyun
fix_curseg_write_pointer(struct f2fs_sb_info * sbi,int type)4909*4882a593Smuzhiyun static int fix_curseg_write_pointer(struct f2fs_sb_info *sbi, int type)
4910*4882a593Smuzhiyun {
4911*4882a593Smuzhiyun struct curseg_info *cs = CURSEG_I(sbi, type);
4912*4882a593Smuzhiyun struct f2fs_dev_info *zbd;
4913*4882a593Smuzhiyun struct blk_zone zone;
4914*4882a593Smuzhiyun unsigned int cs_section, wp_segno, wp_blkoff, wp_sector_off;
4915*4882a593Smuzhiyun block_t cs_zone_block, wp_block;
4916*4882a593Smuzhiyun unsigned int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT;
4917*4882a593Smuzhiyun sector_t zone_sector;
4918*4882a593Smuzhiyun int err;
4919*4882a593Smuzhiyun
4920*4882a593Smuzhiyun cs_section = GET_SEC_FROM_SEG(sbi, cs->segno);
4921*4882a593Smuzhiyun cs_zone_block = START_BLOCK(sbi, GET_SEG_FROM_SEC(sbi, cs_section));
4922*4882a593Smuzhiyun
4923*4882a593Smuzhiyun zbd = get_target_zoned_dev(sbi, cs_zone_block);
4924*4882a593Smuzhiyun if (!zbd)
4925*4882a593Smuzhiyun return 0;
4926*4882a593Smuzhiyun
4927*4882a593Smuzhiyun /* report zone for the sector the curseg points to */
4928*4882a593Smuzhiyun zone_sector = (sector_t)(cs_zone_block - zbd->start_blk)
4929*4882a593Smuzhiyun << log_sectors_per_block;
4930*4882a593Smuzhiyun err = blkdev_report_zones(zbd->bdev, zone_sector, 1,
4931*4882a593Smuzhiyun report_one_zone_cb, &zone);
4932*4882a593Smuzhiyun if (err != 1) {
4933*4882a593Smuzhiyun f2fs_err(sbi, "Report zone failed: %s errno=(%d)",
4934*4882a593Smuzhiyun zbd->path, err);
4935*4882a593Smuzhiyun return err;
4936*4882a593Smuzhiyun }
4937*4882a593Smuzhiyun
4938*4882a593Smuzhiyun if (zone.type != BLK_ZONE_TYPE_SEQWRITE_REQ)
4939*4882a593Smuzhiyun return 0;
4940*4882a593Smuzhiyun
4941*4882a593Smuzhiyun wp_block = zbd->start_blk + (zone.wp >> log_sectors_per_block);
4942*4882a593Smuzhiyun wp_segno = GET_SEGNO(sbi, wp_block);
4943*4882a593Smuzhiyun wp_blkoff = wp_block - START_BLOCK(sbi, wp_segno);
4944*4882a593Smuzhiyun wp_sector_off = zone.wp & GENMASK(log_sectors_per_block - 1, 0);
4945*4882a593Smuzhiyun
4946*4882a593Smuzhiyun if (cs->segno == wp_segno && cs->next_blkoff == wp_blkoff &&
4947*4882a593Smuzhiyun wp_sector_off == 0)
4948*4882a593Smuzhiyun return 0;
4949*4882a593Smuzhiyun
4950*4882a593Smuzhiyun f2fs_notice(sbi, "Unaligned curseg[%d] with write pointer: "
4951*4882a593Smuzhiyun "curseg[0x%x,0x%x] wp[0x%x,0x%x]",
4952*4882a593Smuzhiyun type, cs->segno, cs->next_blkoff, wp_segno, wp_blkoff);
4953*4882a593Smuzhiyun
4954*4882a593Smuzhiyun f2fs_notice(sbi, "Assign new section to curseg[%d]: "
4955*4882a593Smuzhiyun "curseg[0x%x,0x%x]", type, cs->segno, cs->next_blkoff);
4956*4882a593Smuzhiyun
4957*4882a593Smuzhiyun f2fs_allocate_new_section(sbi, type, true);
4958*4882a593Smuzhiyun
4959*4882a593Smuzhiyun /* check consistency of the zone curseg pointed to */
4960*4882a593Smuzhiyun if (check_zone_write_pointer(sbi, zbd, &zone))
4961*4882a593Smuzhiyun return -EIO;
4962*4882a593Smuzhiyun
4963*4882a593Smuzhiyun /* check newly assigned zone */
4964*4882a593Smuzhiyun cs_section = GET_SEC_FROM_SEG(sbi, cs->segno);
4965*4882a593Smuzhiyun cs_zone_block = START_BLOCK(sbi, GET_SEG_FROM_SEC(sbi, cs_section));
4966*4882a593Smuzhiyun
4967*4882a593Smuzhiyun zbd = get_target_zoned_dev(sbi, cs_zone_block);
4968*4882a593Smuzhiyun if (!zbd)
4969*4882a593Smuzhiyun return 0;
4970*4882a593Smuzhiyun
4971*4882a593Smuzhiyun zone_sector = (sector_t)(cs_zone_block - zbd->start_blk)
4972*4882a593Smuzhiyun << log_sectors_per_block;
4973*4882a593Smuzhiyun err = blkdev_report_zones(zbd->bdev, zone_sector, 1,
4974*4882a593Smuzhiyun report_one_zone_cb, &zone);
4975*4882a593Smuzhiyun if (err != 1) {
4976*4882a593Smuzhiyun f2fs_err(sbi, "Report zone failed: %s errno=(%d)",
4977*4882a593Smuzhiyun zbd->path, err);
4978*4882a593Smuzhiyun return err;
4979*4882a593Smuzhiyun }
4980*4882a593Smuzhiyun
4981*4882a593Smuzhiyun if (zone.type != BLK_ZONE_TYPE_SEQWRITE_REQ)
4982*4882a593Smuzhiyun return 0;
4983*4882a593Smuzhiyun
4984*4882a593Smuzhiyun if (zone.wp != zone.start) {
4985*4882a593Smuzhiyun f2fs_notice(sbi,
4986*4882a593Smuzhiyun "New zone for curseg[%d] is not yet discarded. "
4987*4882a593Smuzhiyun "Reset the zone: curseg[0x%x,0x%x]",
4988*4882a593Smuzhiyun type, cs->segno, cs->next_blkoff);
4989*4882a593Smuzhiyun err = __f2fs_issue_discard_zone(sbi, zbd->bdev,
4990*4882a593Smuzhiyun zone_sector >> log_sectors_per_block,
4991*4882a593Smuzhiyun zone.len >> log_sectors_per_block);
4992*4882a593Smuzhiyun if (err) {
4993*4882a593Smuzhiyun f2fs_err(sbi, "Discard zone failed: %s (errno=%d)",
4994*4882a593Smuzhiyun zbd->path, err);
4995*4882a593Smuzhiyun return err;
4996*4882a593Smuzhiyun }
4997*4882a593Smuzhiyun }
4998*4882a593Smuzhiyun
4999*4882a593Smuzhiyun return 0;
5000*4882a593Smuzhiyun }
5001*4882a593Smuzhiyun
f2fs_fix_curseg_write_pointer(struct f2fs_sb_info * sbi)5002*4882a593Smuzhiyun int f2fs_fix_curseg_write_pointer(struct f2fs_sb_info *sbi)
5003*4882a593Smuzhiyun {
5004*4882a593Smuzhiyun int i, ret;
5005*4882a593Smuzhiyun
5006*4882a593Smuzhiyun for (i = 0; i < NR_PERSISTENT_LOG; i++) {
5007*4882a593Smuzhiyun ret = fix_curseg_write_pointer(sbi, i);
5008*4882a593Smuzhiyun if (ret)
5009*4882a593Smuzhiyun return ret;
5010*4882a593Smuzhiyun }
5011*4882a593Smuzhiyun
5012*4882a593Smuzhiyun return 0;
5013*4882a593Smuzhiyun }
5014*4882a593Smuzhiyun
5015*4882a593Smuzhiyun struct check_zone_write_pointer_args {
5016*4882a593Smuzhiyun struct f2fs_sb_info *sbi;
5017*4882a593Smuzhiyun struct f2fs_dev_info *fdev;
5018*4882a593Smuzhiyun };
5019*4882a593Smuzhiyun
check_zone_write_pointer_cb(struct blk_zone * zone,unsigned int idx,void * data)5020*4882a593Smuzhiyun static int check_zone_write_pointer_cb(struct blk_zone *zone, unsigned int idx,
5021*4882a593Smuzhiyun void *data)
5022*4882a593Smuzhiyun {
5023*4882a593Smuzhiyun struct check_zone_write_pointer_args *args;
5024*4882a593Smuzhiyun
5025*4882a593Smuzhiyun args = (struct check_zone_write_pointer_args *)data;
5026*4882a593Smuzhiyun
5027*4882a593Smuzhiyun return check_zone_write_pointer(args->sbi, args->fdev, zone);
5028*4882a593Smuzhiyun }
5029*4882a593Smuzhiyun
f2fs_check_write_pointer(struct f2fs_sb_info * sbi)5030*4882a593Smuzhiyun int f2fs_check_write_pointer(struct f2fs_sb_info *sbi)
5031*4882a593Smuzhiyun {
5032*4882a593Smuzhiyun int i, ret;
5033*4882a593Smuzhiyun struct check_zone_write_pointer_args args;
5034*4882a593Smuzhiyun
5035*4882a593Smuzhiyun for (i = 0; i < sbi->s_ndevs; i++) {
5036*4882a593Smuzhiyun if (!bdev_is_zoned(FDEV(i).bdev))
5037*4882a593Smuzhiyun continue;
5038*4882a593Smuzhiyun
5039*4882a593Smuzhiyun args.sbi = sbi;
5040*4882a593Smuzhiyun args.fdev = &FDEV(i);
5041*4882a593Smuzhiyun ret = blkdev_report_zones(FDEV(i).bdev, 0, BLK_ALL_ZONES,
5042*4882a593Smuzhiyun check_zone_write_pointer_cb, &args);
5043*4882a593Smuzhiyun if (ret < 0)
5044*4882a593Smuzhiyun return ret;
5045*4882a593Smuzhiyun }
5046*4882a593Smuzhiyun
5047*4882a593Smuzhiyun return 0;
5048*4882a593Smuzhiyun }
5049*4882a593Smuzhiyun
is_conv_zone(struct f2fs_sb_info * sbi,unsigned int zone_idx,unsigned int dev_idx)5050*4882a593Smuzhiyun static bool is_conv_zone(struct f2fs_sb_info *sbi, unsigned int zone_idx,
5051*4882a593Smuzhiyun unsigned int dev_idx)
5052*4882a593Smuzhiyun {
5053*4882a593Smuzhiyun if (!bdev_is_zoned(FDEV(dev_idx).bdev))
5054*4882a593Smuzhiyun return true;
5055*4882a593Smuzhiyun return !test_bit(zone_idx, FDEV(dev_idx).blkz_seq);
5056*4882a593Smuzhiyun }
5057*4882a593Smuzhiyun
5058*4882a593Smuzhiyun /* Return the zone index in the given device */
get_zone_idx(struct f2fs_sb_info * sbi,unsigned int secno,int dev_idx)5059*4882a593Smuzhiyun static unsigned int get_zone_idx(struct f2fs_sb_info *sbi, unsigned int secno,
5060*4882a593Smuzhiyun int dev_idx)
5061*4882a593Smuzhiyun {
5062*4882a593Smuzhiyun block_t sec_start_blkaddr = START_BLOCK(sbi, GET_SEG_FROM_SEC(sbi, secno));
5063*4882a593Smuzhiyun
5064*4882a593Smuzhiyun return (sec_start_blkaddr - FDEV(dev_idx).start_blk) >>
5065*4882a593Smuzhiyun sbi->log_blocks_per_blkz;
5066*4882a593Smuzhiyun }
5067*4882a593Smuzhiyun
5068*4882a593Smuzhiyun /*
5069*4882a593Smuzhiyun * Return the usable segments in a section based on the zone's
5070*4882a593Smuzhiyun * corresponding zone capacity. Zone is equal to a section.
5071*4882a593Smuzhiyun */
f2fs_usable_zone_segs_in_sec(struct f2fs_sb_info * sbi,unsigned int segno)5072*4882a593Smuzhiyun static inline unsigned int f2fs_usable_zone_segs_in_sec(
5073*4882a593Smuzhiyun struct f2fs_sb_info *sbi, unsigned int segno)
5074*4882a593Smuzhiyun {
5075*4882a593Smuzhiyun unsigned int dev_idx, zone_idx, unusable_segs_in_sec;
5076*4882a593Smuzhiyun
5077*4882a593Smuzhiyun dev_idx = f2fs_target_device_index(sbi, START_BLOCK(sbi, segno));
5078*4882a593Smuzhiyun zone_idx = get_zone_idx(sbi, GET_SEC_FROM_SEG(sbi, segno), dev_idx);
5079*4882a593Smuzhiyun
5080*4882a593Smuzhiyun /* Conventional zone's capacity is always equal to zone size */
5081*4882a593Smuzhiyun if (is_conv_zone(sbi, zone_idx, dev_idx))
5082*4882a593Smuzhiyun return sbi->segs_per_sec;
5083*4882a593Smuzhiyun
5084*4882a593Smuzhiyun /*
5085*4882a593Smuzhiyun * If the zone_capacity_blocks array is NULL, then zone capacity
5086*4882a593Smuzhiyun * is equal to the zone size for all zones
5087*4882a593Smuzhiyun */
5088*4882a593Smuzhiyun if (!FDEV(dev_idx).zone_capacity_blocks)
5089*4882a593Smuzhiyun return sbi->segs_per_sec;
5090*4882a593Smuzhiyun
5091*4882a593Smuzhiyun /* Get the segment count beyond zone capacity block */
5092*4882a593Smuzhiyun unusable_segs_in_sec = (sbi->blocks_per_blkz -
5093*4882a593Smuzhiyun FDEV(dev_idx).zone_capacity_blocks[zone_idx]) >>
5094*4882a593Smuzhiyun sbi->log_blocks_per_seg;
5095*4882a593Smuzhiyun return sbi->segs_per_sec - unusable_segs_in_sec;
5096*4882a593Smuzhiyun }
5097*4882a593Smuzhiyun
5098*4882a593Smuzhiyun /*
5099*4882a593Smuzhiyun * Return the number of usable blocks in a segment. The number of blocks
5100*4882a593Smuzhiyun * returned is always equal to the number of blocks in a segment for
5101*4882a593Smuzhiyun * segments fully contained within a sequential zone capacity or a
5102*4882a593Smuzhiyun * conventional zone. For segments partially contained in a sequential
5103*4882a593Smuzhiyun * zone capacity, the number of usable blocks up to the zone capacity
5104*4882a593Smuzhiyun * is returned. 0 is returned in all other cases.
5105*4882a593Smuzhiyun */
f2fs_usable_zone_blks_in_seg(struct f2fs_sb_info * sbi,unsigned int segno)5106*4882a593Smuzhiyun static inline unsigned int f2fs_usable_zone_blks_in_seg(
5107*4882a593Smuzhiyun struct f2fs_sb_info *sbi, unsigned int segno)
5108*4882a593Smuzhiyun {
5109*4882a593Smuzhiyun block_t seg_start, sec_start_blkaddr, sec_cap_blkaddr;
5110*4882a593Smuzhiyun unsigned int zone_idx, dev_idx, secno;
5111*4882a593Smuzhiyun
5112*4882a593Smuzhiyun secno = GET_SEC_FROM_SEG(sbi, segno);
5113*4882a593Smuzhiyun seg_start = START_BLOCK(sbi, segno);
5114*4882a593Smuzhiyun dev_idx = f2fs_target_device_index(sbi, seg_start);
5115*4882a593Smuzhiyun zone_idx = get_zone_idx(sbi, secno, dev_idx);
5116*4882a593Smuzhiyun
5117*4882a593Smuzhiyun /*
5118*4882a593Smuzhiyun * Conventional zone's capacity is always equal to zone size,
5119*4882a593Smuzhiyun * so, blocks per segment is unchanged.
5120*4882a593Smuzhiyun */
5121*4882a593Smuzhiyun if (is_conv_zone(sbi, zone_idx, dev_idx))
5122*4882a593Smuzhiyun return sbi->blocks_per_seg;
5123*4882a593Smuzhiyun
5124*4882a593Smuzhiyun if (!FDEV(dev_idx).zone_capacity_blocks)
5125*4882a593Smuzhiyun return sbi->blocks_per_seg;
5126*4882a593Smuzhiyun
5127*4882a593Smuzhiyun sec_start_blkaddr = START_BLOCK(sbi, GET_SEG_FROM_SEC(sbi, secno));
5128*4882a593Smuzhiyun sec_cap_blkaddr = sec_start_blkaddr +
5129*4882a593Smuzhiyun FDEV(dev_idx).zone_capacity_blocks[zone_idx];
5130*4882a593Smuzhiyun
5131*4882a593Smuzhiyun /*
5132*4882a593Smuzhiyun * If segment starts before zone capacity and spans beyond
5133*4882a593Smuzhiyun * zone capacity, then usable blocks are from seg start to
5134*4882a593Smuzhiyun * zone capacity. If the segment starts after the zone capacity,
5135*4882a593Smuzhiyun * then there are no usable blocks.
5136*4882a593Smuzhiyun */
5137*4882a593Smuzhiyun if (seg_start >= sec_cap_blkaddr)
5138*4882a593Smuzhiyun return 0;
5139*4882a593Smuzhiyun if (seg_start + sbi->blocks_per_seg > sec_cap_blkaddr)
5140*4882a593Smuzhiyun return sec_cap_blkaddr - seg_start;
5141*4882a593Smuzhiyun
5142*4882a593Smuzhiyun return sbi->blocks_per_seg;
5143*4882a593Smuzhiyun }
5144*4882a593Smuzhiyun #else
f2fs_fix_curseg_write_pointer(struct f2fs_sb_info * sbi)5145*4882a593Smuzhiyun int f2fs_fix_curseg_write_pointer(struct f2fs_sb_info *sbi)
5146*4882a593Smuzhiyun {
5147*4882a593Smuzhiyun return 0;
5148*4882a593Smuzhiyun }
5149*4882a593Smuzhiyun
f2fs_check_write_pointer(struct f2fs_sb_info * sbi)5150*4882a593Smuzhiyun int f2fs_check_write_pointer(struct f2fs_sb_info *sbi)
5151*4882a593Smuzhiyun {
5152*4882a593Smuzhiyun return 0;
5153*4882a593Smuzhiyun }
5154*4882a593Smuzhiyun
f2fs_usable_zone_blks_in_seg(struct f2fs_sb_info * sbi,unsigned int segno)5155*4882a593Smuzhiyun static inline unsigned int f2fs_usable_zone_blks_in_seg(struct f2fs_sb_info *sbi,
5156*4882a593Smuzhiyun unsigned int segno)
5157*4882a593Smuzhiyun {
5158*4882a593Smuzhiyun return 0;
5159*4882a593Smuzhiyun }
5160*4882a593Smuzhiyun
f2fs_usable_zone_segs_in_sec(struct f2fs_sb_info * sbi,unsigned int segno)5161*4882a593Smuzhiyun static inline unsigned int f2fs_usable_zone_segs_in_sec(struct f2fs_sb_info *sbi,
5162*4882a593Smuzhiyun unsigned int segno)
5163*4882a593Smuzhiyun {
5164*4882a593Smuzhiyun return 0;
5165*4882a593Smuzhiyun }
5166*4882a593Smuzhiyun #endif
f2fs_usable_blks_in_seg(struct f2fs_sb_info * sbi,unsigned int segno)5167*4882a593Smuzhiyun unsigned int f2fs_usable_blks_in_seg(struct f2fs_sb_info *sbi,
5168*4882a593Smuzhiyun unsigned int segno)
5169*4882a593Smuzhiyun {
5170*4882a593Smuzhiyun if (f2fs_sb_has_blkzoned(sbi))
5171*4882a593Smuzhiyun return f2fs_usable_zone_blks_in_seg(sbi, segno);
5172*4882a593Smuzhiyun
5173*4882a593Smuzhiyun return sbi->blocks_per_seg;
5174*4882a593Smuzhiyun }
5175*4882a593Smuzhiyun
f2fs_usable_segs_in_sec(struct f2fs_sb_info * sbi,unsigned int segno)5176*4882a593Smuzhiyun unsigned int f2fs_usable_segs_in_sec(struct f2fs_sb_info *sbi,
5177*4882a593Smuzhiyun unsigned int segno)
5178*4882a593Smuzhiyun {
5179*4882a593Smuzhiyun if (f2fs_sb_has_blkzoned(sbi))
5180*4882a593Smuzhiyun return f2fs_usable_zone_segs_in_sec(sbi, segno);
5181*4882a593Smuzhiyun
5182*4882a593Smuzhiyun return sbi->segs_per_sec;
5183*4882a593Smuzhiyun }
5184*4882a593Smuzhiyun
5185*4882a593Smuzhiyun /*
5186*4882a593Smuzhiyun * Update min, max modified time for cost-benefit GC algorithm
5187*4882a593Smuzhiyun */
init_min_max_mtime(struct f2fs_sb_info * sbi)5188*4882a593Smuzhiyun static void init_min_max_mtime(struct f2fs_sb_info *sbi)
5189*4882a593Smuzhiyun {
5190*4882a593Smuzhiyun struct sit_info *sit_i = SIT_I(sbi);
5191*4882a593Smuzhiyun unsigned int segno;
5192*4882a593Smuzhiyun
5193*4882a593Smuzhiyun down_write(&sit_i->sentry_lock);
5194*4882a593Smuzhiyun
5195*4882a593Smuzhiyun sit_i->min_mtime = ULLONG_MAX;
5196*4882a593Smuzhiyun
5197*4882a593Smuzhiyun for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
5198*4882a593Smuzhiyun unsigned int i;
5199*4882a593Smuzhiyun unsigned long long mtime = 0;
5200*4882a593Smuzhiyun
5201*4882a593Smuzhiyun for (i = 0; i < sbi->segs_per_sec; i++)
5202*4882a593Smuzhiyun mtime += get_seg_entry(sbi, segno + i)->mtime;
5203*4882a593Smuzhiyun
5204*4882a593Smuzhiyun mtime = div_u64(mtime, sbi->segs_per_sec);
5205*4882a593Smuzhiyun
5206*4882a593Smuzhiyun if (sit_i->min_mtime > mtime)
5207*4882a593Smuzhiyun sit_i->min_mtime = mtime;
5208*4882a593Smuzhiyun }
5209*4882a593Smuzhiyun sit_i->max_mtime = get_mtime(sbi, false);
5210*4882a593Smuzhiyun sit_i->dirty_max_mtime = 0;
5211*4882a593Smuzhiyun up_write(&sit_i->sentry_lock);
5212*4882a593Smuzhiyun }
5213*4882a593Smuzhiyun
f2fs_build_segment_manager(struct f2fs_sb_info * sbi)5214*4882a593Smuzhiyun int f2fs_build_segment_manager(struct f2fs_sb_info *sbi)
5215*4882a593Smuzhiyun {
5216*4882a593Smuzhiyun struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
5217*4882a593Smuzhiyun struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
5218*4882a593Smuzhiyun struct f2fs_sm_info *sm_info;
5219*4882a593Smuzhiyun int err;
5220*4882a593Smuzhiyun
5221*4882a593Smuzhiyun sm_info = f2fs_kzalloc(sbi, sizeof(struct f2fs_sm_info), GFP_KERNEL);
5222*4882a593Smuzhiyun if (!sm_info)
5223*4882a593Smuzhiyun return -ENOMEM;
5224*4882a593Smuzhiyun
5225*4882a593Smuzhiyun /* init sm info */
5226*4882a593Smuzhiyun sbi->sm_info = sm_info;
5227*4882a593Smuzhiyun sm_info->seg0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr);
5228*4882a593Smuzhiyun sm_info->main_blkaddr = le32_to_cpu(raw_super->main_blkaddr);
5229*4882a593Smuzhiyun sm_info->segment_count = le32_to_cpu(raw_super->segment_count);
5230*4882a593Smuzhiyun sm_info->reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count);
5231*4882a593Smuzhiyun sm_info->ovp_segments = le32_to_cpu(ckpt->overprov_segment_count);
5232*4882a593Smuzhiyun sm_info->main_segments = le32_to_cpu(raw_super->segment_count_main);
5233*4882a593Smuzhiyun sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr);
5234*4882a593Smuzhiyun sm_info->rec_prefree_segments = sm_info->main_segments *
5235*4882a593Smuzhiyun DEF_RECLAIM_PREFREE_SEGMENTS / 100;
5236*4882a593Smuzhiyun if (sm_info->rec_prefree_segments > DEF_MAX_RECLAIM_PREFREE_SEGMENTS)
5237*4882a593Smuzhiyun sm_info->rec_prefree_segments = DEF_MAX_RECLAIM_PREFREE_SEGMENTS;
5238*4882a593Smuzhiyun
5239*4882a593Smuzhiyun if (!f2fs_lfs_mode(sbi))
5240*4882a593Smuzhiyun sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC;
5241*4882a593Smuzhiyun sm_info->min_ipu_util = DEF_MIN_IPU_UTIL;
5242*4882a593Smuzhiyun sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS;
5243*4882a593Smuzhiyun sm_info->min_seq_blocks = sbi->blocks_per_seg * sbi->segs_per_sec;
5244*4882a593Smuzhiyun sm_info->min_hot_blocks = DEF_MIN_HOT_BLOCKS;
5245*4882a593Smuzhiyun sm_info->min_ssr_sections = reserved_sections(sbi);
5246*4882a593Smuzhiyun
5247*4882a593Smuzhiyun INIT_LIST_HEAD(&sm_info->sit_entry_set);
5248*4882a593Smuzhiyun
5249*4882a593Smuzhiyun init_f2fs_rwsem(&sm_info->curseg_lock);
5250*4882a593Smuzhiyun
5251*4882a593Smuzhiyun if (!f2fs_readonly(sbi->sb)) {
5252*4882a593Smuzhiyun err = f2fs_create_flush_cmd_control(sbi);
5253*4882a593Smuzhiyun if (err)
5254*4882a593Smuzhiyun return err;
5255*4882a593Smuzhiyun }
5256*4882a593Smuzhiyun
5257*4882a593Smuzhiyun err = create_discard_cmd_control(sbi);
5258*4882a593Smuzhiyun if (err)
5259*4882a593Smuzhiyun return err;
5260*4882a593Smuzhiyun
5261*4882a593Smuzhiyun err = build_sit_info(sbi);
5262*4882a593Smuzhiyun if (err)
5263*4882a593Smuzhiyun return err;
5264*4882a593Smuzhiyun err = build_free_segmap(sbi);
5265*4882a593Smuzhiyun if (err)
5266*4882a593Smuzhiyun return err;
5267*4882a593Smuzhiyun err = build_curseg(sbi);
5268*4882a593Smuzhiyun if (err)
5269*4882a593Smuzhiyun return err;
5270*4882a593Smuzhiyun
5271*4882a593Smuzhiyun /* reinit free segmap based on SIT */
5272*4882a593Smuzhiyun err = build_sit_entries(sbi);
5273*4882a593Smuzhiyun if (err)
5274*4882a593Smuzhiyun return err;
5275*4882a593Smuzhiyun
5276*4882a593Smuzhiyun init_free_segmap(sbi);
5277*4882a593Smuzhiyun err = build_dirty_segmap(sbi);
5278*4882a593Smuzhiyun if (err)
5279*4882a593Smuzhiyun return err;
5280*4882a593Smuzhiyun
5281*4882a593Smuzhiyun err = sanity_check_curseg(sbi);
5282*4882a593Smuzhiyun if (err)
5283*4882a593Smuzhiyun return err;
5284*4882a593Smuzhiyun
5285*4882a593Smuzhiyun init_min_max_mtime(sbi);
5286*4882a593Smuzhiyun return 0;
5287*4882a593Smuzhiyun }
5288*4882a593Smuzhiyun
discard_dirty_segmap(struct f2fs_sb_info * sbi,enum dirty_type dirty_type)5289*4882a593Smuzhiyun static void discard_dirty_segmap(struct f2fs_sb_info *sbi,
5290*4882a593Smuzhiyun enum dirty_type dirty_type)
5291*4882a593Smuzhiyun {
5292*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
5293*4882a593Smuzhiyun
5294*4882a593Smuzhiyun mutex_lock(&dirty_i->seglist_lock);
5295*4882a593Smuzhiyun kvfree(dirty_i->dirty_segmap[dirty_type]);
5296*4882a593Smuzhiyun dirty_i->nr_dirty[dirty_type] = 0;
5297*4882a593Smuzhiyun mutex_unlock(&dirty_i->seglist_lock);
5298*4882a593Smuzhiyun }
5299*4882a593Smuzhiyun
destroy_victim_secmap(struct f2fs_sb_info * sbi)5300*4882a593Smuzhiyun static void destroy_victim_secmap(struct f2fs_sb_info *sbi)
5301*4882a593Smuzhiyun {
5302*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
5303*4882a593Smuzhiyun
5304*4882a593Smuzhiyun kvfree(dirty_i->victim_secmap);
5305*4882a593Smuzhiyun }
5306*4882a593Smuzhiyun
destroy_dirty_segmap(struct f2fs_sb_info * sbi)5307*4882a593Smuzhiyun static void destroy_dirty_segmap(struct f2fs_sb_info *sbi)
5308*4882a593Smuzhiyun {
5309*4882a593Smuzhiyun struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
5310*4882a593Smuzhiyun int i;
5311*4882a593Smuzhiyun
5312*4882a593Smuzhiyun if (!dirty_i)
5313*4882a593Smuzhiyun return;
5314*4882a593Smuzhiyun
5315*4882a593Smuzhiyun /* discard pre-free/dirty segments list */
5316*4882a593Smuzhiyun for (i = 0; i < NR_DIRTY_TYPE; i++)
5317*4882a593Smuzhiyun discard_dirty_segmap(sbi, i);
5318*4882a593Smuzhiyun
5319*4882a593Smuzhiyun if (__is_large_section(sbi)) {
5320*4882a593Smuzhiyun mutex_lock(&dirty_i->seglist_lock);
5321*4882a593Smuzhiyun kvfree(dirty_i->dirty_secmap);
5322*4882a593Smuzhiyun mutex_unlock(&dirty_i->seglist_lock);
5323*4882a593Smuzhiyun }
5324*4882a593Smuzhiyun
5325*4882a593Smuzhiyun destroy_victim_secmap(sbi);
5326*4882a593Smuzhiyun SM_I(sbi)->dirty_info = NULL;
5327*4882a593Smuzhiyun kfree(dirty_i);
5328*4882a593Smuzhiyun }
5329*4882a593Smuzhiyun
destroy_curseg(struct f2fs_sb_info * sbi)5330*4882a593Smuzhiyun static void destroy_curseg(struct f2fs_sb_info *sbi)
5331*4882a593Smuzhiyun {
5332*4882a593Smuzhiyun struct curseg_info *array = SM_I(sbi)->curseg_array;
5333*4882a593Smuzhiyun int i;
5334*4882a593Smuzhiyun
5335*4882a593Smuzhiyun if (!array)
5336*4882a593Smuzhiyun return;
5337*4882a593Smuzhiyun SM_I(sbi)->curseg_array = NULL;
5338*4882a593Smuzhiyun for (i = 0; i < NR_CURSEG_TYPE; i++) {
5339*4882a593Smuzhiyun kfree(array[i].sum_blk);
5340*4882a593Smuzhiyun kfree(array[i].journal);
5341*4882a593Smuzhiyun }
5342*4882a593Smuzhiyun kfree(array);
5343*4882a593Smuzhiyun }
5344*4882a593Smuzhiyun
destroy_free_segmap(struct f2fs_sb_info * sbi)5345*4882a593Smuzhiyun static void destroy_free_segmap(struct f2fs_sb_info *sbi)
5346*4882a593Smuzhiyun {
5347*4882a593Smuzhiyun struct free_segmap_info *free_i = SM_I(sbi)->free_info;
5348*4882a593Smuzhiyun
5349*4882a593Smuzhiyun if (!free_i)
5350*4882a593Smuzhiyun return;
5351*4882a593Smuzhiyun SM_I(sbi)->free_info = NULL;
5352*4882a593Smuzhiyun kvfree(free_i->free_segmap);
5353*4882a593Smuzhiyun kvfree(free_i->free_secmap);
5354*4882a593Smuzhiyun kfree(free_i);
5355*4882a593Smuzhiyun }
5356*4882a593Smuzhiyun
destroy_sit_info(struct f2fs_sb_info * sbi)5357*4882a593Smuzhiyun static void destroy_sit_info(struct f2fs_sb_info *sbi)
5358*4882a593Smuzhiyun {
5359*4882a593Smuzhiyun struct sit_info *sit_i = SIT_I(sbi);
5360*4882a593Smuzhiyun
5361*4882a593Smuzhiyun if (!sit_i)
5362*4882a593Smuzhiyun return;
5363*4882a593Smuzhiyun
5364*4882a593Smuzhiyun if (sit_i->sentries)
5365*4882a593Smuzhiyun kvfree(sit_i->bitmap);
5366*4882a593Smuzhiyun kfree(sit_i->tmp_map);
5367*4882a593Smuzhiyun
5368*4882a593Smuzhiyun kvfree(sit_i->sentries);
5369*4882a593Smuzhiyun kvfree(sit_i->sec_entries);
5370*4882a593Smuzhiyun kvfree(sit_i->dirty_sentries_bitmap);
5371*4882a593Smuzhiyun
5372*4882a593Smuzhiyun SM_I(sbi)->sit_info = NULL;
5373*4882a593Smuzhiyun kvfree(sit_i->sit_bitmap);
5374*4882a593Smuzhiyun #ifdef CONFIG_F2FS_CHECK_FS
5375*4882a593Smuzhiyun kvfree(sit_i->sit_bitmap_mir);
5376*4882a593Smuzhiyun kvfree(sit_i->invalid_segmap);
5377*4882a593Smuzhiyun #endif
5378*4882a593Smuzhiyun kfree(sit_i);
5379*4882a593Smuzhiyun }
5380*4882a593Smuzhiyun
f2fs_destroy_segment_manager(struct f2fs_sb_info * sbi)5381*4882a593Smuzhiyun void f2fs_destroy_segment_manager(struct f2fs_sb_info *sbi)
5382*4882a593Smuzhiyun {
5383*4882a593Smuzhiyun struct f2fs_sm_info *sm_info = SM_I(sbi);
5384*4882a593Smuzhiyun
5385*4882a593Smuzhiyun if (!sm_info)
5386*4882a593Smuzhiyun return;
5387*4882a593Smuzhiyun f2fs_destroy_flush_cmd_control(sbi, true);
5388*4882a593Smuzhiyun destroy_discard_cmd_control(sbi);
5389*4882a593Smuzhiyun destroy_dirty_segmap(sbi);
5390*4882a593Smuzhiyun destroy_curseg(sbi);
5391*4882a593Smuzhiyun destroy_free_segmap(sbi);
5392*4882a593Smuzhiyun destroy_sit_info(sbi);
5393*4882a593Smuzhiyun sbi->sm_info = NULL;
5394*4882a593Smuzhiyun kfree(sm_info);
5395*4882a593Smuzhiyun }
5396*4882a593Smuzhiyun
f2fs_create_segment_manager_caches(void)5397*4882a593Smuzhiyun int __init f2fs_create_segment_manager_caches(void)
5398*4882a593Smuzhiyun {
5399*4882a593Smuzhiyun discard_entry_slab = f2fs_kmem_cache_create("f2fs_discard_entry",
5400*4882a593Smuzhiyun sizeof(struct discard_entry));
5401*4882a593Smuzhiyun if (!discard_entry_slab)
5402*4882a593Smuzhiyun goto fail;
5403*4882a593Smuzhiyun
5404*4882a593Smuzhiyun discard_cmd_slab = f2fs_kmem_cache_create("f2fs_discard_cmd",
5405*4882a593Smuzhiyun sizeof(struct discard_cmd));
5406*4882a593Smuzhiyun if (!discard_cmd_slab)
5407*4882a593Smuzhiyun goto destroy_discard_entry;
5408*4882a593Smuzhiyun
5409*4882a593Smuzhiyun sit_entry_set_slab = f2fs_kmem_cache_create("f2fs_sit_entry_set",
5410*4882a593Smuzhiyun sizeof(struct sit_entry_set));
5411*4882a593Smuzhiyun if (!sit_entry_set_slab)
5412*4882a593Smuzhiyun goto destroy_discard_cmd;
5413*4882a593Smuzhiyun
5414*4882a593Smuzhiyun inmem_entry_slab = f2fs_kmem_cache_create("f2fs_inmem_page_entry",
5415*4882a593Smuzhiyun sizeof(struct inmem_pages));
5416*4882a593Smuzhiyun if (!inmem_entry_slab)
5417*4882a593Smuzhiyun goto destroy_sit_entry_set;
5418*4882a593Smuzhiyun return 0;
5419*4882a593Smuzhiyun
5420*4882a593Smuzhiyun destroy_sit_entry_set:
5421*4882a593Smuzhiyun kmem_cache_destroy(sit_entry_set_slab);
5422*4882a593Smuzhiyun destroy_discard_cmd:
5423*4882a593Smuzhiyun kmem_cache_destroy(discard_cmd_slab);
5424*4882a593Smuzhiyun destroy_discard_entry:
5425*4882a593Smuzhiyun kmem_cache_destroy(discard_entry_slab);
5426*4882a593Smuzhiyun fail:
5427*4882a593Smuzhiyun return -ENOMEM;
5428*4882a593Smuzhiyun }
5429*4882a593Smuzhiyun
f2fs_destroy_segment_manager_caches(void)5430*4882a593Smuzhiyun void f2fs_destroy_segment_manager_caches(void)
5431*4882a593Smuzhiyun {
5432*4882a593Smuzhiyun kmem_cache_destroy(sit_entry_set_slab);
5433*4882a593Smuzhiyun kmem_cache_destroy(discard_cmd_slab);
5434*4882a593Smuzhiyun kmem_cache_destroy(discard_entry_slab);
5435*4882a593Smuzhiyun kmem_cache_destroy(inmem_entry_slab);
5436*4882a593Smuzhiyun }
5437