From: Parav Pandit <parav@xxxxxxxxxxxx> In order to support sysfs entries in multiple net namespaces for a rdma device, introduce a ib_core_device whose scope is limited to hold core device and per port sysfs related entires. This is preparation patch so that multiple ib_core_devices in each net namespace can be created in subsequent patch who all can share ib_device. (a) Move sysfs specific fields to ib_core_device. (b) Make sysfs and device life cycle related routines to work on ib_core_device. (c) Introduce and use rdma_init_coredev() helper to initialize coredev fields. (d) Do not access driver data which is supposed to be used by the provider driver. Signed-off-by: Parav Pandit <parav@xxxxxxxxxxxx> Signed-off-by: Leon Romanovsky <leonro@xxxxxxxxxxxx> --- drivers/infiniband/core/core_priv.h | 2 ++ drivers/infiniband/core/device.c | 28 ++++++++++++++++------ drivers/infiniband/core/sysfs.c | 36 ++++++++++++++--------------- include/rdma/ib_verbs.h | 24 +++++++++++++++---- 4 files changed, 60 insertions(+), 30 deletions(-) diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index cc7535c5e192..0da0a26c02b9 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h @@ -54,6 +54,8 @@ struct pkey_index_qp_list { struct list_head qp_list; }; +extern const struct attribute_group ib_dev_attr_group; + int ib_device_register_sysfs(struct ib_device *device, int (*port_callback)(struct ib_device *, u8, struct kobject *)); diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 0027b0d79b09..16e1e854a3b4 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -269,6 +269,24 @@ static struct class ib_class = { .dev_uevent = ib_device_uevent, }; +static void rdma_init_coredev(struct ib_core_device *coredev, + struct ib_device *dev) +{ + /* This BUILD_BUG_ON is intended to catch layout change + * of union of ib_core_device and device. + * dev must be the first element as ib_core and providers + * driver uses it. Adding anything in ib_core_device before + * device will break this assumption. + */ + BUILD_BUG_ON(offsetof(struct ib_core_device, dev) != 0); + + coredev->dev.class = &ib_class; + coredev->dev.groups = dev->groups; + device_initialize(&coredev->dev); + coredev->owner = dev; + INIT_LIST_HEAD(&coredev->port_list); +} + /** * ib_alloc_device - allocate an IB device struct * @size:size of structure to allocate @@ -290,20 +308,16 @@ struct ib_device *ib_alloc_device(size_t size) if (!device) return NULL; - rdma_restrack_init(&device->res); - - device->dev.class = &ib_class; - device_initialize(&device->dev); - - dev_set_drvdata(&device->dev, device); + device->groups[0] = &ib_dev_attr_group; + rdma_init_coredev(&device->coredev, device); INIT_LIST_HEAD(&device->event_handler_list); spin_lock_init(&device->event_handler_lock); rwlock_init(&device->client_data_lock); INIT_LIST_HEAD(&device->client_data_list); - INIT_LIST_HEAD(&device->port_list); refcount_set(&device->refcount, 1); init_completion(&device->unreg_completion); + rdma_restrack_init(&device->res); return device; } diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index da4fafb28867..486219cc5ac4 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -1015,10 +1015,11 @@ static void setup_hw_stats(struct ib_device *device, struct ib_port *port, return; } -static int add_port(struct ib_device *device, int port_num, +static int add_port(struct ib_core_device *coredev, int port_num, int (*port_callback)(struct ib_device *, u8, struct kobject *)) { + struct ib_device *device = rdma_device_to_ibdev(&coredev->dev); struct ib_port *p; struct ib_port_attr attr; int i; @@ -1036,7 +1037,7 @@ static int add_port(struct ib_device *device, int port_num, p->port_num = port_num; ret = kobject_init_and_add(&p->kobj, &port_type, - device->ports_kobj, + coredev->ports_kobj, "%d", port_num); if (ret) { kfree(p); @@ -1127,7 +1128,7 @@ static int add_port(struct ib_device *device, int port_num, if (device->alloc_hw_stats && port_num) setup_hw_stats(device, p, port_num); - list_add_tail(&p->kobj.entry, &device->port_list); + list_add_tail(&p->kobj.entry, &coredev->port_list); kobject_uevent(&p->kobj, KOBJ_ADD); return 0; @@ -1277,15 +1278,15 @@ static struct attribute *ib_dev_attrs[] = { NULL, }; -static const struct attribute_group dev_attr_group = { +const struct attribute_group ib_dev_attr_group = { .attrs = ib_dev_attrs, }; -static void ib_free_port_attrs(struct ib_device *device) +static void ib_free_port_attrs(struct ib_core_device *coredev) { struct kobject *p, *t; - list_for_each_entry_safe(p, t, &device->port_list, entry) { + list_for_each_entry_safe(p, t, &coredev->port_list, entry) { struct ib_port *port = container_of(p, struct ib_port, kobj); list_del(&p->entry); @@ -1305,27 +1306,29 @@ static void ib_free_port_attrs(struct ib_device *device) kobject_put(p); } - kobject_put(device->ports_kobj); + kobject_put(coredev->ports_kobj); } -static int ib_setup_port_attrs(struct ib_device *device, +static int ib_setup_port_attrs(struct ib_core_device *coredev, int (*port_callback)(struct ib_device *, u8, struct kobject *)) { + struct ib_device *device = rdma_device_to_ibdev(&coredev->dev); int ret; int i; - device->ports_kobj = kobject_create_and_add("ports", &device->dev.kobj); - if (!device->ports_kobj) + coredev->ports_kobj = kobject_create_and_add("ports", + &coredev->dev.kobj); + if (!coredev->ports_kobj) return -ENOMEM; if (rdma_cap_ib_switch(device)) { - ret = add_port(device, 0, port_callback); + ret = add_port(coredev, 0, port_callback); if (ret) goto err_put; } else { for (i = 1; i <= device->phys_port_cnt; ++i) { - ret = add_port(device, i, port_callback); + ret = add_port(coredev, i, port_callback); if (ret) goto err_put; } @@ -1334,7 +1337,7 @@ static int ib_setup_port_attrs(struct ib_device *device, return 0; err_put: - ib_free_port_attrs(device); + ib_free_port_attrs(coredev); return ret; } @@ -1344,14 +1347,11 @@ int ib_device_register_sysfs(struct ib_device *device, { int ret; - device->groups[0] = &dev_attr_group; - device->dev.groups = device->groups; - ret = device_add(&device->dev); if (ret) return ret; - ret = ib_setup_port_attrs(device, port_callback); + ret = ib_setup_port_attrs(&device->coredev, port_callback); if (ret) { device_del(&device->dev); return ret; @@ -1371,6 +1371,6 @@ void ib_device_unregister_sysfs(struct ib_device *device) free_hsag(&device->dev.kobj, device->hw_stats_ag); kfree(device->hw_stats); - ib_free_port_attrs(device); + ib_free_port_attrs(&device->coredev); device_unregister(&device->dev); } diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 446143ed49ae..f9bedf28e292 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2257,6 +2257,16 @@ struct ib_counters_read_attr { struct uverbs_attr_bundle; +struct ib_core_device { + /* device must be the first element in structure until, + * union of ib_core_device and device exists in ib_device. + */ + struct device dev; + struct kobject *ports_kobj; + struct list_head port_list; + struct ib_device *owner; /* reach back to owner ib_device */ +}; + struct ib_device { /* Do not access @dma_device directly from ULP nor from HW drivers. */ struct device *dma_device; @@ -2553,16 +2563,17 @@ struct ib_device { struct rdma_netdev_alloc_params *params); struct module *owner; - struct device dev; + union { + struct device dev; + struct ib_core_device coredev; + }; + /* First group for device attributes, * Second group for driver provided attributes (optional). * It is NULL terminated array. */ const struct attribute_group *groups[3]; - struct kobject *ports_kobj; - struct list_head port_list; - enum { IB_DEV_UNINITIALIZED, IB_DEV_REGISTERED, @@ -4262,7 +4273,10 @@ rdma_set_device_sysfs_group(struct ib_device *dev, */ static inline struct ib_device *rdma_device_to_ibdev(struct device *device) { - return dev_get_drvdata(device); + struct ib_core_device *coredev = + container_of(device, struct ib_core_device, dev); + + return coredev->owner; } /** -- 2.19.1