• Coly Li's avatar
    bcache: never set KEY_PTRS of journal key to 0 in journal_reclaim() · 1bee2add
    Coly Li authored
    In journal_reclaim() ja->cur_idx of each cache will be update to
    reclaim available journal buckets. Variable 'int n' is used to count how
    many cache is successfully reclaimed, then n is set to c->journal.key
    by SET_KEY_PTRS(). Later in journal_write_unlocked(), a for_each_cache()
    loop will write the jset data onto each cache.
    
    The problem is, if all jouranl buckets on each cache is full, the
    following code in journal_reclaim(),
    
    529 for_each_cache(ca, c, iter) {
    530       struct journal_device *ja = &ca->journal;
    531       unsigned int next = (ja->cur_idx + 1) % ca->sb.njournal_buckets;
    532
    533       /* No space available on this device */
    534       if (next == ja->discard_idx)
    535               continue;
    536
    537       ja->cur_idx = next;
    538       k->ptr[n++] = MAKE_PTR(0,
    539                         bucket_to_sector(c, ca->sb.d[ja->cur_idx]),
    540                         ca->sb.nr_this_dev);
    541 }
    542
    543 bkey_init(k);
    544 SET_KEY_PTRS(k, n);
    
    If there is no available bucket to reclaim, the if() condition at line
    534 will always true, and n remains 0. Then at line 544, SET_KEY_PTRS()
    will set KEY_PTRS field of c->journal.key to 0.
    
    Setting KEY_PTRS field of c->journal.key to 0 is wrong. Because in
    journal_write_unlocked() the journal data is written in following loop,
    
    649	for (i = 0; i < KEY_PTRS(k); i++) {
    650-671		submit journal data to cache device
    672	}
    
    If KEY_PTRS field is set to 0 in jouranl_reclaim(), the journal data
    won't be written to cache device here. If system crahed or rebooted
    before bkeys of the lost journal entries written into btree nodes, data
    corruption will be reported during bcache reload after rebooting the
    system.
    
    Indeed there is only one cache in a cache set, there is no need to set
    KEY_PTRS field in journal_reclaim() at all. But in order to keep the
    for_each_cache() logic consistent for now, this patch fixes the above
    problem by not setting 0 KEY_PTRS of journal key, if there is no bucket
    available to reclaim.
    Signed-off-by: default avatarColy Li <colyli@suse.de>
    Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
    Cc: stable@vger.kernel.org
    Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
    1bee2add
journal.c 19.7 KB