ibcore: Protect against concurrent access to hardware stats.
Currently access to hardware stats buffer isn't protected, this can result in multiple writes and reads at the same time to the same memory location. This can lead to providing an incorrect value to the user. Add a mutex to protect against it. Linux commit: e945130b52bea65d15f9bdf54949d4cb7a88db7f MFC after: 1 week Reviewed by: kib Sponsored by: Mellanox Technologies // NVIDIA Networking
This commit is contained in:
parent
d8cbfa101c
commit
912e98cede
@ -827,10 +827,15 @@ static ssize_t show_hw_stats(struct kobject *kobj, struct attribute *attr,
|
|||||||
dev = port->ibdev;
|
dev = port->ibdev;
|
||||||
stats = port->hw_stats;
|
stats = port->hw_stats;
|
||||||
}
|
}
|
||||||
|
mutex_lock(&stats->lock);
|
||||||
ret = update_hw_stats(dev, stats, hsa->port_num, hsa->index);
|
ret = update_hw_stats(dev, stats, hsa->port_num, hsa->index);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto unlock;
|
||||||
return print_hw_stat(stats, hsa->index, buf);
|
ret = print_hw_stat(stats, hsa->index, buf);
|
||||||
|
unlock:
|
||||||
|
mutex_unlock(&stats->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t show_stats_lifespan(struct kobject *kobj,
|
static ssize_t show_stats_lifespan(struct kobject *kobj,
|
||||||
@ -838,17 +843,25 @@ static ssize_t show_stats_lifespan(struct kobject *kobj,
|
|||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
struct hw_stats_attribute *hsa;
|
struct hw_stats_attribute *hsa;
|
||||||
|
struct rdma_hw_stats *stats;
|
||||||
int msecs;
|
int msecs;
|
||||||
|
|
||||||
hsa = container_of(attr, struct hw_stats_attribute, attr);
|
hsa = container_of(attr, struct hw_stats_attribute, attr);
|
||||||
if (!hsa->port_num) {
|
if (!hsa->port_num) {
|
||||||
struct ib_device *dev = container_of((struct device *)kobj,
|
struct ib_device *dev = container_of((struct device *)kobj,
|
||||||
struct ib_device, dev);
|
struct ib_device, dev);
|
||||||
msecs = jiffies_to_msecs(dev->hw_stats->lifespan);
|
|
||||||
|
stats = dev->hw_stats;
|
||||||
} else {
|
} else {
|
||||||
struct ib_port *p = container_of(kobj, struct ib_port, kobj);
|
struct ib_port *p = container_of(kobj, struct ib_port, kobj);
|
||||||
msecs = jiffies_to_msecs(p->hw_stats->lifespan);
|
|
||||||
|
stats = p->hw_stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&stats->lock);
|
||||||
|
msecs = jiffies_to_msecs(stats->lifespan);
|
||||||
|
mutex_unlock(&stats->lock);
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", msecs);
|
return sprintf(buf, "%d\n", msecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -857,6 +870,7 @@ static ssize_t set_stats_lifespan(struct kobject *kobj,
|
|||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct hw_stats_attribute *hsa;
|
struct hw_stats_attribute *hsa;
|
||||||
|
struct rdma_hw_stats *stats;
|
||||||
int msecs;
|
int msecs;
|
||||||
int jiffies;
|
int jiffies;
|
||||||
int ret;
|
int ret;
|
||||||
@ -871,11 +885,18 @@ static ssize_t set_stats_lifespan(struct kobject *kobj,
|
|||||||
if (!hsa->port_num) {
|
if (!hsa->port_num) {
|
||||||
struct ib_device *dev = container_of((struct device *)kobj,
|
struct ib_device *dev = container_of((struct device *)kobj,
|
||||||
struct ib_device, dev);
|
struct ib_device, dev);
|
||||||
dev->hw_stats->lifespan = jiffies;
|
|
||||||
|
stats = dev->hw_stats;
|
||||||
} else {
|
} else {
|
||||||
struct ib_port *p = container_of(kobj, struct ib_port, kobj);
|
struct ib_port *p = container_of(kobj, struct ib_port, kobj);
|
||||||
p->hw_stats->lifespan = jiffies;
|
|
||||||
|
stats = p->hw_stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&stats->lock);
|
||||||
|
stats->lifespan = jiffies;
|
||||||
|
mutex_unlock(&stats->lock);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -968,6 +989,7 @@ static void setup_hw_stats(struct ib_device *device, struct ib_port *port,
|
|||||||
sysfs_attr_init(hsag->attrs[i]);
|
sysfs_attr_init(hsag->attrs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_init(&stats->lock);
|
||||||
/* treat an error here as non-fatal */
|
/* treat an error here as non-fatal */
|
||||||
hsag->attrs[i] = alloc_hsa_lifespan("lifespan", port_num);
|
hsag->attrs[i] = alloc_hsa_lifespan("lifespan", port_num);
|
||||||
if (hsag->attrs[i])
|
if (hsag->attrs[i])
|
||||||
|
@ -438,6 +438,9 @@ enum ib_port_speed {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* struct rdma_hw_stats
|
* struct rdma_hw_stats
|
||||||
|
* @lock - Mutex to protect parallel write access to lifespan and values
|
||||||
|
* of counters, which are 64bits and not guaranteeed to be written
|
||||||
|
* atomicaly on 32bits systems.
|
||||||
* @timestamp - Used by the core code to track when the last update was
|
* @timestamp - Used by the core code to track when the last update was
|
||||||
* @lifespan - Used by the core code to determine how old the counters
|
* @lifespan - Used by the core code to determine how old the counters
|
||||||
* should be before being updated again. Stored in jiffies, defaults
|
* should be before being updated again. Stored in jiffies, defaults
|
||||||
@ -453,6 +456,7 @@ enum ib_port_speed {
|
|||||||
* filled in by the drivers get_stats routine
|
* filled in by the drivers get_stats routine
|
||||||
*/
|
*/
|
||||||
struct rdma_hw_stats {
|
struct rdma_hw_stats {
|
||||||
|
struct mutex lock; /* Protect lifespan and values[] */
|
||||||
unsigned long timestamp;
|
unsigned long timestamp;
|
||||||
unsigned long lifespan;
|
unsigned long lifespan;
|
||||||
const char * const *names;
|
const char * const *names;
|
||||||
|
Loading…
Reference in New Issue
Block a user