f0c98ebc57
1/ Replace pcommit with ADR / directed-flushing: The pcommit instruction, which has not shipped on any product, is deprecated. Instead, the requirement is that platforms implement either ADR, or provide one or more flush addresses per nvdimm. ADR (Asynchronous DRAM Refresh) flushes data in posted write buffers to the memory controller on a power-fail event. Flush addresses are defined in ACPI 6.x as an NVDIMM Firmware Interface Table (NFIT) sub-structure: "Flush Hint Address Structure". A flush hint is an mmio address that when written and fenced assures that all previous posted writes targeting a given dimm have been flushed to media. 2/ On-demand ARS (address range scrub): Linux uses the results of the ACPI ARS commands to track bad blocks in pmem devices. When latent errors are detected we re-scrub the media to refresh the bad block list, userspace can also request a re-scrub at any time. 3/ Support for the Microsoft DSM (device specific method) command format. 4/ Support for EDK2/OVMF virtual disk device memory ranges. 5/ Various fixes and cleanups across the subsystem. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJXmXBsAAoJEB7SkWpmfYgCEwwP/1IOt9ocP+iHLMDH9KE7VaTZ NmUDR+Zy6g5cRQM7SgcuU5BXUcx+OsSrSrUTVF1cW994o9Gbz1mFotkv0ZAsPcYY ZVRQxo2oqHrssyOcg+PsgKWiXn68rJOCgmpEyzaJywl5qTMst7pzsT1s1f7rSh6h trCf4VaJJwxZR8fARGtlHUnnhPe2Orp99EZRKEWprAsIv2kPuWpPHSjRjuEgN1JG KW8AYwWqFTtiLRUk86I4KBB0wcDrfctsjgN9Ogd6+aHyQBRnVSr2U+vDCFkC8KLu qiDCpYp+yyxBjclnljz7tRRT3GtzfCUWd4v2KVWqgg2IaobUc0Lbukp/rmikUXQP WLikT2OCQ994eFK5OX3Q3cIU/4j459TQnof8q14yVSpjAKrNUXVSR5puN7Hxa+V7 41wKrAsnsyY1oq+Yd/rMR8VfH7PHx3bFkrmRCGZCufLX1UQm4aYj+sWagDKiV3yA DiudghbOnhfurfGsnXUVw7y7GKs+gNWNBmB6ndAD6ZEHmKoGUhAEbJDLCc3DnANl b/2mv1MIdIcC1DlCmnbbcn6fv6bICe/r8poK3VrCK3UgOq/EOvKIWl7giP+k1JuC 6DdVYhlNYIVFXUNSLFAwz8OkLu8byx7WDm36iEqrKHtPw+8qa/2bWVgOU6OBgpjV cN3edFVIdxvZeMgM5Ubq =xCBG -----END PGP SIGNATURE----- Merge tag 'libnvdimm-for-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm Pull libnvdimm updates from Dan Williams: - Replace pcommit with ADR / directed-flushing. The pcommit instruction, which has not shipped on any product, is deprecated. Instead, the requirement is that platforms implement either ADR, or provide one or more flush addresses per nvdimm. ADR (Asynchronous DRAM Refresh) flushes data in posted write buffers to the memory controller on a power-fail event. Flush addresses are defined in ACPI 6.x as an NVDIMM Firmware Interface Table (NFIT) sub-structure: "Flush Hint Address Structure". A flush hint is an mmio address that when written and fenced assures that all previous posted writes targeting a given dimm have been flushed to media. - On-demand ARS (address range scrub). Linux uses the results of the ACPI ARS commands to track bad blocks in pmem devices. When latent errors are detected we re-scrub the media to refresh the bad block list, userspace can also request a re-scrub at any time. - Support for the Microsoft DSM (device specific method) command format. - Support for EDK2/OVMF virtual disk device memory ranges. - Various fixes and cleanups across the subsystem. * tag 'libnvdimm-for-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: (41 commits) libnvdimm-btt: Delete an unnecessary check before the function call "__nd_device_register" nfit: do an ARS scrub on hitting a latent media error nfit: move to nfit/ sub-directory nfit, libnvdimm: allow an ARS scrub to be triggered on demand libnvdimm: register nvdimm_bus devices with an nd_bus driver pmem: clarify a debug print in pmem_clear_poison x86/insn: remove pcommit Revert "KVM: x86: add pcommit support" nfit, tools/testing/nvdimm/: unify shutdown paths libnvdimm: move ->module to struct nvdimm_bus_descriptor nfit: cleanup acpi_nfit_init calling convention nfit: fix _FIT evaluation memory leak + use after free tools/testing/nvdimm: add manufacturing_{date|location} dimm properties tools/testing/nvdimm: add virtual ramdisk range acpi, nfit: treat virtual ramdisk SPA as pmem region pmem: kill __pmem address space pmem: kill wmb_pmem() libnvdimm, pmem: use nvdimm_flush() for namespace I/O writes fs/dax: remove wmb_pmem() libnvdimm, pmem: flush posted-write queues on shutdown ...
182 lines
3.2 KiB
C
182 lines
3.2 KiB
C
/*
|
|
* Copyright (C) 2001 Sistina Software (UK) Limited
|
|
*
|
|
* This file is released under the GPL.
|
|
*/
|
|
|
|
#include "dm-core.h"
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kmod.h>
|
|
#include <linux/bio.h>
|
|
|
|
#define DM_MSG_PREFIX "target"
|
|
|
|
static LIST_HEAD(_targets);
|
|
static DECLARE_RWSEM(_lock);
|
|
|
|
#define DM_MOD_NAME_SIZE 32
|
|
|
|
static inline struct target_type *__find_target_type(const char *name)
|
|
{
|
|
struct target_type *tt;
|
|
|
|
list_for_each_entry(tt, &_targets, list)
|
|
if (!strcmp(name, tt->name))
|
|
return tt;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static struct target_type *get_target_type(const char *name)
|
|
{
|
|
struct target_type *tt;
|
|
|
|
down_read(&_lock);
|
|
|
|
tt = __find_target_type(name);
|
|
if (tt && !try_module_get(tt->module))
|
|
tt = NULL;
|
|
|
|
up_read(&_lock);
|
|
return tt;
|
|
}
|
|
|
|
static void load_module(const char *name)
|
|
{
|
|
request_module("dm-%s", name);
|
|
}
|
|
|
|
struct target_type *dm_get_target_type(const char *name)
|
|
{
|
|
struct target_type *tt = get_target_type(name);
|
|
|
|
if (!tt) {
|
|
load_module(name);
|
|
tt = get_target_type(name);
|
|
}
|
|
|
|
return tt;
|
|
}
|
|
|
|
void dm_put_target_type(struct target_type *tt)
|
|
{
|
|
down_read(&_lock);
|
|
module_put(tt->module);
|
|
up_read(&_lock);
|
|
}
|
|
|
|
int dm_target_iterate(void (*iter_func)(struct target_type *tt,
|
|
void *param), void *param)
|
|
{
|
|
struct target_type *tt;
|
|
|
|
down_read(&_lock);
|
|
list_for_each_entry(tt, &_targets, list)
|
|
iter_func(tt, param);
|
|
up_read(&_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dm_register_target(struct target_type *tt)
|
|
{
|
|
int rv = 0;
|
|
|
|
down_write(&_lock);
|
|
if (__find_target_type(tt->name))
|
|
rv = -EEXIST;
|
|
else
|
|
list_add(&tt->list, &_targets);
|
|
|
|
up_write(&_lock);
|
|
return rv;
|
|
}
|
|
|
|
void dm_unregister_target(struct target_type *tt)
|
|
{
|
|
down_write(&_lock);
|
|
if (!__find_target_type(tt->name)) {
|
|
DMCRIT("Unregistering unrecognised target: %s", tt->name);
|
|
BUG();
|
|
}
|
|
|
|
list_del(&tt->list);
|
|
|
|
up_write(&_lock);
|
|
}
|
|
|
|
/*
|
|
* io-err: always fails an io, useful for bringing
|
|
* up LVs that have holes in them.
|
|
*/
|
|
static int io_err_ctr(struct dm_target *tt, unsigned int argc, char **args)
|
|
{
|
|
/*
|
|
* Return error for discards instead of -EOPNOTSUPP
|
|
*/
|
|
tt->num_discard_bios = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void io_err_dtr(struct dm_target *tt)
|
|
{
|
|
/* empty */
|
|
}
|
|
|
|
static int io_err_map(struct dm_target *tt, struct bio *bio)
|
|
{
|
|
return -EIO;
|
|
}
|
|
|
|
static int io_err_map_rq(struct dm_target *ti, struct request *clone,
|
|
union map_info *map_context)
|
|
{
|
|
return -EIO;
|
|
}
|
|
|
|
static int io_err_clone_and_map_rq(struct dm_target *ti, struct request *rq,
|
|
union map_info *map_context,
|
|
struct request **clone)
|
|
{
|
|
return -EIO;
|
|
}
|
|
|
|
static void io_err_release_clone_rq(struct request *clone)
|
|
{
|
|
}
|
|
|
|
static long io_err_direct_access(struct dm_target *ti, sector_t sector,
|
|
void **kaddr, pfn_t *pfn, long size)
|
|
{
|
|
return -EIO;
|
|
}
|
|
|
|
static struct target_type error_target = {
|
|
.name = "error",
|
|
.version = {1, 5, 0},
|
|
.features = DM_TARGET_WILDCARD,
|
|
.ctr = io_err_ctr,
|
|
.dtr = io_err_dtr,
|
|
.map = io_err_map,
|
|
.map_rq = io_err_map_rq,
|
|
.clone_and_map_rq = io_err_clone_and_map_rq,
|
|
.release_clone_rq = io_err_release_clone_rq,
|
|
.direct_access = io_err_direct_access,
|
|
};
|
|
|
|
int __init dm_target_init(void)
|
|
{
|
|
return dm_register_target(&error_target);
|
|
}
|
|
|
|
void dm_target_exit(void)
|
|
{
|
|
dm_unregister_target(&error_target);
|
|
}
|
|
|
|
EXPORT_SYMBOL(dm_register_target);
|
|
EXPORT_SYMBOL(dm_unregister_target);
|