Re: [PATCH V2] lightnvm: pblk: fix race condition on GC

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Thanks Heiner, it's awesome to get this fixed!

Reviewed-by: Hans Holmberg <hans.holmberg@xxxxxxxxxxxx>

On Mon, Feb 4, 2019 at 9:19 AM Javier González <javier@xxxxxxxxxxx> wrote:
>
> > On 1 Feb 2019, at 03.38, Heiner Litz <hlitz@xxxxxxxx> wrote:
> >
> > This patch fixes a race condition where a write is mapped to the last
> > sectors of a line. The write is synced to the device but the L2P is not
> > updated yet. When the line is garbage collected before the L2P update is
> > performed, the sectors are ignored by the GC logic and the line is freed
> > before all sectors are moved. When the L2P is finally updated, it contains
> > a mapping to a freed line, subsequent reads of the corresponding LBAs fail.
> >
> > This patch introduces a per line counter specifying the number of sectors
> > that are synced to the device but have not been updated in the L2P. Lines
> > with a counter of greater than zero will not be selected for GC.
> >
> > Signed-off-by: Heiner Litz <hlitz@xxxxxxxx>
> > ---
> >
> > v2: changed according to Javier's comment. Instead of performing check
> > while holding the trans_lock, add an atomic per line counter
> >
> > drivers/lightnvm/pblk-core.c  |  1 +
> > drivers/lightnvm/pblk-gc.c    | 20 +++++++++++++-------
> > drivers/lightnvm/pblk-map.c   |  1 +
> > drivers/lightnvm/pblk-rb.c    |  1 +
> > drivers/lightnvm/pblk-write.c |  1 +
> > drivers/lightnvm/pblk.h       |  1 +
> > 6 files changed, 18 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
> > index eabcbc119681..b7ed0502abef 100644
> > --- a/drivers/lightnvm/pblk-core.c
> > +++ b/drivers/lightnvm/pblk-core.c
> > @@ -1278,6 +1278,7 @@ static int pblk_line_prepare(struct pblk *pblk, struct pblk_line *line)
> >       spin_unlock(&line->lock);
> >
> >       kref_init(&line->ref);
> > +     atomic_set(&line->sec_to_update, 0);
> >
> >       return 0;
> > }
> > diff --git a/drivers/lightnvm/pblk-gc.c b/drivers/lightnvm/pblk-gc.c
> > index 2fa118c8eb71..26a52ea7ec45 100644
> > --- a/drivers/lightnvm/pblk-gc.c
> > +++ b/drivers/lightnvm/pblk-gc.c
> > @@ -365,16 +365,22 @@ static struct pblk_line *pblk_gc_get_victim_line(struct pblk *pblk,
> >                                                struct list_head *group_list)
> > {
> >       struct pblk_line *line, *victim;
> > -     int line_vsc, victim_vsc;
> > +     unsigned int line_vsc = ~0x0L, victim_vsc = ~0x0L;
> >
> >       victim = list_first_entry(group_list, struct pblk_line, list);
> > +
> >       list_for_each_entry(line, group_list, list) {
> > -             line_vsc = le32_to_cpu(*line->vsc);
> > -             victim_vsc = le32_to_cpu(*victim->vsc);
> > -             if (line_vsc < victim_vsc)
> > +             if (!atomic_read(&line->sec_to_update))
> > +                     line_vsc = le32_to_cpu(*line->vsc);
> > +             if (line_vsc < victim_vsc) {
> >                       victim = line;
> > +                     victim_vsc = le32_to_cpu(*victim->vsc);
> > +             }
> >       }
> >
> > +     if (victim_vsc == ~0x0)
> > +             return NULL;
> > +
> >       return victim;
> > }
> >
> > @@ -448,13 +454,13 @@ static void pblk_gc_run(struct pblk *pblk)
> >
> >       do {
> >               spin_lock(&l_mg->gc_lock);
> > -             if (list_empty(group_list)) {
> > +
> > +             line = pblk_gc_get_victim_line(pblk, group_list);
> > +             if (!line) {
> >                       spin_unlock(&l_mg->gc_lock);
> >                       break;
> >               }
> >
> > -             line = pblk_gc_get_victim_line(pblk, group_list);
> > -
> >               spin_lock(&line->lock);
> >               WARN_ON(line->state != PBLK_LINESTATE_CLOSED);
> >               line->state = PBLK_LINESTATE_GC;
> > diff --git a/drivers/lightnvm/pblk-map.c b/drivers/lightnvm/pblk-map.c
> > index 79df583ea709..7fbc99b60cac 100644
> > --- a/drivers/lightnvm/pblk-map.c
> > +++ b/drivers/lightnvm/pblk-map.c
> > @@ -73,6 +73,7 @@ static int pblk_map_page_data(struct pblk *pblk, unsigned int sentry,
> >                */
> >               if (i < valid_secs) {
> >                       kref_get(&line->ref);
> > +                     atomic_inc(&line->sec_to_update);
> >                       w_ctx = pblk_rb_w_ctx(&pblk->rwb, sentry + i);
> >                       w_ctx->ppa = ppa_list[i];
> >                       meta->lba = cpu_to_le64(w_ctx->lba);
> > diff --git a/drivers/lightnvm/pblk-rb.c b/drivers/lightnvm/pblk-rb.c
> > index a6133b50ed9c..03c241b340ea 100644
> > --- a/drivers/lightnvm/pblk-rb.c
> > +++ b/drivers/lightnvm/pblk-rb.c
> > @@ -260,6 +260,7 @@ static int __pblk_rb_update_l2p(struct pblk_rb *rb, unsigned int to_update)
> >                                                       entry->cacheline);
> >
> >               line = pblk_ppa_to_line(pblk, w_ctx->ppa);
> > +             atomic_dec(&line->sec_to_update);
> >               kref_put(&line->ref, pblk_line_put);
> >               clean_wctx(w_ctx);
> >               rb->l2p_update = pblk_rb_ptr_wrap(rb, rb->l2p_update, 1);
> > diff --git a/drivers/lightnvm/pblk-write.c b/drivers/lightnvm/pblk-write.c
> > index 06d56deb645d..6593deab52da 100644
> > --- a/drivers/lightnvm/pblk-write.c
> > +++ b/drivers/lightnvm/pblk-write.c
> > @@ -177,6 +177,7 @@ static void pblk_prepare_resubmit(struct pblk *pblk, unsigned int sentry,
> >                * re-map these entries
> >                */
> >               line = pblk_ppa_to_line(pblk, w_ctx->ppa);
> > +             atomic_dec(&line->sec_to_update);
> >               kref_put(&line->ref, pblk_line_put);
> >       }
> >       spin_unlock(&pblk->trans_lock);
> > diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
> > index a6386d5acd73..ac3ab778e976 100644
> > --- a/drivers/lightnvm/pblk.h
> > +++ b/drivers/lightnvm/pblk.h
> > @@ -487,6 +487,7 @@ struct pblk_line {
> >       __le32 *vsc;                    /* Valid sector count in line */
> >
> >       struct kref ref;                /* Write buffer L2P references */
> > +     atomic_t sec_to_update;         /* Outstanding L2P updates to ppa */
> >
> >       struct pblk_w_err_gc *w_err_gc; /* Write error gc recovery metadata */
> >
> > --
> > 2.17.1
>
>
> Looks good to me. Again, good marathon-catch! :)
>
> Reviewed-by: Javier González <javier@xxxxxxxxxxx>
>
>




[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux