Skip to content

Commit 6078e07

Browse files
committed
Merge tag 'libnvdimm-for-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull libnvdimm updates from Dan Williams: - Improve the efficiency and performance of reading nvdimm-namespace labels. Reduce the amount of label data read at driver load time by a few orders of magnitude. Reduce heavyweight call-outs to platform-firmware routines. - Handle media errors located in the 'struct page' array stored on a persistent memory namespace. Let the kernel clear these errors rather than an awkward userspace workaround. - Fix Address Range Scrub (ARS) completion tracking. Correct occasions where the kernel indicates completion of ARS before submission. - Fix asynchronous device registration reference counting. - Add support for reporting an nvdimm dirty-shutdown-count via sysfs. - Fix various small libnvdimm core and uapi issues. * tag 'libnvdimm-for-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: (21 commits) acpi, nfit: Further restrict userspace ARS start requests acpi, nfit: Fix Address Range Scrub completion tracking UAPI: ndctl: Remove use of PAGE_SIZE UAPI: ndctl: Fix g++-unsupported initialisation in headers tools/testing/nvdimm: Populate dirty shutdown data acpi, nfit: Collect shutdown status acpi, nfit: Introduce nfit_mem flags libnvdimm, label: Fix sparse warning nvdimm: Use namespace index data to reduce number of label reads needed nvdimm: Split label init out from the logic for getting config data nvdimm: Remove empty if statement nvdimm: Clarify comment in sizeof_namespace_index nvdimm: Sanity check labeloff libnvdimm, dimm: Maximize label transfer size libnvdimm, pmem: Fix badblocks population for 'raw' namespaces libnvdimm, namespace: Drop the repeat assignment for variable dev->parent libnvdimm, region: Fail badblocks listing for inactive regions libnvdimm, pfn: during init, clear errors in the metadata area libnvdimm: Set device node in nd_device_register libnvdimm: Hold reference on parent while scheduling async init ...
2 parents df132e4 + 5948612 commit 6078e07

File tree

20 files changed

+564
-217
lines changed

20 files changed

+564
-217
lines changed

drivers/acpi/nfit/core.c

Lines changed: 206 additions & 91 deletions
Large diffs are not rendered by default.

drivers/acpi/nfit/intel.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright(c) 2018 Intel Corporation. All rights reserved.
4+
* Intel specific definitions for NVDIMM Firmware Interface Table - NFIT
5+
*/
6+
#ifndef _NFIT_INTEL_H_
7+
#define _NFIT_INTEL_H_
8+
9+
#define ND_INTEL_SMART 1
10+
11+
#define ND_INTEL_SMART_SHUTDOWN_COUNT_VALID (1 << 5)
12+
#define ND_INTEL_SMART_SHUTDOWN_VALID (1 << 10)
13+
14+
struct nd_intel_smart {
15+
u32 status;
16+
union {
17+
struct {
18+
u32 flags;
19+
u8 reserved0[4];
20+
u8 health;
21+
u8 spares;
22+
u8 life_used;
23+
u8 alarm_flags;
24+
u16 media_temperature;
25+
u16 ctrl_temperature;
26+
u32 shutdown_count;
27+
u8 ait_status;
28+
u16 pmic_temperature;
29+
u8 reserved1[8];
30+
u8 shutdown_state;
31+
u32 vendor_size;
32+
u8 vendor_data[92];
33+
} __packed;
34+
u8 data[128];
35+
};
36+
} __packed;
37+
38+
#endif

drivers/acpi/nfit/nfit.h

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,8 @@ enum nfit_dimm_notifiers {
118118
};
119119

120120
enum nfit_ars_state {
121-
ARS_REQ,
122-
ARS_REQ_REDO,
123-
ARS_DONE,
124-
ARS_SHORT,
121+
ARS_REQ_SHORT,
122+
ARS_REQ_LONG,
125123
ARS_FAILED,
126124
};
127125

@@ -159,6 +157,13 @@ struct nfit_memdev {
159157
struct acpi_nfit_memory_map memdev[0];
160158
};
161159

