File Index
Files and directories
Sign in
FILE

btt_devs.c

File preview with syntax highlighting.

linux-6.19.14/drivers/nvdimm/btt_devs.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
  4 */
  5#include <linux/blkdev.h>
  6#include <linux/device.h>
  7#include <linux/sizes.h>
  8#include <linux/slab.h>
  9#include <linux/fs.h>
 10#include <linux/mm.h>
 11#include "nd-core.h"
 12#include "btt.h"
 13#include "nd.h"
 14
 15static void nd_btt_release(struct device *dev)
 16{
 17	struct nd_region *nd_region = to_nd_region(dev->parent);
 18	struct nd_btt *nd_btt = to_nd_btt(dev);
 19
 20	dev_dbg(dev, "trace\n");
 21	nd_detach_ndns(&nd_btt->dev, &nd_btt->ndns);
 22	ida_free(&nd_region->btt_ida, nd_btt->id);
 23	kfree(nd_btt->uuid);
 24	kfree(nd_btt);
 25}
 26
 27struct nd_btt *to_nd_btt(struct device *dev)
 28{
 29	struct nd_btt *nd_btt = container_of(dev, struct nd_btt, dev);
 30
 31	WARN_ON(!is_nd_btt(dev));
 32	return nd_btt;
 33}
 34EXPORT_SYMBOL(to_nd_btt);
 35
 36static const unsigned long btt_lbasize_supported[] = { 512, 520, 528,
 37	4096, 4104, 4160, 4224, 0 };
 38
 39static ssize_t sector_size_show(struct device *dev,
 40		struct device_attribute *attr, char *buf)
 41{
 42	struct nd_btt *nd_btt = to_nd_btt(dev);
 43
 44	return nd_size_select_show(nd_btt->lbasize, btt_lbasize_supported, buf);
 45}
 46
 47static ssize_t sector_size_store(struct device *dev,
 48		struct device_attribute *attr, const char *buf, size_t len)
 49{
 50	struct nd_btt *nd_btt = to_nd_btt(dev);
 51	ssize_t rc;
 52
 53	guard(device)(dev);
 54	guard(nvdimm_bus)(dev);
 55	rc = nd_size_select_store(dev, buf, &nd_btt->lbasize,
 56			btt_lbasize_supported);
 57	dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf,
 58			buf[len - 1] == '\n' ? "" : "\n");
 59
 60	return rc ? rc : len;
 61}
 62static DEVICE_ATTR_RW(sector_size);
 63
 64static ssize_t uuid_show(struct device *dev,
 65		struct device_attribute *attr, char *buf)
 66{
 67	struct nd_btt *nd_btt = to_nd_btt(dev);
 68
 69	if (nd_btt->uuid)
 70		return sprintf(buf, "%pUb\n", nd_btt->uuid);
 71	return sprintf(buf, "\n");
 72}
 73
 74static ssize_t uuid_store(struct device *dev,
 75		struct device_attribute *attr, const char *buf, size_t len)
 76{
 77	struct nd_btt *nd_btt = to_nd_btt(dev);
 78	ssize_t rc;
 79
 80	device_lock(dev);
 81	rc = nd_uuid_store(dev, &nd_btt->uuid, buf, len);
 82	dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf,
 83			buf[len - 1] == '\n' ? "" : "\n");
 84	device_unlock(dev);
 85
 86	return rc ? rc : len;
 87}
 88static DEVICE_ATTR_RW(uuid);
 89
 90static ssize_t namespace_show(struct device *dev,
 91		struct device_attribute *attr, char *buf)
 92{
 93	struct nd_btt *nd_btt = to_nd_btt(dev);
 94
 95	guard(nvdimm_bus)(dev);
 96	return sprintf(buf, "%s\n", nd_btt->ndns
 97			? dev_name(&nd_btt->ndns->dev) : "");
 98}
 99
