Re: [PATCH v2 1/4] driver core: generalize driver_override in struct device

Frank Li <[email protected]>
Newsgroups gmane.linux.ports.sh.devel,gmane.linux.kernel,gmane.linux.kernel.hwmon,gmane.linux.ports.arm.msm,gmane.linux.sound
Message-ID <[email protected]>
From: Frank Li (AI-BOT) <[email protected]>

AI bot review and may be useless.

> +static ssize_t driver_override_store(struct device *dev,
> +				     struct device_attribute *attr,
> +				     const char *buf, size_t count)
> +{
> +	int ret;
> +
> +	ret = __device_set_driver_override(dev, buf, count);
> +	if (ret)
> +		return ret;
> +
> +	return count;
> +}

Potential issue: if __device_set_driver_override() succeeds but
modifies state, returning 'count' may not reflect actual bytes
consumed if buf contains embedded nulls. Consider documenting
expected behavior or validating input length upfront.

> +static ssize_t driver_override_show(struct device *dev,
> +				    struct device_attribute *attr, char *buf)
> +{
> +	guard(spinlock)(&dev->driver_override.lock);
> +	return sysfs_emit(buf, "%s\n", dev->driver_override.name);
> +}

Potential NULL dereference: if dev->driver_override.name is NULL,
sysfs_emit() will print "(null)". Add explicit check or document
that NULL is acceptable output.

> +	if (sp->bus->driver_override) {
> +		error = device_add_group(dev, &driver_override_dev_group);
> +		if (error)
> +			goto out_groups;
> +	}

Error path bug: on device_add_group() failure, code jumps to
out_groups but should jump to out_override (which doesn't exist
yet). This leaks the sysfs link created below. Reorder or add
intermediate label.

> +	error = sysfs_create_link(&sp->devices_kset->kobj, &dev->kobj, dev_name(dev));
> +	if (error)
> -		goto out_groups;
> +		goto out_override;

Good: label renamed to match new cleanup order.

> +out_override:
> +	if (dev->bus->driver_override)
> +		device_remove_group(dev, &driver_override_dev_group);

Potential issue: dev->bus may be NULL or different from sp->bus at
this point. Use sp->bus for consistency with the add path above.

> +int __device_set_driver_override(struct device *dev, const char *s, size_t len)
> +{
> +	const char *new, *old;
> +	char *cp;
> +
> +	if (!s)
> +		return -EINVAL;

Inconsistency: len parameter is passed but then recalculated via
strlen(s) below. If len is meant to be trusted, don't recalculate.
If not, remove the parameter or document why both exist.

> +	len = strlen(s);

This overwrites the len parameter, making the initial bounds check
at PAGE_SIZE potentially useless. Clarify intent: is len from
userspace or always recomputed?

> +	new = kstrndup(s, len, GFP_KERNEL);
> +	if (!new)
> +		return -ENOMEM;
> +
> +	spin_lock(&dev->driver_override.lock);
> +	old = dev->driver_override.name;
> +	if (cp != s) {
> +		dev->driver_override.name = new;
> +		spin_unlock(&dev->driver_override.lock);
> +	} else {
> +		/* "\n" passed - clear override */
> +		dev->driver_override.name = NULL;
> +		spin_unlock(&dev->driver_override.lock);
> +
> +		kfree(new);
> +	}
> +	kfree(old);

Logic is correct but confusing: cp is set only if '\n' is found, so
the condition `if (cp != s)` is checking "was newline NOT at start".
Add a comment explaining the two paths (newline-at-start clears,
otherwise
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.