Re: invalid drv data in show attribute

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>On Sun, Sep 04, 2022 at 02:37:32PM +0000, Czerwacki, Eial wrote:
>> Greetings,
>>
>> while working on a driver, I've found a bug that I'm unable to understand.
>> I assume that I'm doing something wrong. here is my reduced c file:
>
>Other minor things now that my coffee has kicked in:
>
>> /* modules info */
>> #define DEVICE_NAME "vSMP"
>> #define DRIVER_LICENSE "GPL v2"
>> #define DRIVER_AUTHOR "Eial Czerwacki <eial.czerwacki@xxxxxxx>"
>> #define DRIVER_DESC "vSMP hypervisor driver"
>
>For things that you only ever use once, no need for a #define.
sure

>
>> #define DRIVER_VERSION "0.1"
>
>drivers never have versions once they are merged into the kernel tree,
>just drop it.
acked

>
>>
>> #define PCI_DEVICE_ID_SAP_FLX_VSMP_CTL 0x1011
>>
>> #define ROOT_SYFS_FOLDER "vsmp"
>> #define DEVICE_ATTR_NAME(_name_) &dev_attr_##_name_ .attr
>
>That's very very odd, don't do that.  Spell it out so that it makes
>sense what is happening, otherwise this looks like a driver-core #define
>that I had never known was there.  Turns out it wasn't there :)
will do

>
>> #ifndef sysfs_emit
>> #define sysfs_emit sprintf
>> #endif // sysfs_emit
>>
>> MODULE_LICENSE(DRIVER_LICENSE);
>> MODULE_AUTHOR(DRIVER_AUTHOR);
>> MODULE_DESCRIPTION(DRIVER_DESC);
>> MODULE_VERSION(DRIVER_VERSION);
>>
>> #define MAX_LABEL_LEN 81
>>
>> struct data {
>>       char version[MAX_LABEL_LEN];
>>       struct pci_dev *pdev;
>>       struct kobject *kobj;
>
>Think about which structure is going to own this data.  You have
>pointers to 2 reference counted objects, yet no reference count on this
>object.  So who controls the lifespan of it and how?
>
the kobj ptr is just for the link I've mentioned in the other mail.
as for pdev, I assume that I can get the bars somehow from the device struct right?

>> };
>>
>> static ssize_t version_show(struct device *dev, struct device_attribute *attr,
>>                           char *buf)
>> {
>>       struct data *d = dev_get_drvdata(dev);
>>
>>       return sysfs_emit(buf, "%s\n", d->version);
>> }
>>
>> DEVICE_ATTR_RO(version);
>>
>> static int populate_version(struct data *d)
>> {
>>       int ret_val;
>>
>>       snprintf(d->version, sizeof(d->version) - 1,
>>                "%u.%u.%u.%u", 1,2,3,4);
>>
>>       ret_val = sysfs_add_file_to_group(d->kobj, DEVICE_ATTR_NAME(version), NULL);
>
>Just call sysfs_create_file(), don't add a file to a group like this.
>
>If you want a named group, then statically create it ahead of time with
>a name, which makes this all much simpler.
>
>In fact, never call any "create_file()" function, use lists of attribute
>groups as the driver core handles them automatically for you, no need to
>manually add or remove or anything else.  Much simpler and easier for a
>driver writer to use instead of having to have the same error handling
>logic everywhere.
you are correct, I don't know why I decided to treat the parent folder as group.
will use that, thanks

>
>>       if (ret_val) {
>>               dev_err(&d->pdev->dev, "Failed to create version entry, error (%d)\n",
>>                       ret_val);
>>               return -EINVAL;
>>       }
>>       dev_info(&d->pdev->dev, "version is %s\n", d->version);
>>
>>       return ret_val;
>> }
>>
>> static const struct pci_device_id vsmp_pci_table[] = {
>>       { PCI_VDEVICE(SCALEMP, PCI_DEVICE_ID_SAP_FLX_VSMP_CTL), 0, },
>>       { 0, }, /* terminate list */
>> };
>>
>> static int vsmp_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
>> {
>>       struct data *d;
>>       int ret_val = 0;
>>
>>       d = devm_kzalloc(&pci->dev, sizeof(*d), GFP_KERNEL);
>>       if (IS_ERR(d))
>>               return PTR_ERR(d);
>>
>>       d->pdev = pci;
>>       pci_set_drvdata(pci, d);
>>       d->kobj = kobject_create_and_add(ROOT_SYFS_FOLDER, &d->pdev->dev.kobj);
>
>That's a crazy pointer chain there.
>
>Never add a "raw" kobject to a struct device as you then just broke the
>tree and userspace will never know it is there so userspace tools and
>libraries can't see it unless they manually walk the sysfs tree (and you
>really don't want them doing that.)  With what you did here, this object
>is now invisible to libudev so no library will see it :(
that is the root of my issue, right?

>
>
>>       if (!d->kobj) {
>>               kfree(d);
>>               dev_err(&d->pdev->dev, "Failed to create vSMP sysfs entry.\n");
>>
>>               return -EINVAL;
>>       }
>>
>>       ret_val = sysfs_create_link(hypervisor_kobj, d->kobj, ROOT_SYFS_FOLDER);
>
>Again, no need to ever create a link here.  symlinks are usually for
>pointing to attributes of something (driver, device, etc.) or for when
>we have messed up in the past and had to move an object somewhere else
>and keep userspace from breaking by adding a link so that tools continue
>to work properly.
>
>Don't create links to start with for no good reason.  And if you do,
>document the heck out of it so we understand why.
I understand, as said in the other mail, the link is for easy access to the data like
block devices can be found under /sys/block

>
>>       if (ret_val) {
>>               kobject_del(d->kobj);
>>               kfree(d);
>>               dev_err(&d->pdev->dev, "Failed to link obj to hypervisor, error (%d)\n", ret_val);
>>
>>               return ret_val;
>>       }
>>
>>       populate_version(d);
>
>No error handling :)
right, thanks!

Eial




[Index of Archives]     [Linux Driver Development]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux