ssize_t nd_namespace_store()

in claim.c [135:227]


ssize_t nd_namespace_store(struct device *dev,
		struct nd_namespace_common **_ndns, const char *buf,
		size_t len)
{
	struct nd_namespace_common *ndns;
	struct device *found;
	char *name;

	if (dev->driver) {
		dev_dbg(dev, "namespace already active\n");
		return -EBUSY;
	}

	name = kstrndup(buf, len, GFP_KERNEL);
	if (!name)
		return -ENOMEM;
	strim(name);

	if (strncmp(name, "namespace", 9) == 0 || strcmp(name, "") == 0)
		/* pass */;
	else {
		len = -EINVAL;
		goto out;
	}

	ndns = *_ndns;
	if (strcmp(name, "") == 0) {
		nd_detach_and_reset(dev, _ndns);
		goto out;
	} else if (ndns) {
		dev_dbg(dev, "namespace already set to: %s\n",
				dev_name(&ndns->dev));
		len = -EBUSY;
		goto out;
	}

	found = device_find_child(dev->parent, name, namespace_match);
	if (!found) {
		dev_dbg(dev, "'%s' not found under %s\n", name,
				dev_name(dev->parent));
		len = -ENODEV;
		goto out;
	}

	ndns = to_ndns(found);

	switch (ndns->claim_class) {
	case NVDIMM_CCLASS_NONE:
		break;
	case NVDIMM_CCLASS_BTT:
	case NVDIMM_CCLASS_BTT2:
		if (!is_nd_btt(dev)) {
			len = -EBUSY;
			goto out_attach;
		}
		break;
	case NVDIMM_CCLASS_PFN:
		if (!is_nd_pfn(dev)) {
			len = -EBUSY;
			goto out_attach;
		}
		break;
	case NVDIMM_CCLASS_DAX:
		if (!is_nd_dax(dev)) {
			len = -EBUSY;
			goto out_attach;
		}
		break;
	default:
		len = -EBUSY;
		goto out_attach;
		break;
	}

	if (__nvdimm_namespace_capacity(ndns) < SZ_16M) {
		dev_dbg(dev, "%s too small to host\n", name);
		len = -ENXIO;
		goto out_attach;
	}

	WARN_ON_ONCE(!is_nvdimm_bus_locked(dev));
	if (!__nd_attach_ndns(dev, ndns, _ndns)) {
		dev_dbg(dev, "%s already claimed\n",
				dev_name(&ndns->dev));
		len = -EBUSY;
	}

 out_attach:
	put_device(&ndns->dev); /* from device_find_child */
 out:
	kfree(name);
	return len;
}