100static ssize_t namespace_store(struct device *dev,
101		struct device_attribute *attr, const char *buf, size_t len)
102{
103	struct nd_btt *nd_btt = to_nd_btt(dev);
104	ssize_t rc;
105
106	guard(device)(dev);
107	guard(nvdimm_bus)(dev);
108	rc = nd_namespace_store(dev, &nd_btt->ndns, buf, len);
109	dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf,
110			buf[len - 1] == '\n' ? "" : "\n");
111
112	return rc;
113}
114static DEVICE_ATTR_RW(namespace);
115
116static ssize_t size_show(struct device *dev,
117		struct device_attribute *attr, char *buf)
118{
119	struct nd_btt *nd_btt = to_nd_btt(dev);
120	ssize_t rc;
121
122	device_lock(dev);
123	if (dev->driver)
124		rc = sprintf(buf, "%llu\n", nd_btt->size);
125	else {
126		/* no size to convey if the btt instance is disabled */
127		rc = -ENXIO;
128	}
129	device_unlock(dev);
130
131	return rc;
132}
133static DEVICE_ATTR_RO(size);
134
135static ssize_t log_zero_flags_show(struct device *dev,
136		struct device_attribute *attr, char *buf)
137{
138	return sprintf(buf, "Y\n");
139}
140static DEVICE_ATTR_RO(log_zero_flags);
141
142static struct attribute *nd_btt_attributes[] = {
143	&dev_attr_sector_size.attr,
144	&dev_attr_namespace.attr,
145	&dev_attr_uuid.attr,
146	&dev_attr_size.attr,
147	&dev_attr_log_zero_flags.attr,
148	NULL,
149};
150
151static struct attribute_group nd_btt_attribute_group = {
152	.attrs = nd_btt_attributes,
153};
154
155static const struct attribute_group *nd_btt_attribute_groups[] = {
156	&nd_btt_attribute_group,
157	&nd_device_attribute_group,
158	&nd_numa_attribute_group,
159	NULL,
160};
161
162static const struct device_type nd_btt_device_type = {
163	.name = "nd_btt",
164	.release = nd_btt_release,
165	.groups = nd_btt_attribute_groups,
166};
167
168bool is_nd_btt(struct device *dev)
169{
170	return dev->type == &nd_btt_device_type;
171}
172EXPORT_SYMBOL(is_nd_btt);
173
174static struct lock_class_key nvdimm_btt_key;
175
176static struct device *__nd_btt_create(struct nd_region *nd_region,
177				      unsigned long lbasize, uuid_t *uuid,
178				      struct nd_namespace_common *ndns)
179{
180	struct nd_btt *nd_btt;
181	struct device *dev;
182
183	nd_btt = kzalloc(sizeof(*nd_btt), GFP_KERNEL);
184	if (!nd_btt)
185		return NULL;
186
187	nd_btt->id = ida_alloc(&nd_region->btt_ida, GFP_KERNEL);
188	if (nd_btt->id < 0)
189		goto out_nd_btt;
190
191	nd_btt->lbasize = lbasize;
192	if (uuid) {
193		uuid = kmemdup(uuid, 16, GFP_KERNEL);
194		if (!uuid)
195			goto out_put_id;
196	}
197	nd_btt->uuid = uuid;
198	dev = &nd_btt->dev;
199	dev_set_name(dev, "btt%d.%d", nd_region->id, nd_btt->id);
200	dev->parent = &nd_region->dev;
201	dev->type = &nd_btt_device_type;
202	device_initialize(&nd_btt->dev);
203	lockdep_set_class(&nd_btt->dev.mutex, &nvdimm_btt_key);
204	if (ndns && !__nd_attach_ndns(&nd_btt->dev, ndns, &nd_btt->ndns)) {
205		dev_dbg(&ndns->dev, "failed, already claimed by %s\n",
206				dev_name(ndns->claim));
207		put_device(dev);
208		return NULL;
209	}
210	return dev;
211
212out_put_id:
213	ida_free(&nd_region->btt_ida, nd_btt->id);
214
215out_nd_btt:
216	kfree(nd_btt);
217	return NULL;
218}
219
220struct device *nd_btt_create(struct nd_region *nd_region)
221{
222	struct device *dev = __nd_btt_create(nd_region, 0, NULL, NULL);
223
224	nd_device_register(dev);
225	return dev;
226}
227
228/**
229 * nd_btt_arena_is_valid - check if the metadata layout is valid
230 * @nd_btt:	device with BTT geometry and backing device info
231 * @super:	pointer to the arena's info block being tested
232 *
233 * Check consistency of the btt info block with itself by validating
234 * the checksum, and with the parent namespace by verifying the
235 * parent_uuid contained in the info block with the one supplied in.
236 *
237 * Returns:
238 * false for an invalid info block, true for a valid one
239 */
240bool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct btt_sb *super)
241{
242	const uuid_t *ns_uuid = nd_dev_to_uuid(&nd_btt->ndns->dev);
243	uuid_t parent_uuid;
244	u64 checksum;
245
246	if (memcmp(super->signature, BTT_SIG, BTT_SIG_LEN) != 0)
247		return false;
248
249	import_uuid(&parent_uuid, super->parent_uuid);
250	if (!uuid_is_null(&parent_uuid))
251		if (!uuid_equal(&parent_uuid, ns_uuid))
252			return false;
253
254	checksum = le64_to_cpu(super->checksum);
255	super->checksum = 0;
256	if (checksum != nd_sb_checksum((struct nd_gen_sb *) super))
257		return false;
258	super->checksum = cpu_to_le64(checksum);
259
260	/* TODO: figure out action for this */
261	if ((le32_to_cpu(super->flags) & IB_FLAG_ERROR_MASK) != 0)
262		dev_info(&nd_btt->dev, "Found arena with an error flag\n");
263
264	return true;
265}
266EXPORT_SYMBOL(nd_btt_arena_is_valid);
267
268int nd_btt_version(struct nd_btt *nd_btt, struct nd_namespace_common *ndns,
269		struct btt_sb *btt_sb)
270{
271	if (ndns->claim_class == NVDIMM_CCLASS_BTT2) {
272		/* Probe/setup for BTT v2.0 */
273		nd_btt->initial_offset = 0;
274		nd_btt->version_major = 2;
275		nd_btt->version_minor = 0;
276		if (nvdimm_read_bytes(ndns, 0, btt_sb, sizeof(*btt_sb), 0))
277			return -ENXIO;
278		if (!nd_btt_arena_is_valid(nd_btt, btt_sb))
279			return -ENODEV;
280		if ((le16_to_cpu(btt_sb->version_major) != 2) ||
281				(le16_to_cpu(btt_sb->version_minor) != 0))
282			return -ENODEV;
283	} else {
284		/*
285		 * Probe/setup for BTT v1.1 (NVDIMM_CCLASS_NONE or
286		 * NVDIMM_CCLASS_BTT)
287		 */
288		nd_btt->initial_offset = SZ_4K;
289		nd_btt->version_major = 1;
290		nd_btt->version_minor = 1;
291		if (nvdimm_read_bytes(ndns, SZ_4K, btt_sb, sizeof(*btt_sb), 0))
292			return -ENXIO;
293		if (!nd_btt_arena_is_valid(nd_btt, btt_sb))
294			return -ENODEV;
295		if ((le16_to_cpu(btt_sb->version_major) != 1) ||
296				(le16_to_cpu(btt_sb->version_minor) != 1))
297			return -ENODEV;
298	}
299	return 0;
300}
301EXPORT_SYMBOL(nd_btt_version);
302
303static int __nd_btt_probe(struct nd_btt *nd_btt,
304		struct nd_namespace_common *ndns, struct btt_sb *btt_sb)
305{
306	int rc;
307
308	if (!btt_sb || !ndns || !nd_btt)
309		return -ENODEV;
310
311	if (nvdimm_namespace_capacity(ndns) < SZ_16M)
312		return -ENXIO;
313
314	rc = nd_btt_version(nd_btt, ndns, btt_sb);
315	if (rc < 0)
316		return rc;
317
318	nd_btt->lbasize = le32_to_cpu(btt_sb->external_lbasize);
319	nd_btt->uuid = kmemdup(&btt_sb->uuid, sizeof(uuid_t), GFP_KERNEL);
320	if (!nd_btt->uuid)
321		return -ENOMEM;
322
323	nd_device_register(&nd_btt->dev);
324
325	return 0;
326}
327
328int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns)
329{
330	int rc;
331	struct device *btt_dev;
332	struct btt_sb *btt_sb;
333	struct nd_region *nd_region = to_nd_region(ndns->dev.parent);
334
335	if (ndns->force_raw)
336		return -ENODEV;
337
338	switch (ndns->claim_class) {
339	case NVDIMM_CCLASS_NONE:
340	case NVDIMM_CCLASS_BTT:
341	case NVDIMM_CCLASS_BTT2:
342		break;
343	default:
344		return -ENODEV;
345	}
346
347	scoped_guard(nvdimm_bus, &ndns->dev)
348		btt_dev = __nd_btt_create(nd_region, 0, NULL, ndns);
349	if (!btt_dev)
350		return -ENOMEM;
351	btt_sb = devm_kzalloc(dev, sizeof(*btt_sb), GFP_KERNEL);
352	rc = __nd_btt_probe(to_nd_btt(btt_dev), ndns, btt_sb);
353	dev_dbg(dev, "btt: %s\n", rc == 0 ? dev_name(btt_dev) : "<none>");
354	if (rc < 0) {
355		struct nd_btt *nd_btt = to_nd_btt(btt_dev);
356
357		nd_detach_ndns(btt_dev, &nd_btt->ndns);
358		put_device(btt_dev);
359	}
360
361	return rc;
362}
363EXPORT_SYMBOL(nd_btt_probe);
~/ Read-only file preview.