diff options
author | Hans Holmberg <hans.holmberg@cnexlabs.com> | 2018-12-11 14:16:13 -0500 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2018-12-11 14:22:33 -0500 |
commit | 3bcebc5bac0935d662f30d317e33ffa660bebf93 (patch) | |
tree | a253b85173c905425e6dc5bcdd285399faa2419f /drivers/lightnvm/pblk-init.c | |
parent | 525f7bb2c9f9b2c6673854eade89e98fb3ba7802 (diff) |
lightnvm: pblk: set conservative threshold for user writes
In a worst-case scenario (random writes), OP% of sectors
in each line will be invalid, and we will then need
to move data out of 100/OP% lines to free a single line.
So, to prevent the possibility of running out of lines,
temporarily block user writes when there is less than
100/OP% free lines.
Also ensure that pblk creation does not produce instances
with insufficient over provisioning.
Insufficient over-provising is not a problem on real hardware,
but often an issue when running QEMU simulations (with few lines).
100 lines is enough to create a sane instance with the standard
(11%) over provisioning.
Signed-off-by: Hans Holmberg <hans.holmberg@cnexlabs.com>
Reviewed-by: Javier González <javier@javigon.com>
Signed-off-by: Matias Bjørling <mb@lightnvm.io>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/lightnvm/pblk-init.c')
-rw-r--r-- | drivers/lightnvm/pblk-init.c | 40 |
1 files changed, 31 insertions, 9 deletions
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c index 13822594647c..f083130d9920 100644 --- a/drivers/lightnvm/pblk-init.c +++ b/drivers/lightnvm/pblk-init.c | |||
@@ -635,7 +635,7 @@ static unsigned int calc_emeta_len(struct pblk *pblk) | |||
635 | return (lm->emeta_len[1] + lm->emeta_len[2] + lm->emeta_len[3]); | 635 | return (lm->emeta_len[1] + lm->emeta_len[2] + lm->emeta_len[3]); |
636 | } | 636 | } |
637 | 637 | ||
638 | static void pblk_set_provision(struct pblk *pblk, long nr_free_blks) | 638 | static int pblk_set_provision(struct pblk *pblk, int nr_free_chks) |
639 | { | 639 | { |
640 | struct nvm_tgt_dev *dev = pblk->dev; | 640 | struct nvm_tgt_dev *dev = pblk->dev; |
641 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; | 641 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; |
@@ -643,23 +643,41 @@ static void pblk_set_provision(struct pblk *pblk, long nr_free_blks) | |||
643 | struct nvm_geo *geo = &dev->geo; | 643 | struct nvm_geo *geo = &dev->geo; |
644 | sector_t provisioned; | 644 | sector_t provisioned; |
645 | int sec_meta, blk_meta; | 645 | int sec_meta, blk_meta; |
646 | int minimum; | ||
646 | 647 | ||
647 | if (geo->op == NVM_TARGET_DEFAULT_OP) | 648 | if (geo->op == NVM_TARGET_DEFAULT_OP) |
648 | pblk->op = PBLK_DEFAULT_OP; | 649 | pblk->op = PBLK_DEFAULT_OP; |
649 | else | 650 | else |
650 | pblk->op = geo->op; | 651 | pblk->op = geo->op; |
651 | 652 | ||
652 | provisioned = nr_free_blks; | 653 | minimum = pblk_get_min_chks(pblk); |
654 | provisioned = nr_free_chks; | ||
653 | provisioned *= (100 - pblk->op); | 655 | provisioned *= (100 - pblk->op); |
654 | sector_div(provisioned, 100); | 656 | sector_div(provisioned, 100); |
655 | 657 | ||
656 | pblk->op_blks = nr_free_blks - provisioned; | 658 | if ((nr_free_chks - provisioned) < minimum) { |
659 | if (geo->op != NVM_TARGET_DEFAULT_OP) { | ||
660 | pblk_err(pblk, "OP too small to create a sane instance\n"); | ||
661 | return -EINTR; | ||
662 | } | ||
663 | |||
664 | /* If the user did not specify an OP value, and PBLK_DEFAULT_OP | ||
665 | * is not enough, calculate and set sane value | ||
666 | */ | ||
667 | |||
668 | provisioned = nr_free_chks - minimum; | ||
669 | pblk->op = (100 * minimum) / nr_free_chks; | ||
670 | pblk_info(pblk, "Default OP insufficient, adjusting OP to %d\n", | ||
671 | pblk->op); | ||
672 | } | ||
673 | |||
674 | pblk->op_blks = nr_free_chks - provisioned; | ||
657 | 675 | ||
658 | /* Internally pblk manages all free blocks, but all calculations based | 676 | /* Internally pblk manages all free blocks, but all calculations based |
659 | * on user capacity consider only provisioned blocks | 677 | * on user capacity consider only provisioned blocks |
660 | */ | 678 | */ |
661 | pblk->rl.total_blocks = nr_free_blks; | 679 | pblk->rl.total_blocks = nr_free_chks; |
662 | pblk->rl.nr_secs = nr_free_blks * geo->clba; | 680 | pblk->rl.nr_secs = nr_free_chks * geo->clba; |
663 | 681 | ||
664 | /* Consider sectors used for metadata */ | 682 | /* Consider sectors used for metadata */ |
665 | sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines; | 683 | sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines; |
@@ -667,8 +685,10 @@ static void pblk_set_provision(struct pblk *pblk, long nr_free_blks) | |||
667 | 685 | ||
668 | pblk->capacity = (provisioned - blk_meta) * geo->clba; | 686 | pblk->capacity = (provisioned - blk_meta) * geo->clba; |
669 | 687 | ||
670 | atomic_set(&pblk->rl.free_blocks, nr_free_blks); | 688 | atomic_set(&pblk->rl.free_blocks, nr_free_chks); |
671 | atomic_set(&pblk->rl.free_user_blocks, nr_free_blks); | 689 | atomic_set(&pblk->rl.free_user_blocks, nr_free_chks); |
690 | |||
691 | return 0; | ||
672 | } | 692 | } |
673 | 693 | ||
674 | static int pblk_setup_line_meta_chk(struct pblk *pblk, struct pblk_line *line, | 694 | static int pblk_setup_line_meta_chk(struct pblk *pblk, struct pblk_line *line, |
@@ -984,7 +1004,7 @@ static int pblk_lines_init(struct pblk *pblk) | |||
984 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; | 1004 | struct pblk_line_mgmt *l_mg = &pblk->l_mg; |
985 | struct pblk_line *line; | 1005 | struct pblk_line *line; |
986 | void *chunk_meta; | 1006 | void *chunk_meta; |
987 | long nr_free_chks = 0; | 1007 | int nr_free_chks = 0; |
988 | int i, ret; | 1008 | int i, ret; |
989 | 1009 | ||
990 | ret = pblk_line_meta_init(pblk); | 1010 | ret = pblk_line_meta_init(pblk); |
@@ -1031,7 +1051,9 @@ static int pblk_lines_init(struct pblk *pblk) | |||
1031 | goto fail_free_lines; | 1051 | goto fail_free_lines; |
1032 | } | 1052 | } |
1033 | 1053 | ||
1034 | pblk_set_provision(pblk, nr_free_chks); | 1054 | ret = pblk_set_provision(pblk, nr_free_chks); |
1055 | if (ret) | ||
1056 | goto fail_free_lines; | ||
1035 | 1057 | ||
1036 | vfree(chunk_meta); | 1058 | vfree(chunk_meta); |
1037 | return 0; | 1059 | return 0; |