160+
enum nfit_mem_flags {
161+
NFIT_MEM_LSR,
162+
NFIT_MEM_LSW,
163+
NFIT_MEM_DIRTY,
164+
NFIT_MEM_DIRTY_COUNT,
165+
};
166+
162167
/* assembled tables for a given dimm/memory-device */
163168
struct nfit_mem {
164169
struct nvdimm *nvdimm;
@@ -178,9 +183,9 @@ struct nfit_mem {
178183
struct acpi_nfit_desc *acpi_desc;
179184
struct resource *flush_wpq;
180185
unsigned long dsm_mask;
186+
unsigned long flags;
187+
u32 dirty_shutdown;
181188
int family;
182-
bool has_lsr;
183-
bool has_lsw;
184189
};
185190

186191
struct acpi_nfit_desc {
@@ -198,6 +203,7 @@ struct acpi_nfit_desc {
198203
struct device *dev;
199204
u8 ars_start_flags;
200205
struct nd_cmd_ars_status *ars_status;
206+
struct nfit_spa *scrub_spa;
201207
struct delayed_work dwork;
202208
struct list_head list;
203209
struct kernfs_node *scrub_count_state;
@@ -252,7 +258,8 @@ struct nfit_blk {
252258

253259
extern struct list_head acpi_descs;
254260
extern struct mutex acpi_desc_lock;
255-
int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, unsigned long flags);
261+
int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc,
262+
enum nfit_ars_state req_type);
256263

257264
#ifdef CONFIG_X86_MCE
258265
void nfit_mce_register(void);

drivers/nvdimm/bus.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,6 @@ static int to_nd_device_type(struct device *dev)
5454

5555
static int nvdimm_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
5656
{
57-
/*
58-
* Ensure that region devices always have their numa node set as
59-
* early as possible.
60-
*/
61-
if (is_nd_region(dev))
62-
set_dev_node(dev, to_nd_region(dev)->numa_node);
6357
return add_uevent_var(env, "MODALIAS=" ND_DEVICE_MODALIAS_FMT,
6458
to_nd_device_type(dev));
6559
}
@@ -488,6 +482,8 @@ static void nd_async_device_register(void *d, async_cookie_t cookie)
488482
put_device(dev);
489483
}
490484
put_device(dev);
485+
if (dev->parent)
486+
put_device(dev->parent);
491487
}
492488

493489
static void nd_async_device_unregister(void *d, async_cookie_t cookie)
@@ -506,7 +502,19 @@ void __nd_device_register(struct device *dev)
506502
{
507503
if (!dev)
508504
return;
505+
506+
/*
507+
* Ensure that region devices always have their NUMA node set as
508+
* early as possible. This way we are able to make certain that
509+
* any memory associated with the creation and the creation
510+
* itself of the region is associated with the correct node.
511+
*/
512+
if (is_nd_region(dev))
513+
set_dev_node(dev, to_nd_region(dev)->numa_node);
514+
509515
dev->bus = &nvdimm_bus_type;
516+
if (dev->parent)
517+
get_device(dev->parent);
510518
get_device(dev);
511519
async_schedule_domain(nd_async_device_register, dev,
512520
&nd_async_domain);

drivers/nvdimm/dimm.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ static int nvdimm_probe(struct device *dev)
7575
* DIMM capacity. We fail the dimm probe to prevent regions from
7676
* attempting to parse the label area.
7777
*/
78-
rc = nvdimm_init_config_data(ndd);
78+
rc = nd_label_data_init(ndd);
7979
if (rc == -EACCES)
8080
nvdimm_set_locked(dev);
8181
if (rc)
@@ -84,10 +84,6 @@ static int nvdimm_probe(struct device *dev)
8484
dev_dbg(dev, "config data size: %d\n", ndd->nsarea.config_size);
8585

8686
nvdimm_bus_lock(dev);
87-
ndd->ns_current = nd_label_validate(ndd);
88-
ndd->ns_next = nd_label_next_nsindex(ndd->ns_current);
89-
nd_label_copy(ndd, to_next_namespace_index(ndd),
90-
to_current_namespace_index(ndd));
9187
if (ndd->ns_current >= 0) {
9288
rc = nd_label_reserve_dpa(ndd);
9389
if (rc == 0)

drivers/nvdimm/dimm_devs.c

Lines changed: 24 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -85,56 +85,48 @@ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd)
8585
return cmd_rc;
8686
}
8787

