staticint dax_bus_uevent(conststruct device *dev, struct kobj_uevent_env *env)
{ /* * We only ever expect to handle device-dax instances, i.e. the * @type argument to MODULE_ALIAS_DAX_DEVICE() is always zero
*/ return add_uevent_var(env, "MODALIAS=" DAX_DEVICE_MODALIAS_FMT, 0);
}
/* * Static dax regions are regions created by an external subsystem * nvdimm where a single range is assigned. Its boundaries are by the external * subsystem and are usually limited to one physical memory range. For example, * for PMEM it is usually defined by NVDIMM Namespace boundaries (i.e. a * single contiguous range) * * On dynamic dax regions, the assigned region can be partitioned by dax core * into multiple subdivisions. A subdivision is represented into one * /dev/daxN.M device composed by one or more potentially discontiguous ranges. * * When allocating a dax region, drivers must set whether it's static * (IORESOURCE_DAX_STATIC). On static dax devices, the @pgmap is pre-assigned * to dax core when calling devm_create_dev_dax(), whereas in dynamic dax * devices it is NULL but afterwards allocated by dax core on device ->probe(). * Care is needed to make sure that dynamic dax devices are torn down with a * cleared @pgmap field (see kill_dev_dax()).
*/ staticbool is_static(struct dax_region *dax_region)
{ return (dax_region->res.flags & IORESOURCE_DAX_STATIC) != 0;
}
if (dax_match_id(dax_drv, dev)) return1; return dax_match_type(dax_drv, dev);
}
/* * Rely on the fact that drvdata is set before the attributes are * registered, and that the attributes are unregistered before drvdata * is cleared to assume that drvdata is always valid.
*/ static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct dax_region *dax_region = dev_get_drvdata(dev);
if (IS_ERR(dev_dax))
rc = PTR_ERR(dev_dax); else { /* * In support of crafting multiple new devices * simultaneously multiple seeds can be created, * but only the first one that has not been * successfully bound is tracked as the region * seed.
*/ if (!dax_region->seed)
dax_region->seed = &dev_dax->dev;
dax_region->youngest = &dev_dax->dev;
rc = len;
}
}
up_write(&dax_region_rwsem);
/* * Dynamic dax region have the pgmap allocated via dev_kzalloc() * and thus freed by devm. Clear the pgmap to not have stale pgmap * ranges on probe() from previous reconfigurations of region devices.
*/ if (!static_dev_dax(dev_dax))
dev_dax->pgmap = NULL;
}
EXPORT_SYMBOL_GPL(kill_dev_dax);
staticvoid trim_dev_dax_range(struct dev_dax *dev_dax)
{ int i = dev_dax->nr_range - 1; struct range *range = &dev_dax->ranges[i].range; struct dax_region *dax_region = dev_dax->region;
lockdep_assert_held_write(&dax_region_rwsem);
dev_dbg(&dev_dax->dev, "delete range[%d]: %#llx:%#llx\n", i,
(unsignedlonglong)range->start,
(unsignedlonglong)range->end);
/* a return value >= 0 indicates this invocation invalidated the id */ staticint __free_dev_dax_id(struct dev_dax *dev_dax)
{ struct dax_region *dax_region; int rc = dev_dax->id;
victim = device_find_child_by_name(dax_region->dev, buf); if (!victim) return -ENXIO;
device_lock(dev);
device_lock(victim);
dev_dax = to_dev_dax(victim);
down_write(&dax_dev_rwsem); if (victim->driver || dev_dax_size(dev_dax))
rc = -EBUSY; else { /* * Invalidate the device so it does not become active * again, but always preserve device-id-0 so that * /sys/bus/dax/ is guaranteed to be populated while any * dax_region is registered.
*/ if (dev_dax->id > 0) {
do_del = __free_dev_dax_id(dev_dax) >= 0;
rc = len; if (dax_region->seed == victim)
dax_region->seed = NULL; if (dax_region->youngest == victim)
dax_region->youngest = NULL;
} else
rc = -EBUSY;
}
up_write(&dax_dev_rwsem);
device_unlock(victim);
/* won the race to invalidate the device, clean it up */ if (do_del)
devm_release_action(dev, unregister_dev_dax, victim);
device_unlock(dev);
put_device(victim);
if (is_static(dax_region)) if (a == &dev_attr_available_size.attr
|| a == &dev_attr_create.attr
|| a == &dev_attr_seed.attr
|| a == &dev_attr_delete.attr) return0; return a->mode;
}
struct dax_region *alloc_dax_region(struct device *parent, int region_id, struct range *range, int target_node, unsignedint align, unsignedlong flags)
{ struct dax_region *dax_region;
/* * The DAX core assumes that it can store its private data in * parent->driver_data. This WARN is a reminder / safeguard for * developers of device-dax drivers.
*/ if (dev_get_drvdata(parent)) {
dev_WARN(parent, "dax core failed to setup private data\n"); return NULL;
}
if (!IS_ALIGNED(range->start, align)
|| !IS_ALIGNED(range_len(range), align)) return NULL;
dax_region = kzalloc(sizeof(*dax_region), GFP_KERNEL); if (!dax_region) return NULL;
/* handle the seed alloc special case */ if (!size) { if (dev_WARN_ONCE(dev, dev_dax->nr_range, "0-size allocation must be first\n")) return -EBUSY; /* nr_range == 0 is elsewhere special cased as 0-size device */ return0;
}
dev_dbg(dev, "alloc range[%d]: %pa:%pa\n", dev_dax->nr_range - 1,
&alloc->start, &alloc->end); /* * A dev_dax instance must be registered before mapping device * children can be added. Defer to devm_create_dev_dax() to add * the initial mapping device.
*/ if (!device_is_registered(&dev_dax->dev)) return0;
rc = devm_register_dax_mapping(dev_dax, dev_dax->nr_range - 1); if (rc)
trim_dev_dax_range(dev_dax);
staticbool alloc_is_aligned(struct dev_dax *dev_dax, resource_size_t size)
{ /* * The minimum mapping granularity for a device instance is a * single subsection, unless the arch says otherwise.
*/ return IS_ALIGNED(size, max_t(unsignedlong, dev_dax->align, memremap_compat_align()));
}
if (dev_WARN_ONCE(dev, !adjust || i != dev_dax->nr_range - 1, "failed to find matching resource\n")) return -ENXIO; return adjust_dev_dax_range(dev_dax, adjust, range_len(range)
- shrink);
} return0;
}
/* * Only allow adjustments that preserve the relative pgoff of existing * allocations. I.e. the dev_dax->ranges array is ordered by increasing pgoff.
*/ staticbool adjust_ok(struct dev_dax *dev_dax, struct resource *res)
{ struct dev_dax_range *last; int i;
if (dev_dax->nr_range == 0) returnfalse; if (strcmp(res->name, dev_name(&dev_dax->dev)) != 0) returnfalse;
last = &dev_dax->ranges[dev_dax->nr_range - 1]; if (last->range.start != res->start || last->range.end != res->end) returnfalse; for (i = 0; i < dev_dax->nr_range - 1; i++) { struct dev_dax_range *dax_range = &dev_dax->ranges[i];
if (dax_range->pgoff > last->pgoff) returnfalse;
}
if (dev->driver) return -EBUSY; if (size == dev_size) return0; if (size > dev_size && size - dev_size > avail) return -ENOSPC; if (size < dev_size) return dev_dax_shrink(dev_dax, size);
to_alloc = size - dev_size; if (dev_WARN_ONCE(dev, !alloc_is_aligned(dev_dax, to_alloc), "resize of %pa misaligned\n", &to_alloc)) return -ENXIO;
/* * Expand the device into the unused portion of the region. This * may involve adjusting the end of an existing resource, or * allocating a new resource.
*/
retry:
first = region_res->child; if (!first) return alloc_dev_dax_range(dev_dax, dax_region->res.start, to_alloc);
rc = -ENOSPC; for (res = first; res; res = res->sibling) { struct resource *next = res->sibling;
/* space at the beginning of the region */ if (res == first && res->start > dax_region->res.start) {
alloc = min(res->start - dax_region->res.start, to_alloc);
rc = alloc_dev_dax_range(dev_dax, dax_region->res.start, alloc); break;
}
alloc = 0; /* space between allocations */ if (next && next->start > res->end + 1)
alloc = min(next->start - (res->end + 1), to_alloc);
/* space at the end of the region */ if (!alloc && !next && res->end < region_res->end)
alloc = min(region_res->end - res->end, to_alloc);
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
{ /* * We only ever expect to handle device-dax instances, i.e. the * @type argument to MODULE_ALIAS_DAX_DEVICE() is always zero
*/ return sysfs_emit(buf, DAX_DEVICE_MODALIAS_FMT "\n", 0);
} static DEVICE_ATTR_RO(modalias);
if (a == &dev_attr_target_node.attr && dev_dax_target_node(dev_dax) < 0) return0; if (a == &dev_attr_numa_node.attr && !IS_ENABLED(CONFIG_NUMA)) return0; if (a == &dev_attr_mapping.attr && is_static(dax_region)) return0; if ((a == &dev_attr_align.attr ||
a == &dev_attr_size.attr) && is_static(dax_region)) return0444; return a->mode;
}
/* * No dax_operations since there is no access to this device outside of * mmap of the resulting character device.
*/
dax_dev = alloc_dax(dev_dax, NULL); if (IS_ERR(dax_dev)) {
rc = PTR_ERR(dax_dev); goto err_alloc_dax;
}
set_dax_synchronous(dax_dev);
set_dax_nocache(dax_dev);
set_dax_nomc(dax_dev);
/* a device_dax instance is dead while the driver is not attached */
kill_dax(dax_dev);
rc = devm_add_action_or_reset(dax_region->dev, unregister_dev_dax, dev); if (rc) return ERR_PTR(rc);
/* register mapping device for the initial allocation range */ if (dev_dax->nr_range && range_len(&dev_dax->ranges[0].range)) {
rc = devm_register_dax_mapping(dev_dax, 0); if (rc) return ERR_PTR(rc);
}
/* * dax_bus_probe() calls dax_drv->probe() unconditionally. * So better be safe than sorry and ensure it is provided.
*/ if (!dax_drv->probe) return -EINVAL;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.