Skip to content

Commit a4bd217

Browse files
Javier Gonzálezaxboe
authored andcommitted
lightnvm: physical block device (pblk) target
This patch introduces pblk, a host-side translation layer for Open-Channel SSDs to expose them like block devices. The translation layer allows data placement decisions, and I/O scheduling to be managed by the host, enabling users to optimize the SSD for their specific workloads. An open-channel SSD has a set of LUNs (parallel units) and a collection of blocks. Each block can be read in any order, but writes must be sequential. Writes may also fail, and if a block requires it, must also be reset before new writes can be applied. To manage the constraints, pblk maintains a logical to physical address (L2P) table, write cache, garbage collection logic, recovery scheme, and logic to rate-limit user I/Os versus garbage collection I/Os. The L2P table is fully-associative and manages sectors at a 4KB granularity. Pblk stores the L2P table in two places, in the out-of-band area of the media and on the last page of a line. In the cause of a power failure, pblk will perform a scan to recover the L2P table. The user data is organized into lines. A line is data striped across blocks and LUNs. The lines enable the host to reduce the amount of metadata to maintain besides the user data and makes it easier to implement RAID or erasure coding in the future. pblk implements multi-tenant support and can be instantiated multiple times on the same drive. Each instance owns a portion of the SSD - both regarding I/O bandwidth and capacity - providing I/O isolation for each case. Finally, pblk also exposes a sysfs interface that allows user-space to peek into the internals of pblk. The interface is available at /dev/block/*/pblk/ where * is the block device name exposed. This work also contains contributions from: Matias Bjørling <[email protected]> Simon A. F. Lund <[email protected]> Young Tack Jin <[email protected]> Huaicheng Li <[email protected]> Signed-off-by: Javier González <[email protected]> Signed-off-by: Matias Bjørling <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 6eb0824 commit a4bd217

File tree

15 files changed

+8044
-0
lines changed

15 files changed

+8044
-0
lines changed

Documentation/lightnvm/pblk.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
pblk: Physical Block Device Target
2+
==================================
3+
4+
pblk implements a fully associative, host-based FTL that exposes a traditional
5+
block I/O interface. Its primary responsibilities are:
6+
7+
- Map logical addresses onto physical addresses (4KB granularity) in a
8+
logical-to-physical (L2P) table.
9+
- Maintain the integrity and consistency of the L2P table as well as its
10+
recovery from normal tear down and power outage.
11+
- Deal with controller- and media-specific constrains.
12+
- Handle I/O errors.
13+
- Implement garbage collection.
14+
- Maintain consistency across the I/O stack during synchronization points.
15+
16+
For more information please refer to:
17+
18+
http://lightnvm.io
19+
20+
which maintains updated FAQs, manual pages, technical documentation, tools,
21+
contacts, etc.

drivers/lightnvm/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,13 @@ config NVM_RRPC
3333
host. The target is implemented using a linear mapping table and
3434
cost-based garbage collection. It is optimized for 4K IO sizes.
3535

36+
config NVM_PBLK
37+
tristate "Physical Block Device Open-Channel SSD target"
38+
---help---
39+
Allows an open-channel SSD to be exposed as a block device to the
40+
host. The target assumes the device exposes raw flash and must be
41+
explicitly managed by the host.
42+
43+
Please note the disk format is considered EXPERIMENTAL for now.
44+
3645
endif # NVM

drivers/lightnvm/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,8 @@
44

55
obj-$(CONFIG_NVM) := core.o
66
obj-$(CONFIG_NVM_RRPC) += rrpc.o
7+
obj-$(CONFIG_NVM_PBLK) += pblk.o
8+
pblk-y := pblk-init.o pblk-core.o pblk-rb.o \
9+
pblk-write.o pblk-cache.o pblk-read.o \
10+
pblk-gc.o pblk-recovery.o pblk-map.o \
11+
pblk-rl.o pblk-sysfs.o

drivers/lightnvm/pblk-cache.c

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright (C) 2016 CNEX Labs
3+
* Initial release: Javier Gonzalez <[email protected]>
4+
* Matias Bjorling <[email protected]>
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU General Public License version
8+
* 2 as published by the Free Software Foundation.
9+
*
10+
* This program is distributed in the hope that it will be useful, but
11+
* WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* General Public License for more details.
14+
*
15+
* pblk-cache.c - pblk's write cache
16+
*/
17+
18+
#include "pblk.h"
19+
20+
int pblk_write_to_cache(struct pblk *pblk, struct bio *bio, unsigned long flags)
21+
{
22+
struct pblk_w_ctx w_ctx;
23+
sector_t lba = pblk_get_lba(bio);
24+
unsigned int bpos, pos;
25+
int nr_entries = pblk_get_secs(bio);
26+
int i, ret;
27+
28+
/* Update the write buffer head (mem) with the entries that we can
29+
* write. The write in itself cannot fail, so there is no need to
30+
* rollback from here on.
31+
*/
32+
retry:
33+
ret = pblk_rb_may_write_user(&pblk->rwb, bio, nr_entries, &bpos);
34+
if (ret == NVM_IO_REQUEUE) {
35+
io_schedule();
36+
goto retry;
37+
}
38+
39+
if (unlikely(!bio_has_data(bio)))
40+
goto out;
41+
42+
w_ctx.flags = flags;
43+
pblk_ppa_set_empty(&w_ctx.ppa);
44+
45+
for (i = 0; i < nr_entries; i++) {
46+
void *data = bio_data(bio);
47+
48+
w_ctx.lba = lba + i;
49+
50+
pos = pblk_rb_wrap_pos(&pblk->rwb, bpos + i);
51+
pblk_rb_write_entry_user(&pblk->rwb, data, w_ctx, pos);
52+
53+
bio_advance(bio, PBLK_EXPOSED_PAGE_SIZE);
54+
}
55+
56+
#ifdef CONFIG_NVM_DEBUG
57+
atomic_long_add(nr_entries, &pblk->inflight_writes);
58+
atomic_long_add(nr_entries, &pblk->req_writes);
59+
#endif
60+
61+
out:
62+
pblk_write_should_kick(pblk);
63+
return ret;
64+
}
65+
66+
/*
67+
* On GC the incoming lbas are not necessarily sequential. Also, some of the
68+
* lbas might not be valid entries, which are marked as empty by the GC thread
69+
*/
70+
int pblk_write_gc_to_cache(struct pblk *pblk, void *data, u64 *lba_list,
71+
unsigned int nr_entries, unsigned int nr_rec_entries,
72+
struct pblk_line *gc_line, unsigned long flags)
73+
{
74+
struct pblk_w_ctx w_ctx;
75+
unsigned int bpos, pos;
76+
int i, valid_entries;
77+
78+
/* Update the write buffer head (mem) with the entries that we can
79+
* write. The write in itself cannot fail, so there is no need to
80+
* rollback from here on.
81+
*/
82+
retry:
83+
if (!pblk_rb_may_write_gc(&pblk->rwb, nr_rec_entries, &bpos)) {
84+
io_schedule();
85+
goto retry;
86+
}
87+
88+
w_ctx.flags = flags;
89+
pblk_ppa_set_empty(&w_ctx.ppa);
90+
91+
for (i = 0, valid_entries = 0; i < nr_entries; i++) {
92+
if (lba_list[i] == ADDR_EMPTY)
93+
continue;
94+
95+
w_ctx.lba = lba_list[i];
96+
97+
pos = pblk_rb_wrap_pos(&pblk->rwb, bpos + valid_entries);
98+
pblk_rb_write_entry_gc(&pblk->rwb, data, w_ctx, gc_line, pos);
99+
100+
data += PBLK_EXPOSED_PAGE_SIZE;
101+
valid_entries++;
102+
}
103+
104+
WARN_ONCE(nr_rec_entries != valid_entries,
105+
"pblk: inconsistent GC write\n");
106+
107+
#ifdef CONFIG_NVM_DEBUG
108+
atomic_long_add(valid_entries, &pblk->inflight_writes);
109+
atomic_long_add(valid_entries, &pblk->recov_gc_writes);
110+
#endif
111+
112+
pblk_write_should_kick(pblk);
113+
return NVM_IO_OK;
114+
}

0 commit comments

Comments
 (0)