static ssize_t dev_dax_resize()

in bus.c [962:1033]


static ssize_t dev_dax_resize(struct dax_region *dax_region,
		struct dev_dax *dev_dax, resource_size_t size)
{
	resource_size_t avail = dax_region_avail_size(dax_region), to_alloc;
	resource_size_t dev_size = dev_dax_size(dev_dax);
	struct resource *region_res = &dax_region->res;
	struct device *dev = &dev_dax->dev;
	struct resource *res, *first;
	resource_size_t alloc = 0;
	int rc;

	if (dev->driver)
		return -EBUSY;
	if (size == dev_size)
		return 0;
	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);

		if (!alloc)
			continue;

		if (adjust_ok(dev_dax, res)) {
			rc = adjust_dev_dax_range(dev_dax, res, resource_size(res) + alloc);
			break;
		}
		rc = alloc_dev_dax_range(dev_dax, res->end + 1, alloc);
		break;
	}
	if (rc)
		return rc;
	to_alloc -= alloc;
	if (to_alloc)
		goto retry;
	return 0;
}