88-
int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
88+
int nvdimm_get_config_data(struct nvdimm_drvdata *ndd, void *buf,
89+
size_t offset, size_t len)
8990
{
9091
struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev);
92+
struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
9193
int rc = validate_dimm(ndd), cmd_rc = 0;
9294
struct nd_cmd_get_config_data_hdr *cmd;
93-
struct nvdimm_bus_descriptor *nd_desc;
94-
u32 max_cmd_size, config_size;
95-
size_t offset;
95+
size_t max_cmd_size, buf_offset;
9696

9797
if (rc)
9898
return rc;
9999

100-
if (ndd->data)
101-
return 0;
102-
103-
if (ndd->nsarea.status || ndd->nsarea.max_xfer == 0
104-
|| ndd->nsarea.config_size < ND_LABEL_MIN_SIZE) {
105-
dev_dbg(ndd->dev, "failed to init config data area: (%d:%d)\n",
106-
ndd->nsarea.max_xfer, ndd->nsarea.config_size);
100+
if (offset + len > ndd->nsarea.config_size)
107101
return -ENXIO;
108-
}
109102

110-
ndd->data = kvmalloc(ndd->nsarea.config_size, GFP_KERNEL);
111-
if (!ndd->data)
112-
return -ENOMEM;
113-
114-
max_cmd_size = min_t(u32, PAGE_SIZE, ndd->nsarea.max_xfer);
115-
cmd = kzalloc(max_cmd_size + sizeof(*cmd), GFP_KERNEL);
103+
max_cmd_size = min_t(u32, len, ndd->nsarea.max_xfer);
104+
cmd = kvzalloc(max_cmd_size + sizeof(*cmd), GFP_KERNEL);
116105
if (!cmd)
117106
return -ENOMEM;
118107

119-
nd_desc = nvdimm_bus->nd_desc;
120-
for (config_size = ndd->nsarea.config_size, offset = 0;
121-
config_size; config_size -= cmd->in_length,
122-
offset += cmd->in_length) {
123-
cmd->in_length = min(config_size, max_cmd_size);
124-
cmd->in_offset = offset;
108+
for (buf_offset = 0; len;
109+
len -= cmd->in_length, buf_offset += cmd->in_length) {
110+
size_t cmd_size;
111+
112+
cmd->in_offset = offset + buf_offset;
113+
cmd->in_length = min(max_cmd_size, len);
114+
115+
cmd_size = sizeof(*cmd) + cmd->in_length;
116+
125117
rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
126-
ND_CMD_GET_CONFIG_DATA, cmd,
127-
cmd->in_length + sizeof(*cmd), &cmd_rc);
118+
ND_CMD_GET_CONFIG_DATA, cmd, cmd_size, &cmd_rc);
128119
if (rc < 0)
129120
break;
130121
if (cmd_rc < 0) {
131122
rc = cmd_rc;
132123
break;
133124
}
134-
memcpy(ndd->data + offset, cmd->out_buf, cmd->in_length);
125+
126+
/* out_buf should be valid, copy it into our output buffer */
127+
memcpy(buf + buf_offset, cmd->out_buf, cmd->in_length);
135128
}
136-
dev_dbg(ndd->dev, "len: %zu rc: %d\n", offset, rc);
137-
kfree(cmd);
129+
kvfree(cmd);
138130

139131
return rc;
140132
}
@@ -151,15 +143,11 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
151143
if (rc)
152144
return rc;
153145

154-
if (!ndd->data)
155-
return -ENXIO;
156-
157146
if (offset + len > ndd->nsarea.config_size)
158147
return -ENXIO;
159148

160-
max_cmd_size = min_t(u32, PAGE_SIZE, len);
161-
max_cmd_size = min_t(u32, max_cmd_size, ndd->nsarea.max_xfer);
162-
cmd = kzalloc(max_cmd_size + sizeof(*cmd) + sizeof(u32), GFP_KERNEL);
149+
max_cmd_size = min_t(u32, len, ndd->nsarea.max_xfer);
150+
cmd = kvzalloc(max_cmd_size + sizeof(*cmd) + sizeof(u32), GFP_KERNEL);
163151
if (!cmd)
164152
return -ENOMEM;
165153

@@ -183,7 +171,7 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset,
183171
break;
184172
}
185173
}
186-
kfree(cmd);
174+
kvfree(cmd);
187175

188176
return rc;
189177
}

0 commit comments

Comments
 (0)