@@ -771,6 +771,8 @@ static int __nvm_configure_remove(struct nvm_ioctl_remove *remove)
static int nvm_configure_show(const char *val)
{
struct nvm_dev *dev;
+ struct nvm_target *t = NULL;
+ struct nvm_tgt_type *tt;
char opcode, devname[DISK_NAME_LEN];
int ret;
@@ -793,6 +795,14 @@ static int nvm_configure_show(const char *val)
dev->mt->lun_info_print(dev);
+ down_write(&nvm_lock);
+ list_for_each_entry(dev, &nvm_devices, devices)
+ list_for_each_entry(t, &dev->online_targets, list) {
+ tt = t->type;
+ tt->print_debug(t->disk->private_data);
+ }
+ up_write(&nvm_lock);
+
return 0;
}
@@ -784,6 +784,11 @@ static void rrpc_sync_buffer(struct rrpc *rrpc, struct rrpc_addr *p)
WARN_ON(test_and_set_bit((p->addr - bppa), buf->sync_bitmap));
+#ifdef CONFIG_NVM_DEBUG
+ atomic_dec(&rrpc->inflight_writes);
+ atomic_inc(&rrpc->sync_writes);
+#endif
+
if (unlikely(bitmap_full(buf->sync_bitmap, buf->nentries))) {
/* Write buffer out-of-bounds */
WARN_ON((buf->cur_mem != buf->nentries) &&
@@ -820,6 +825,9 @@ static void rrpc_end_io_read(struct rrpc *rrpc, struct nvm_rq *rqd,
rrpc_unlock_rq(rrpc, rrqd);
mempool_free(rrqd, rrpc->rrq_pool);
+#ifdef CONFIG_NVM_DEBUG
+ atomic_sub(nr_pages, &rrpc->inflight_reads);
+#endif
}
static void rrpc_end_io(struct nvm_rq *rqd)
@@ -919,6 +927,11 @@ static int rrpc_write_ppalist_rq(struct rrpc *rrpc, struct bio *bio,
rrqd->addr = p;
+#ifdef CONFIG_NVM_DEBUG
+ atomic_inc(&rrpc->inflight_writes);
+ atomic_inc(&rrpc->req_writes);
+#endif
+
err = rrpc_write_to_buffer(rrpc, bio, rrqd, p, w_buf, flags);
if (err) {
pr_err("rrpc: could not write to write buffer\n");
@@ -967,6 +980,11 @@ static int rrpc_write_rq(struct rrpc *rrpc, struct bio *bio,
rrqd->addr = p;
+#ifdef CONFIG_NVM_DEBUG
+ atomic_inc(&rrpc->inflight_writes);
+ atomic_inc(&rrpc->req_writes);
+#endif
+
err = rrpc_write_to_buffer(rrpc, bio, rrqd, p, w_buf, flags);
if (err) {
pr_err("rrpc: could not write to write buffer\n");
@@ -1023,6 +1041,10 @@ static int rrpc_read_ppalist_rq(struct rrpc *rrpc, struct bio *bio,
}
brrqd[i].addr = gp;
+
+#ifdef CONFIG_NVM_DEBUG
+ atomic_inc(&rrpc->inflight_reads);
+#endif
}
rqd->opcode = NVM_OP_HBREAD;
@@ -1055,6 +1077,10 @@ static int rrpc_read_rq(struct rrpc *rrpc, struct bio *bio, struct nvm_rq *rqd,
rqd->opcode = NVM_OP_HBREAD;
rrqd->addr = gp;
+#ifdef CONFIG_NVM_DEBUG
+ atomic_inc(&rrpc->inflight_reads);
+#endif
+
return NVM_IO_OK;
}
@@ -1615,6 +1641,9 @@ submit_io:
mempool_free(rqd, rrpc->rq_pool);
bio_put(bio);
}
+#ifdef CONFIG_NVM_DEBUG
+ atomic_add(pgs_to_sync, &rrpc->sub_writes);
+#endif
}
spin_unlock(&rlun->parent->lock);
@@ -2128,6 +2157,14 @@ static void *rrpc_init(struct nvm_dev *dev, struct gendisk *tdisk,
/* simple round-robin strategy */
atomic_set(&rrpc->next_lun, -1);
+#ifdef CONFIG_NVM_DEBUG
+ atomic_set(&rrpc->inflight_writes, 0);
+ atomic_set(&rrpc->req_writes, 0);
+ atomic_set(&rrpc->sub_writes, 0);
+ atomic_set(&rrpc->sync_writes, 0);
+ atomic_set(&rrpc->inflight_reads, 0);
+#endif
+
ret = rrpc_luns_init(rrpc, lun_begin, lun_end);
if (ret) {
pr_err("nvm: rrpc: could not initialize luns\n");
@@ -2182,6 +2219,24 @@ err:
return ERR_PTR(ret);
}
+#ifdef CONFIG_NVM_DEBUG
+static void rrpc_print_debug(void *private)
+{
+ struct rrpc *rrpc = private;
+
+ pr_info("rrpc: %u\t%u\t%u\t%u\t%u\n",
+ atomic_read(&rrpc->inflight_writes),
+ atomic_read(&rrpc->inflight_reads),
+ atomic_read(&rrpc->req_writes),
+ atomic_read(&rrpc->sub_writes),
+ atomic_read(&rrpc->sync_writes));
+}
+#else
+static void rrpc_print_debug(void *private)
+{
+}
+#endif
+
/* round robin, page-based FTL, and cost-based GC */
static struct nvm_tgt_type tt_rrpc = {
.name = "rrpc",
@@ -2193,6 +2248,8 @@ static struct nvm_tgt_type tt_rrpc = {
.init = rrpc_init,
.exit = rrpc_exit,
+
+ .print_debug = rrpc_print_debug,
};
static int __init rrpc_module_init(void)
@@ -167,6 +167,14 @@ struct rrpc {
* to point to the next write lun
*/
+#ifdef CONFIG_NVM_DEBUG
+ atomic_t inflight_writes;
+ atomic_t req_writes;
+ atomic_t sub_writes;
+ atomic_t sync_writes;
+ atomic_t inflight_reads;
+#endif
+
spinlock_t bio_lock;
struct bio_list requeue_bios;
struct work_struct ws_requeue;
@@ -428,6 +428,7 @@ typedef blk_qc_t (nvm_tgt_make_rq_fn)(struct request_queue *, struct bio *);
typedef sector_t (nvm_tgt_capacity_fn)(void *);
typedef void *(nvm_tgt_init_fn)(struct nvm_dev *, struct gendisk *, int, int);
typedef void (nvm_tgt_exit_fn)(void *);
+typedef void (nvm_tgt_print_debug_fn)(void *);
struct nvm_tgt_type {
const char *name;
@@ -442,6 +443,9 @@ struct nvm_tgt_type {
nvm_tgt_init_fn *init;
nvm_tgt_exit_fn *exit;
+ /* debugging */
+ nvm_tgt_print_debug_fn *print_debug;
+
/* For internal use */
struct list_head list;
};
Add a target to print its debug information when lightnvm debug information is printed trough configure_debug. In rrpc, we add statistics on inflight reads and writes, as well as submitted and synced writes. Signed-off-by: Javier González <javier@cnexlabs.com> --- drivers/lightnvm/core.c | 10 +++++++++ drivers/lightnvm/rrpc.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/lightnvm/rrpc.h | 8 +++++++ include/linux/lightnvm.h | 4 ++++ 4 files changed, 79 insertions(+)