mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 10:31:46 +09:00
FROMGIT: f2fs: factor out discard_cmd usage from general rb_tree use
This is a second part to remove the mixed use of rb_tree in discard_cmd from
extent_cache.
This should also fix arm32 memory alignment issue caused by shared rb_entry.
[struct discard_cmd] [struct rb_entry]
[0] struct rb_node rb_node; [0] struct rb_node rb_node;
union { union {
struct { struct {
[16] block_t lstart; [12] unsigned int ofs;
block_t len; unsigned int len;
};
unsigned long long key;
} __packed;
Cc: <stable@vger.kernel.org>
Fixes: 004b686218 ("f2fs: use rb-tree to track pending discard commands")
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
(cherry picked from commit 7e9775a516ff6c1e73ee2b42ec563cafee38f42f
https: //git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git dev)
Change-Id: I61ee2b6bcc283406ca40f0ed7c3146de1e813d61
This commit is contained in:
@@ -192,7 +192,7 @@ static struct rb_entry *__lookup_rb_tree_slow(struct rb_root_cached *root,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rb_entry *f2fs_lookup_rb_tree(struct rb_root_cached *root,
|
static struct rb_entry *f2fs_lookup_rb_tree(struct rb_root_cached *root,
|
||||||
struct rb_entry *cached_re, unsigned int ofs)
|
struct rb_entry *cached_re, unsigned int ofs)
|
||||||
{
|
{
|
||||||
struct rb_entry *re;
|
struct rb_entry *re;
|
||||||
@@ -204,7 +204,7 @@ struct rb_entry *f2fs_lookup_rb_tree(struct rb_root_cached *root,
|
|||||||
return re;
|
return re;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rb_node **f2fs_lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi,
|
static struct rb_node **f2fs_lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi,
|
||||||
struct rb_root_cached *root,
|
struct rb_root_cached *root,
|
||||||
struct rb_node **parent,
|
struct rb_node **parent,
|
||||||
unsigned int ofs, bool *leftmost)
|
unsigned int ofs, bool *leftmost)
|
||||||
@@ -238,7 +238,7 @@ struct rb_node **f2fs_lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi,
|
|||||||
* in order to simplify the insertion after.
|
* in order to simplify the insertion after.
|
||||||
* tree must stay unchanged between lookup and insertion.
|
* tree must stay unchanged between lookup and insertion.
|
||||||
*/
|
*/
|
||||||
struct rb_entry *f2fs_lookup_rb_tree_ret(struct rb_root_cached *root,
|
static struct rb_entry *f2fs_lookup_rb_tree_ret(struct rb_root_cached *root,
|
||||||
struct rb_entry *cached_re,
|
struct rb_entry *cached_re,
|
||||||
unsigned int ofs,
|
unsigned int ofs,
|
||||||
struct rb_entry **prev_entry,
|
struct rb_entry **prev_entry,
|
||||||
@@ -311,36 +311,6 @@ lookup_neighbors:
|
|||||||
return re;
|
return re;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool f2fs_check_rb_tree_consistence(struct f2fs_sb_info *sbi,
|
|
||||||
struct rb_root_cached *root)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_F2FS_CHECK_FS
|
|
||||||
struct rb_node *cur = rb_first_cached(root), *next;
|
|
||||||
struct rb_entry *cur_re, *next_re;
|
|
||||||
|
|
||||||
if (!cur)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
while (cur) {
|
|
||||||
next = rb_next(cur);
|
|
||||||
if (!next)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
cur_re = rb_entry(cur, struct rb_entry, rb_node);
|
|
||||||
next_re = rb_entry(next, struct rb_entry, rb_node);
|
|
||||||
|
|
||||||
if (cur_re->ofs + cur_re->len > next_re->ofs) {
|
|
||||||
f2fs_info(sbi, "inconsistent rbtree, cur(%u, %u) next(%u, %u)",
|
|
||||||
cur_re->ofs, cur_re->len,
|
|
||||||
next_re->ofs, next_re->len);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
cur = next;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct kmem_cache *extent_tree_slab;
|
static struct kmem_cache *extent_tree_slab;
|
||||||
static struct kmem_cache *extent_node_slab;
|
static struct kmem_cache *extent_node_slab;
|
||||||
|
|
||||||
|
|||||||
@@ -350,15 +350,7 @@ struct discard_info {
|
|||||||
|
|
||||||
struct discard_cmd {
|
struct discard_cmd {
|
||||||
struct rb_node rb_node; /* rb node located in rb-tree */
|
struct rb_node rb_node; /* rb node located in rb-tree */
|
||||||
union {
|
struct discard_info di; /* discard info */
|
||||||
struct {
|
|
||||||
block_t lstart; /* logical start address */
|
|
||||||
block_t len; /* length */
|
|
||||||
block_t start; /* actual start address in dev */
|
|
||||||
};
|
|
||||||
struct discard_info di; /* discard info */
|
|
||||||
|
|
||||||
};
|
|
||||||
struct list_head list; /* command list */
|
struct list_head list; /* command list */
|
||||||
struct completion wait; /* compleation */
|
struct completion wait; /* compleation */
|
||||||
struct block_device *bdev; /* bdev */
|
struct block_device *bdev; /* bdev */
|
||||||
@@ -4130,19 +4122,6 @@ void f2fs_leave_shrinker(struct f2fs_sb_info *sbi);
|
|||||||
* extent_cache.c
|
* extent_cache.c
|
||||||
*/
|
*/
|
||||||
bool sanity_check_extent_cache(struct inode *inode);
|
bool sanity_check_extent_cache(struct inode *inode);
|
||||||
struct rb_entry *f2fs_lookup_rb_tree(struct rb_root_cached *root,
|
|
||||||
struct rb_entry *cached_re, unsigned int ofs);
|
|
||||||
struct rb_node **f2fs_lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi,
|
|
||||||
struct rb_root_cached *root,
|
|
||||||
struct rb_node **parent,
|
|
||||||
unsigned int ofs, bool *leftmost);
|
|
||||||
struct rb_entry *f2fs_lookup_rb_tree_ret(struct rb_root_cached *root,
|
|
||||||
struct rb_entry *cached_re, unsigned int ofs,
|
|
||||||
struct rb_entry **prev_entry, struct rb_entry **next_entry,
|
|
||||||
struct rb_node ***insert_p, struct rb_node **insert_parent,
|
|
||||||
bool force, bool *leftmost);
|
|
||||||
bool f2fs_check_rb_tree_consistence(struct f2fs_sb_info *sbi,
|
|
||||||
struct rb_root_cached *root);
|
|
||||||
void f2fs_init_extent_tree(struct inode *inode);
|
void f2fs_init_extent_tree(struct inode *inode);
|
||||||
void f2fs_drop_extent_tree(struct inode *inode);
|
void f2fs_drop_extent_tree(struct inode *inode);
|
||||||
void f2fs_destroy_extent_node(struct inode *inode);
|
void f2fs_destroy_extent_node(struct inode *inode);
|
||||||
|
|||||||
@@ -932,9 +932,9 @@ static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi,
|
|||||||
dc = f2fs_kmem_cache_alloc(discard_cmd_slab, GFP_NOFS, true, NULL);
|
dc = f2fs_kmem_cache_alloc(discard_cmd_slab, GFP_NOFS, true, NULL);
|
||||||
INIT_LIST_HEAD(&dc->list);
|
INIT_LIST_HEAD(&dc->list);
|
||||||
dc->bdev = bdev;
|
dc->bdev = bdev;
|
||||||
dc->lstart = lstart;
|
dc->di.lstart = lstart;
|
||||||
dc->start = start;
|
dc->di.start = start;
|
||||||
dc->len = len;
|
dc->di.len = len;
|
||||||
dc->ref = 0;
|
dc->ref = 0;
|
||||||
dc->state = D_PREP;
|
dc->state = D_PREP;
|
||||||
dc->queued = 0;
|
dc->queued = 0;
|
||||||
@@ -949,20 +949,108 @@ static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi,
|
|||||||
return dc;
|
return dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct discard_cmd *__attach_discard_cmd(struct f2fs_sb_info *sbi,
|
static bool f2fs_check_discard_tree(struct f2fs_sb_info *sbi)
|
||||||
struct block_device *bdev, block_t lstart,
|
{
|
||||||
block_t start, block_t len,
|
#ifdef CONFIG_F2FS_CHECK_FS
|
||||||
struct rb_node *parent, struct rb_node **p,
|
struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
||||||
bool leftmost)
|
struct rb_node *cur = rb_first_cached(&dcc->root), *next;
|
||||||
|
struct discard_cmd *cur_dc, *next_dc;
|
||||||
|
|
||||||
|
while (cur) {
|
||||||
|
next = rb_next(cur);
|
||||||
|
if (!next)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
cur_dc = rb_entry(cur, struct discard_cmd, rb_node);
|
||||||
|
next_dc = rb_entry(next, struct discard_cmd, rb_node);
|
||||||
|
|
||||||
|
if (cur_dc->di.lstart + cur_dc->di.len > next_dc->di.lstart) {
|
||||||
|
f2fs_info(sbi, "broken discard_rbtree, "
|
||||||
|
"cur(%u, %u) next(%u, %u)",
|
||||||
|
cur_dc->di.lstart, cur_dc->di.len,
|
||||||
|
next_dc->di.lstart, next_dc->di.len);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct discard_cmd *__lookup_discard_cmd(struct f2fs_sb_info *sbi,
|
||||||
|
block_t blkaddr)
|
||||||
{
|
{
|
||||||
struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
||||||
|
struct rb_node *node = dcc->root.rb_root.rb_node;
|
||||||
struct discard_cmd *dc;
|
struct discard_cmd *dc;
|
||||||
|
|
||||||
dc = __create_discard_cmd(sbi, bdev, lstart, start, len);
|
while (node) {
|
||||||
|
dc = rb_entry(node, struct discard_cmd, rb_node);
|
||||||
|
|
||||||
rb_link_node(&dc->rb_node, parent, p);
|
if (blkaddr < dc->di.lstart)
|
||||||
rb_insert_color_cached(&dc->rb_node, &dcc->root, leftmost);
|
node = node->rb_left;
|
||||||
|
else if (blkaddr >= dc->di.lstart + dc->di.len)
|
||||||
|
node = node->rb_right;
|
||||||
|
else
|
||||||
|
return dc;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct discard_cmd *__lookup_discard_cmd_ret(struct rb_root_cached *root,
|
||||||
|
block_t blkaddr,
|
||||||
|
struct discard_cmd **prev_entry,
|
||||||
|
struct discard_cmd **next_entry,
|
||||||
|
struct rb_node ***insert_p,
|
||||||
|
struct rb_node **insert_parent)
|
||||||
|
{
|
||||||
|
struct rb_node **pnode = &root->rb_root.rb_node;
|
||||||
|
struct rb_node *parent = NULL, *tmp_node;
|
||||||
|
struct discard_cmd *dc;
|
||||||
|
|
||||||
|
*insert_p = NULL;
|
||||||
|
*insert_parent = NULL;
|
||||||
|
*prev_entry = NULL;
|
||||||
|
*next_entry = NULL;
|
||||||
|
|
||||||
|
if (RB_EMPTY_ROOT(&root->rb_root))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (*pnode) {
|
||||||
|
parent = *pnode;
|
||||||
|
dc = rb_entry(*pnode, struct discard_cmd, rb_node);
|
||||||
|
|
||||||
|
if (blkaddr < dc->di.lstart)
|
||||||
|
pnode = &(*pnode)->rb_left;
|
||||||
|
else if (blkaddr >= dc->di.lstart + dc->di.len)
|
||||||
|
pnode = &(*pnode)->rb_right;
|
||||||
|
else
|
||||||
|
goto lookup_neighbors;
|
||||||
|
}
|
||||||
|
|
||||||
|
*insert_p = pnode;
|
||||||
|
*insert_parent = parent;
|
||||||
|
|
||||||
|
dc = rb_entry(parent, struct discard_cmd, rb_node);
|
||||||
|
tmp_node = parent;
|
||||||
|
if (parent && blkaddr > dc->di.lstart)
|
||||||
|
tmp_node = rb_next(parent);
|
||||||
|
*next_entry = rb_entry_safe(tmp_node, struct discard_cmd, rb_node);
|
||||||
|
|
||||||
|
tmp_node = parent;
|
||||||
|
if (parent && blkaddr < dc->di.lstart)
|
||||||
|
tmp_node = rb_prev(parent);
|
||||||
|
*prev_entry = rb_entry_safe(tmp_node, struct discard_cmd, rb_node);
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
lookup_neighbors:
|
||||||
|
/* lookup prev node for merging backward later */
|
||||||
|
tmp_node = rb_prev(&dc->rb_node);
|
||||||
|
*prev_entry = rb_entry_safe(tmp_node, struct discard_cmd, rb_node);
|
||||||
|
|
||||||
|
/* lookup next node for merging frontward later */
|
||||||
|
tmp_node = rb_next(&dc->rb_node);
|
||||||
|
*next_entry = rb_entry_safe(tmp_node, struct discard_cmd, rb_node);
|
||||||
return dc;
|
return dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -974,7 +1062,7 @@ static void __detach_discard_cmd(struct discard_cmd_control *dcc,
|
|||||||
|
|
||||||
list_del(&dc->list);
|
list_del(&dc->list);
|
||||||
rb_erase_cached(&dc->rb_node, &dcc->root);
|
rb_erase_cached(&dc->rb_node, &dcc->root);
|
||||||
dcc->undiscard_blks -= dc->len;
|
dcc->undiscard_blks -= dc->di.len;
|
||||||
|
|
||||||
kmem_cache_free(discard_cmd_slab, dc);
|
kmem_cache_free(discard_cmd_slab, dc);
|
||||||
|
|
||||||
@@ -987,7 +1075,7 @@ static void __remove_discard_cmd(struct f2fs_sb_info *sbi,
|
|||||||
struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
trace_f2fs_remove_discard(dc->bdev, dc->start, dc->len);
|
trace_f2fs_remove_discard(dc->bdev, dc->di.start, dc->di.len);
|
||||||
|
|
||||||
spin_lock_irqsave(&dc->lock, flags);
|
spin_lock_irqsave(&dc->lock, flags);
|
||||||
if (dc->bio_ref) {
|
if (dc->bio_ref) {
|
||||||
@@ -1005,7 +1093,7 @@ static void __remove_discard_cmd(struct f2fs_sb_info *sbi,
|
|||||||
printk_ratelimited(
|
printk_ratelimited(
|
||||||
"%sF2FS-fs (%s): Issue discard(%u, %u, %u) failed, ret: %d",
|
"%sF2FS-fs (%s): Issue discard(%u, %u, %u) failed, ret: %d",
|
||||||
KERN_INFO, sbi->sb->s_id,
|
KERN_INFO, sbi->sb->s_id,
|
||||||
dc->lstart, dc->start, dc->len, dc->error);
|
dc->di.lstart, dc->di.start, dc->di.len, dc->error);
|
||||||
__detach_discard_cmd(dcc, dc);
|
__detach_discard_cmd(dcc, dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1122,14 +1210,14 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi,
|
|||||||
if (is_sbi_flag_set(sbi, SBI_NEED_FSCK))
|
if (is_sbi_flag_set(sbi, SBI_NEED_FSCK))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
trace_f2fs_issue_discard(bdev, dc->start, dc->len);
|
trace_f2fs_issue_discard(bdev, dc->di.start, dc->di.len);
|
||||||
|
|
||||||
lstart = dc->lstart;
|
lstart = dc->di.lstart;
|
||||||
start = dc->start;
|
start = dc->di.start;
|
||||||
len = dc->len;
|
len = dc->di.len;
|
||||||
total_len = len;
|
total_len = len;
|
||||||
|
|
||||||
dc->len = 0;
|
dc->di.len = 0;
|
||||||
|
|
||||||
while (total_len && *issued < dpolicy->max_requests && !err) {
|
while (total_len && *issued < dpolicy->max_requests && !err) {
|
||||||
struct bio *bio = NULL;
|
struct bio *bio = NULL;
|
||||||
@@ -1145,7 +1233,7 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi,
|
|||||||
if (*issued == dpolicy->max_requests)
|
if (*issued == dpolicy->max_requests)
|
||||||
last = true;
|
last = true;
|
||||||
|
|
||||||
dc->len += len;
|
dc->di.len += len;
|
||||||
|
|
||||||
if (time_to_inject(sbi, FAULT_DISCARD)) {
|
if (time_to_inject(sbi, FAULT_DISCARD)) {
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
@@ -1207,34 +1295,41 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __insert_discard_tree(struct f2fs_sb_info *sbi,
|
static void __insert_discard_cmd(struct f2fs_sb_info *sbi,
|
||||||
struct block_device *bdev, block_t lstart,
|
struct block_device *bdev, block_t lstart,
|
||||||
block_t start, block_t len,
|
block_t start, block_t len)
|
||||||
struct rb_node **insert_p,
|
|
||||||
struct rb_node *insert_parent)
|
|
||||||
{
|
{
|
||||||
struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
||||||
struct rb_node **p;
|
struct rb_node **p = &dcc->root.rb_root.rb_node;
|
||||||
struct rb_node *parent = NULL;
|
struct rb_node *parent = NULL;
|
||||||
|
struct discard_cmd *dc;
|
||||||
bool leftmost = true;
|
bool leftmost = true;
|
||||||
|
|
||||||
if (insert_p && insert_parent) {
|
/* look up rb tree to find parent node */
|
||||||
parent = insert_parent;
|
while (*p) {
|
||||||
p = insert_p;
|
parent = *p;
|
||||||
goto do_insert;
|
dc = rb_entry(parent, struct discard_cmd, rb_node);
|
||||||
|
|
||||||
|
if (lstart < dc->di.lstart) {
|
||||||
|
p = &(*p)->rb_left;
|
||||||
|
} else if (lstart >= dc->di.lstart + dc->di.len) {
|
||||||
|
p = &(*p)->rb_right;
|
||||||
|
leftmost = false;
|
||||||
|
} else {
|
||||||
|
f2fs_bug_on(sbi, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p = f2fs_lookup_rb_tree_for_insert(sbi, &dcc->root, &parent,
|
dc = __create_discard_cmd(sbi, bdev, lstart, start, len);
|
||||||
lstart, &leftmost);
|
|
||||||
do_insert:
|
rb_link_node(&dc->rb_node, parent, p);
|
||||||
__attach_discard_cmd(sbi, bdev, lstart, start, len, parent,
|
rb_insert_color_cached(&dc->rb_node, &dcc->root, leftmost);
|
||||||
p, leftmost);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __relocate_discard_cmd(struct discard_cmd_control *dcc,
|
static void __relocate_discard_cmd(struct discard_cmd_control *dcc,
|
||||||
struct discard_cmd *dc)
|
struct discard_cmd *dc)
|
||||||
{
|
{
|
||||||
list_move_tail(&dc->list, &dcc->pend_list[plist_idx(dc->len)]);
|
list_move_tail(&dc->list, &dcc->pend_list[plist_idx(dc->di.len)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __punch_discard_cmd(struct f2fs_sb_info *sbi,
|
static void __punch_discard_cmd(struct f2fs_sb_info *sbi,
|
||||||
@@ -1244,7 +1339,7 @@ static void __punch_discard_cmd(struct f2fs_sb_info *sbi,
|
|||||||
struct discard_info di = dc->di;
|
struct discard_info di = dc->di;
|
||||||
bool modified = false;
|
bool modified = false;
|
||||||
|
|
||||||
if (dc->state == D_DONE || dc->len == 1) {
|
if (dc->state == D_DONE || dc->di.len == 1) {
|
||||||
__remove_discard_cmd(sbi, dc);
|
__remove_discard_cmd(sbi, dc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1252,23 +1347,22 @@ static void __punch_discard_cmd(struct f2fs_sb_info *sbi,
|
|||||||
dcc->undiscard_blks -= di.len;
|
dcc->undiscard_blks -= di.len;
|
||||||
|
|
||||||
if (blkaddr > di.lstart) {
|
if (blkaddr > di.lstart) {
|
||||||
dc->len = blkaddr - dc->lstart;
|
dc->di.len = blkaddr - dc->di.lstart;
|
||||||
dcc->undiscard_blks += dc->len;
|
dcc->undiscard_blks += dc->di.len;
|
||||||
__relocate_discard_cmd(dcc, dc);
|
__relocate_discard_cmd(dcc, dc);
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blkaddr < di.lstart + di.len - 1) {
|
if (blkaddr < di.lstart + di.len - 1) {
|
||||||
if (modified) {
|
if (modified) {
|
||||||
__insert_discard_tree(sbi, dc->bdev, blkaddr + 1,
|
__insert_discard_cmd(sbi, dc->bdev, blkaddr + 1,
|
||||||
di.start + blkaddr + 1 - di.lstart,
|
di.start + blkaddr + 1 - di.lstart,
|
||||||
di.lstart + di.len - 1 - blkaddr,
|
di.lstart + di.len - 1 - blkaddr);
|
||||||
NULL, NULL);
|
|
||||||
} else {
|
} else {
|
||||||
dc->lstart++;
|
dc->di.lstart++;
|
||||||
dc->len--;
|
dc->di.len--;
|
||||||
dc->start++;
|
dc->di.start++;
|
||||||
dcc->undiscard_blks += dc->len;
|
dcc->undiscard_blks += dc->di.len;
|
||||||
__relocate_discard_cmd(dcc, dc);
|
__relocate_discard_cmd(dcc, dc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1288,37 +1382,33 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi,
|
|||||||
SECTOR_TO_BLOCK(q->limits.max_discard_sectors);
|
SECTOR_TO_BLOCK(q->limits.max_discard_sectors);
|
||||||
block_t end = lstart + len;
|
block_t end = lstart + len;
|
||||||
|
|
||||||
dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root,
|
dc = __lookup_discard_cmd_ret(&dcc->root, lstart,
|
||||||
NULL, lstart,
|
&prev_dc, &next_dc, &insert_p, &insert_parent);
|
||||||
(struct rb_entry **)&prev_dc,
|
|
||||||
(struct rb_entry **)&next_dc,
|
|
||||||
&insert_p, &insert_parent, true, NULL);
|
|
||||||
if (dc)
|
if (dc)
|
||||||
prev_dc = dc;
|
prev_dc = dc;
|
||||||
|
|
||||||
if (!prev_dc) {
|
if (!prev_dc) {
|
||||||
di.lstart = lstart;
|
di.lstart = lstart;
|
||||||
di.len = next_dc ? next_dc->lstart - lstart : len;
|
di.len = next_dc ? next_dc->di.lstart - lstart : len;
|
||||||
di.len = min(di.len, len);
|
di.len = min(di.len, len);
|
||||||
di.start = start;
|
di.start = start;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
struct rb_node *node;
|
struct rb_node *node;
|
||||||
bool merged = false;
|
|
||||||
struct discard_cmd *tdc = NULL;
|
struct discard_cmd *tdc = NULL;
|
||||||
|
|
||||||
if (prev_dc) {
|
if (prev_dc) {
|
||||||
di.lstart = prev_dc->lstart + prev_dc->len;
|
di.lstart = prev_dc->di.lstart + prev_dc->di.len;
|
||||||
if (di.lstart < lstart)
|
if (di.lstart < lstart)
|
||||||
di.lstart = lstart;
|
di.lstart = lstart;
|
||||||
if (di.lstart >= end)
|
if (di.lstart >= end)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!next_dc || next_dc->lstart > end)
|
if (!next_dc || next_dc->di.lstart > end)
|
||||||
di.len = end - di.lstart;
|
di.len = end - di.lstart;
|
||||||
else
|
else
|
||||||
di.len = next_dc->lstart - di.lstart;
|
di.len = next_dc->di.lstart - di.lstart;
|
||||||
di.start = start + di.lstart - lstart;
|
di.start = start + di.lstart - lstart;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1334,7 +1424,7 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi,
|
|||||||
__relocate_discard_cmd(dcc, prev_dc);
|
__relocate_discard_cmd(dcc, prev_dc);
|
||||||
di = prev_dc->di;
|
di = prev_dc->di;
|
||||||
tdc = prev_dc;
|
tdc = prev_dc;
|
||||||
merged = true;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_dc && next_dc->state == D_PREP &&
|
if (next_dc && next_dc->state == D_PREP &&
|
||||||
@@ -1348,13 +1438,10 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi,
|
|||||||
__relocate_discard_cmd(dcc, next_dc);
|
__relocate_discard_cmd(dcc, next_dc);
|
||||||
if (tdc)
|
if (tdc)
|
||||||
__remove_discard_cmd(sbi, tdc);
|
__remove_discard_cmd(sbi, tdc);
|
||||||
merged = true;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!merged) {
|
__insert_discard_cmd(sbi, bdev, di.lstart, di.start, di.len);
|
||||||
__insert_discard_tree(sbi, bdev, di.lstart, di.start,
|
|
||||||
di.len, NULL, NULL);
|
|
||||||
}
|
|
||||||
next:
|
next:
|
||||||
prev_dc = next_dc;
|
prev_dc = next_dc;
|
||||||
if (!prev_dc)
|
if (!prev_dc)
|
||||||
@@ -1393,15 +1480,11 @@ static void __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi,
|
|||||||
struct rb_node **insert_p = NULL, *insert_parent = NULL;
|
struct rb_node **insert_p = NULL, *insert_parent = NULL;
|
||||||
struct discard_cmd *dc;
|
struct discard_cmd *dc;
|
||||||
struct blk_plug plug;
|
struct blk_plug plug;
|
||||||
unsigned int pos = dcc->next_pos;
|
|
||||||
bool io_interrupted = false;
|
bool io_interrupted = false;
|
||||||
|
|
||||||
mutex_lock(&dcc->cmd_lock);
|
mutex_lock(&dcc->cmd_lock);
|
||||||
dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root,
|
dc = __lookup_discard_cmd_ret(&dcc->root, dcc->next_pos,
|
||||||
NULL, pos,
|
&prev_dc, &next_dc, &insert_p, &insert_parent);
|
||||||
(struct rb_entry **)&prev_dc,
|
|
||||||
(struct rb_entry **)&next_dc,
|
|
||||||
&insert_p, &insert_parent, true, NULL);
|
|
||||||
if (!dc)
|
if (!dc)
|
||||||
dc = next_dc;
|
dc = next_dc;
|
||||||
|
|
||||||
@@ -1419,7 +1502,7 @@ static void __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
dcc->next_pos = dc->lstart + dc->len;
|
dcc->next_pos = dc->di.lstart + dc->di.len;
|
||||||
err = __submit_discard_cmd(sbi, dpolicy, dc, issued);
|
err = __submit_discard_cmd(sbi, dpolicy, dc, issued);
|
||||||
|
|
||||||
if (*issued >= dpolicy->max_requests)
|
if (*issued >= dpolicy->max_requests)
|
||||||
@@ -1478,8 +1561,7 @@ retry:
|
|||||||
if (list_empty(pend_list))
|
if (list_empty(pend_list))
|
||||||
goto next;
|
goto next;
|
||||||
if (unlikely(dcc->rbtree_check))
|
if (unlikely(dcc->rbtree_check))
|
||||||
f2fs_bug_on(sbi, !f2fs_check_rb_tree_consistence(sbi,
|
f2fs_bug_on(sbi, !f2fs_check_discard_tree(sbi));
|
||||||
&dcc->root));
|
|
||||||
blk_start_plug(&plug);
|
blk_start_plug(&plug);
|
||||||
list_for_each_entry_safe(dc, tmp, pend_list, list) {
|
list_for_each_entry_safe(dc, tmp, pend_list, list) {
|
||||||
f2fs_bug_on(sbi, dc->state != D_PREP);
|
f2fs_bug_on(sbi, dc->state != D_PREP);
|
||||||
@@ -1557,7 +1639,7 @@ static unsigned int __wait_one_discard_bio(struct f2fs_sb_info *sbi,
|
|||||||
dc->ref--;
|
dc->ref--;
|
||||||
if (!dc->ref) {
|
if (!dc->ref) {
|
||||||
if (!dc->error)
|
if (!dc->error)
|
||||||
len = dc->len;
|
len = dc->di.len;
|
||||||
__remove_discard_cmd(sbi, dc);
|
__remove_discard_cmd(sbi, dc);
|
||||||
}
|
}
|
||||||
mutex_unlock(&dcc->cmd_lock);
|
mutex_unlock(&dcc->cmd_lock);
|
||||||
@@ -1580,14 +1662,15 @@ next:
|
|||||||
|
|
||||||
mutex_lock(&dcc->cmd_lock);
|
mutex_lock(&dcc->cmd_lock);
|
||||||
list_for_each_entry_safe(iter, tmp, wait_list, list) {
|
list_for_each_entry_safe(iter, tmp, wait_list, list) {
|
||||||
if (iter->lstart + iter->len <= start || end <= iter->lstart)
|
if (iter->di.lstart + iter->di.len <= start ||
|
||||||
|
end <= iter->di.lstart)
|
||||||
continue;
|
continue;
|
||||||
if (iter->len < dpolicy->granularity)
|
if (iter->di.len < dpolicy->granularity)
|
||||||
continue;
|
continue;
|
||||||
if (iter->state == D_DONE && !iter->ref) {
|
if (iter->state == D_DONE && !iter->ref) {
|
||||||
wait_for_completion_io(&iter->wait);
|
wait_for_completion_io(&iter->wait);
|
||||||
if (!iter->error)
|
if (!iter->error)
|
||||||
trimmed += iter->len;
|
trimmed += iter->di.len;
|
||||||
__remove_discard_cmd(sbi, iter);
|
__remove_discard_cmd(sbi, iter);
|
||||||
} else {
|
} else {
|
||||||
iter->ref++;
|
iter->ref++;
|
||||||
@@ -1631,8 +1714,7 @@ static void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr)
|
|||||||
bool need_wait = false;
|
bool need_wait = false;
|
||||||
|
|
||||||
mutex_lock(&dcc->cmd_lock);
|
mutex_lock(&dcc->cmd_lock);
|
||||||
dc = (struct discard_cmd *)f2fs_lookup_rb_tree(&dcc->root,
|
dc = __lookup_discard_cmd(sbi, blkaddr);
|
||||||
NULL, blkaddr);
|
|
||||||
if (dc) {
|
if (dc) {
|
||||||
if (dc->state == D_PREP) {
|
if (dc->state == D_PREP) {
|
||||||
__punch_discard_cmd(sbi, dc, blkaddr);
|
__punch_discard_cmd(sbi, dc, blkaddr);
|
||||||
@@ -2965,24 +3047,20 @@ next:
|
|||||||
|
|
||||||
mutex_lock(&dcc->cmd_lock);
|
mutex_lock(&dcc->cmd_lock);
|
||||||
if (unlikely(dcc->rbtree_check))
|
if (unlikely(dcc->rbtree_check))
|
||||||
f2fs_bug_on(sbi, !f2fs_check_rb_tree_consistence(sbi,
|
f2fs_bug_on(sbi, !f2fs_check_discard_tree(sbi));
|
||||||
&dcc->root));
|
|
||||||
|
|
||||||
dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root,
|
dc = __lookup_discard_cmd_ret(&dcc->root, start,
|
||||||
NULL, start,
|
&prev_dc, &next_dc, &insert_p, &insert_parent);
|
||||||
(struct rb_entry **)&prev_dc,
|
|
||||||
(struct rb_entry **)&next_dc,
|
|
||||||
&insert_p, &insert_parent, true, NULL);
|
|
||||||
if (!dc)
|
if (!dc)
|
||||||
dc = next_dc;
|
dc = next_dc;
|
||||||
|
|
||||||
blk_start_plug(&plug);
|
blk_start_plug(&plug);
|
||||||
|
|
||||||
while (dc && dc->lstart <= end) {
|
while (dc && dc->di.lstart <= end) {
|
||||||
struct rb_node *node;
|
struct rb_node *node;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (dc->len < dpolicy->granularity)
|
if (dc->di.len < dpolicy->granularity)
|
||||||
goto skip;
|
goto skip;
|
||||||
|
|
||||||
if (dc->state != D_PREP) {
|
if (dc->state != D_PREP) {
|
||||||
@@ -2993,7 +3071,7 @@ next:
|
|||||||
err = __submit_discard_cmd(sbi, dpolicy, dc, &issued);
|
err = __submit_discard_cmd(sbi, dpolicy, dc, &issued);
|
||||||
|
|
||||||
if (issued >= dpolicy->max_requests) {
|
if (issued >= dpolicy->max_requests) {
|
||||||
start = dc->lstart + dc->len;
|
start = dc->di.lstart + dc->di.len;
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
__remove_discard_cmd(sbi, dc);
|
__remove_discard_cmd(sbi, dc);
|
||||||
|
|||||||
Reference in New Issue
Block a user