|
@@ -934,6 +934,7 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,
|
|
|
/* common policy */
|
|
|
dpolicy->type = discard_type;
|
|
|
dpolicy->sync = true;
|
|
|
+ dpolicy->ordered = false;
|
|
|
dpolicy->granularity = granularity;
|
|
|
|
|
|
dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST;
|
|
@@ -945,6 +946,7 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,
|
|
|
dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME;
|
|
|
dpolicy->io_aware = true;
|
|
|
dpolicy->sync = false;
|
|
|
+ dpolicy->ordered = true;
|
|
|
if (utilization(sbi) > DEF_DISCARD_URGENT_UTIL) {
|
|
|
dpolicy->granularity = 1;
|
|
|
dpolicy->max_interval = DEF_MIN_DISCARD_ISSUE_TIME;
|
|
@@ -1181,6 +1183,63 @@ static int __queue_discard_cmd(struct f2fs_sb_info *sbi,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi,
|
|
|
+ struct discard_policy *dpolicy)
|
|
|
+{
|
|
|
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
|
|
+ struct discard_cmd *prev_dc = NULL, *next_dc = NULL;
|
|
|
+ struct rb_node **insert_p = NULL, *insert_parent = NULL;
|
|
|
+ struct discard_cmd *dc;
|
|
|
+ struct blk_plug plug;
|
|
|
+ unsigned int pos = dcc->next_pos;
|
|
|
+ unsigned int issued = 0;
|
|
|
+ bool io_interrupted = false;
|
|
|
+
|
|
|
+ mutex_lock(&dcc->cmd_lock);
|
|
|
+ dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root,
|
|
|
+ NULL, pos,
|
|
|
+ (struct rb_entry **)&prev_dc,
|
|
|
+ (struct rb_entry **)&next_dc,
|
|
|
+ &insert_p, &insert_parent, true);
|
|
|
+ if (!dc)
|
|
|
+ dc = next_dc;
|
|
|
+
|
|
|
+ blk_start_plug(&plug);
|
|
|
+
|
|
|
+ while (dc) {
|
|
|
+ struct rb_node *node;
|
|
|
+
|
|
|
+ if (dc->state != D_PREP)
|
|
|
+ goto next;
|
|
|
+
|
|
|
+ if (dpolicy->io_aware && !is_idle(sbi)) {
|
|
|
+ io_interrupted = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ dcc->next_pos = dc->lstart + dc->len;
|
|
|
+ __submit_discard_cmd(sbi, dpolicy, dc);
|
|
|
+
|
|
|
+ if (++issued >= dpolicy->max_requests)
|
|
|
+ break;
|
|
|
+next:
|
|
|
+ node = rb_next(&dc->rb_node);
|
|
|
+ dc = rb_entry_safe(node, struct discard_cmd, rb_node);
|
|
|
+ }
|
|
|
+
|
|
|
+ blk_finish_plug(&plug);
|
|
|
+
|
|
|
+ if (!dc)
|
|
|
+ dcc->next_pos = 0;
|
|
|
+
|
|
|
+ mutex_unlock(&dcc->cmd_lock);
|
|
|
+
|
|
|
+ if (!issued && io_interrupted)
|
|
|
+ issued = -1;
|
|
|
+
|
|
|
+ return issued;
|
|
|
+}
|
|
|
+
|
|
|
static int __issue_discard_cmd(struct f2fs_sb_info *sbi,
|
|
|
struct discard_policy *dpolicy)
|
|
|
{
|
|
@@ -1194,6 +1253,10 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi,
|
|
|
for (i = MAX_PLIST_NUM - 1; i >= 0; i--) {
|
|
|
if (i + 1 < dpolicy->granularity)
|
|
|
break;
|
|
|
+
|
|
|
+ if (i < DEFAULT_DISCARD_GRANULARITY && dpolicy->ordered)
|
|
|
+ return __issue_discard_cmd_orderly(sbi, dpolicy);
|
|
|
+
|
|
|
pend_list = &dcc->pend_list[i];
|
|
|
|
|
|
mutex_lock(&dcc->cmd_lock);
|
|
@@ -1754,6 +1817,7 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi)
|
|
|
dcc->nr_discards = 0;
|
|
|
dcc->max_discards = MAIN_SEGS(sbi) << sbi->log_blocks_per_seg;
|
|
|
dcc->undiscard_blks = 0;
|
|
|
+ dcc->next_pos = 0;
|
|
|
dcc->root = RB_ROOT;
|
|
|
dcc->rbtree_check = false;
|
|
|
|