static resource_size_t scan_allocate()

in namespace_devs.c [592:742]


static resource_size_t scan_allocate(struct nd_region *nd_region,
		struct nd_mapping *nd_mapping, struct nd_label_id *label_id,
		resource_size_t n)
{
	resource_size_t mapping_end = nd_mapping->start + nd_mapping->size - 1;
	bool is_pmem = strncmp(label_id->id, "pmem", 4) == 0;
	struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
	struct resource *res, *exist = NULL, valid;
	const resource_size_t to_allocate = n;
	int first;

	for_each_dpa_resource(ndd, res)
		if (strcmp(label_id->id, res->name) == 0)
			exist = res;

	valid.start = nd_mapping->start;
	valid.end = mapping_end;
	valid.name = "free space";
 retry:
	first = 0;
	for_each_dpa_resource(ndd, res) {
		struct resource *next = res->sibling, *new_res = NULL;
		resource_size_t allocate, available = 0;
		enum alloc_loc loc = ALLOC_ERR;
		const char *action;
		int rc = 0;

		/* ignore resources outside this nd_mapping */
		if (res->start > mapping_end)
			continue;
		if (res->end < nd_mapping->start)
			continue;

		/* space at the beginning of the mapping */
		if (!first++ && res->start > nd_mapping->start) {
			valid.start = nd_mapping->start;
			valid.end = res->start - 1;
			space_valid(nd_region, ndd, label_id, NULL, next, exist,
					to_allocate, &valid);
			available = resource_size(&valid);
			if (available)
				loc = ALLOC_BEFORE;
		}

		/* space between allocations */
		if (!loc && next) {
			valid.start = res->start + resource_size(res);
			valid.end = min(mapping_end, next->start - 1);
			space_valid(nd_region, ndd, label_id, res, next, exist,
					to_allocate, &valid);
			available = resource_size(&valid);
			if (available)
				loc = ALLOC_MID;
		}

		/* space at the end of the mapping */
		if (!loc && !next) {
			valid.start = res->start + resource_size(res);
			valid.end = mapping_end;
			space_valid(nd_region, ndd, label_id, res, next, exist,
					to_allocate, &valid);
			available = resource_size(&valid);
			if (available)
				loc = ALLOC_AFTER;
		}

		if (!loc || !available)
			continue;
		allocate = min(available, n);
		switch (loc) {
		case ALLOC_BEFORE:
			if (strcmp(res->name, label_id->id) == 0) {
				/* adjust current resource up */
				rc = adjust_resource(res, res->start - allocate,
						resource_size(res) + allocate);
				action = "cur grow up";
			} else
				action = "allocate";
			break;
		case ALLOC_MID:
			if (strcmp(next->name, label_id->id) == 0) {
				/* adjust next resource up */
				rc = adjust_resource(next, next->start
						- allocate, resource_size(next)
						+ allocate);
				new_res = next;
				action = "next grow up";
			} else if (strcmp(res->name, label_id->id) == 0) {
				action = "grow down";
			} else
				action = "allocate";
			break;
		case ALLOC_AFTER:
			if (strcmp(res->name, label_id->id) == 0)
				action = "grow down";
			else
				action = "allocate";
			break;
		default:
			return n;
		}

		if (strcmp(action, "allocate") == 0) {
			/* BLK allocate bottom up */
			if (!is_pmem)
				valid.start += available - allocate;

			new_res = nvdimm_allocate_dpa(ndd, label_id,
					valid.start, allocate);
			if (!new_res)
				rc = -EBUSY;
		} else if (strcmp(action, "grow down") == 0) {
			/* adjust current resource down */
			rc = adjust_resource(res, res->start, resource_size(res)
					+ allocate);
			if (rc == 0)
				res->flags |= DPA_RESOURCE_ADJUSTED;
		}

		if (!new_res)
			new_res = res;

		nd_dbg_dpa(nd_region, ndd, new_res, "%s(%d) %d\n",
				action, loc, rc);

		if (rc)
			return n;

		n -= allocate;
		if (n) {
			/*
			 * Retry scan with newly inserted resources.
			 * For example, if we did an ALLOC_BEFORE
			 * insertion there may also have been space
			 * available for an ALLOC_AFTER insertion, so we
			 * need to check this same resource again
			 */
			goto retry;
		} else
			return 0;
	}

	/*
	 * If we allocated nothing in the BLK case it may be because we are in
	 * an initial "pmem-reserve pass".  Only do an initial BLK allocation
	 * when none of the DPA space is reserved.
	 */
	if ((is_pmem || !ndd->dpa.child) && n == to_allocate)
		return init_dpa_allocation(label_id, nd_region, nd_mapping, n);
	return n;
}