Implement crashdump support on NVME

MFC after:	3 days
Sponsored by:	Netflix, Inc.
This commit is contained in:
Scott Long 2016-07-19 03:13:51 +00:00
parent b1b8369114
commit a498975ef7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=303017
3 changed files with 68 additions and 0 deletions

View File

@ -47,6 +47,7 @@ struct nvd_disk;
static disk_ioctl_t nvd_ioctl; static disk_ioctl_t nvd_ioctl;
static disk_strategy_t nvd_strategy; static disk_strategy_t nvd_strategy;
static dumper_t nvd_dump;
static void nvd_done(void *arg, const struct nvme_completion *cpl); static void nvd_done(void *arg, const struct nvme_completion *cpl);
@ -226,6 +227,26 @@ nvd_ioctl(struct disk *ndisk, u_long cmd, void *data, int fflag,
return (ret); return (ret);
} }
static int
nvd_dump(void *arg, void *virt, vm_offset_t phys, off_t offset, size_t len)
{
struct nvd_disk *ndisk;
struct disk *dp;
int error;
dp = arg;
ndisk = dp->d_drv1;
if (len > 0) {
if ((error = nvme_ns_dump(ndisk->ns, virt, offset, len)) != 0)
return (error);
} else {
/* XXX sync to stable storage */
}
return (0);
}
static void static void
nvd_done(void *arg, const struct nvme_completion *cpl) nvd_done(void *arg, const struct nvme_completion *cpl)
{ {
@ -302,6 +323,7 @@ nvd_new_disk(struct nvme_namespace *ns, void *ctrlr_arg)
disk = disk_alloc(); disk = disk_alloc();
disk->d_strategy = nvd_strategy; disk->d_strategy = nvd_strategy;
disk->d_ioctl = nvd_ioctl; disk->d_ioctl = nvd_ioctl;
disk->d_dump = nvd_dump;
disk->d_name = NVD_STR; disk->d_name = NVD_STR;
disk->d_drv1 = ndisk; disk->d_drv1 = ndisk;

View File

@ -876,6 +876,8 @@ int nvme_ns_cmd_deallocate(struct nvme_namespace *ns, void *payload,
void *cb_arg); void *cb_arg);
int nvme_ns_cmd_flush(struct nvme_namespace *ns, nvme_cb_fn_t cb_fn, int nvme_ns_cmd_flush(struct nvme_namespace *ns, nvme_cb_fn_t cb_fn,
void *cb_arg); void *cb_arg);
int nvme_ns_dump(struct nvme_namespace *ns, void *virt, off_t offset,
size_t len);
/* Registration functions */ /* Registration functions */
struct nvme_consumer * nvme_register_consumer(nvme_cons_ns_fn_t ns_fn, struct nvme_consumer * nvme_register_consumer(nvme_cons_ns_fn_t ns_fn,

View File

@ -151,3 +151,47 @@ nvme_ns_cmd_flush(struct nvme_namespace *ns, nvme_cb_fn_t cb_fn, void *cb_arg)
return (0); return (0);
} }
/* Timeout = 1 sec */
#define NVD_DUMP_TIMEOUT 100000
int
nvme_ns_dump(struct nvme_namespace *ns, void *virt, off_t offset, size_t len)
{
struct nvme_completion_poll_status status;
struct nvme_request *req;
struct nvme_command *cmd;
uint64_t lba, lba_count;
int i;
status.done = FALSE;
req = nvme_allocate_request_vaddr(virt, len, nvme_completion_poll_cb,
&status);
if (req == NULL)
return (ENOMEM);
cmd = &req->cmd;
cmd->opc = NVME_OPC_WRITE;
cmd->nsid = ns->id;
lba = offset / nvme_ns_get_sector_size(ns);
lba_count = len / nvme_ns_get_sector_size(ns);
*(uint64_t *)&cmd->cdw10 = lba;
cmd->cdw12 = lba_count - 1;
nvme_ctrlr_submit_io_request(ns->ctrlr, req);
if (req->qpair == NULL)
return (ENXIO);
i = 0;
while ((i++ < NVD_DUMP_TIMEOUT) && (status.done == FALSE)) {
DELAY(10);
nvme_qpair_process_completions(req->qpair);
}
if (status.done == FALSE)
return (ETIMEDOUT);
return (0);
}