static int __pmem_label_update()

in label.c [877:969]


static int __pmem_label_update(struct nd_region *nd_region,
		struct nd_mapping *nd_mapping, struct nd_namespace_pmem *nspm,
		int pos, unsigned long flags)
{
	struct nd_namespace_common *ndns = &nspm->nsio.common;
	struct nd_interleave_set *nd_set = nd_region->nd_set;
	struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
	struct nd_namespace_label *nd_label;
	struct nd_namespace_index *nsindex;
	struct nd_label_ent *label_ent;
	struct nd_label_id label_id;
	struct resource *res;
	unsigned long *free;
	u32 nslot, slot;
	size_t offset;
	u64 cookie;
	int rc;

	if (!preamble_next(ndd, &nsindex, &free, &nslot))
		return -ENXIO;

	cookie = nd_region_interleave_set_cookie(nd_region, nsindex);
	nd_label_gen_id(&label_id, nspm->uuid, 0);
	for_each_dpa_resource(ndd, res)
		if (strcmp(res->name, label_id.id) == 0)
			break;

	if (!res) {
		WARN_ON_ONCE(1);
		return -ENXIO;
	}

	/* allocate and write the label to the staging (next) index */
	slot = nd_label_alloc_slot(ndd);
	if (slot == UINT_MAX)
		return -ENXIO;
	dev_dbg(ndd->dev, "allocated: %d\n", slot);

	nd_label = to_label(ndd, slot);
	memset(nd_label, 0, sizeof_namespace_label(ndd));
	nsl_set_uuid(ndd, nd_label, nspm->uuid);
	nsl_set_name(ndd, nd_label, nspm->alt_name);
	nsl_set_flags(ndd, nd_label, flags);
	nsl_set_nlabel(ndd, nd_label, nd_region->ndr_mappings);
	nsl_set_nrange(ndd, nd_label, 1);
	nsl_set_position(ndd, nd_label, pos);
	nsl_set_isetcookie(ndd, nd_label, cookie);
	nsl_set_rawsize(ndd, nd_label, resource_size(res));
	nsl_set_lbasize(ndd, nd_label, nspm->lbasize);
	nsl_set_dpa(ndd, nd_label, res->start);
	nsl_set_slot(ndd, nd_label, slot);
	nsl_set_type_guid(ndd, nd_label, &nd_set->type_guid);
	nsl_set_claim_class(ndd, nd_label, ndns->claim_class);
	nsl_calculate_checksum(ndd, nd_label);
	nd_dbg_dpa(nd_region, ndd, res, "\n");

	/* update label */
	offset = nd_label_offset(ndd, nd_label);
	rc = nvdimm_set_config_data(ndd, offset, nd_label,
			sizeof_namespace_label(ndd));
	if (rc < 0)
		return rc;

	/* Garbage collect the previous label */
	mutex_lock(&nd_mapping->lock);
	list_for_each_entry(label_ent, &nd_mapping->labels, list) {
		if (!label_ent->label)
			continue;
		if (test_and_clear_bit(ND_LABEL_REAP, &label_ent->flags) ||
		    nsl_uuid_equal(ndd, label_ent->label, nspm->uuid))
			reap_victim(nd_mapping, label_ent);
	}

	/* update index */
	rc = nd_label_write_index(ndd, ndd->ns_next,
			nd_inc_seq(__le32_to_cpu(nsindex->seq)), 0);
	if (rc == 0) {
		list_for_each_entry(label_ent, &nd_mapping->labels, list)
			if (!label_ent->label) {
				label_ent->label = nd_label;
				nd_label = NULL;
				break;
			}
		dev_WARN_ONCE(&nspm->nsio.common.dev, nd_label,
				"failed to track label: %d\n",
				to_slot(ndd, nd_label));
		if (nd_label)
			rc = -ENXIO;
	}
	mutex_unlock(&nd_mapping->lock);

	return rc;
}