cxl/port: Fix missing target list lock
[ Upstream commit 5459e186a5c9f412334321cff58d70dcb0e48a04 ]
cxl_port_setup_targets() modifies the ->targets[] array of a switch
decoder. target_list_show() expects to be able to emit a coherent
snapshot of that array by "holding" ->target_lock for read. The
target_lock is held for write during initialization of the ->targets[]
array, but it is not held for write during cxl_port_setup_targets().
The ->target_lock() predates the introduction of @cxl_region_rwsem. That
semaphore protects changes to host-physical-address (HPA) decode which
is precisely what writes to a switch decoder's target list affects.
Replace ->target_lock with @cxl_region_rwsem.
Now the side-effect of snapshotting a unstable view of a decoder's
target list is likely benign so the Fixes: tag is presumptive.
Fixes: 27b3f8d138
("cxl/region: Program target lists")
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
4e0d679193
commit
1a5369728c
|
@ -172,14 +172,10 @@ static ssize_t target_list_show(struct device *dev,
|
|||
{
|
||||
struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(dev);
|
||||
ssize_t offset;
|
||||
unsigned int seq;
|
||||
int rc;
|
||||
|
||||
do {
|
||||
seq = read_seqbegin(&cxlsd->target_lock);
|
||||
rc = emit_target_list(cxlsd, buf);
|
||||
} while (read_seqretry(&cxlsd->target_lock, seq));
|
||||
|
||||
guard(rwsem_read)(&cxl_region_rwsem);
|
||||
rc = emit_target_list(cxlsd, buf);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
offset = rc;
|
||||
|
@ -1579,7 +1575,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_mem_find_port, CXL);
|
|||
static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd,
|
||||
struct cxl_port *port, int *target_map)
|
||||
{
|
||||
int i, rc = 0;
|
||||
int i;
|
||||
|
||||
if (!target_map)
|
||||
return 0;
|
||||
|
@ -1589,19 +1585,16 @@ static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd,
|
|||
if (xa_empty(&port->dports))
|
||||
return -EINVAL;
|
||||
|
||||
write_seqlock(&cxlsd->target_lock);
|
||||
guard(rwsem_write)(&cxl_region_rwsem);
|
||||
for (i = 0; i < cxlsd->cxld.interleave_ways; i++) {
|
||||
struct cxl_dport *dport = find_dport(port, target_map[i]);
|
||||
|
||||
if (!dport) {
|
||||
rc = -ENXIO;
|
||||
break;
|
||||
}
|
||||
if (!dport)
|
||||
return -ENXIO;
|
||||
cxlsd->target[i] = dport;
|
||||
}
|
||||
write_sequnlock(&cxlsd->target_lock);
|
||||
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos)
|
||||
|
@ -1671,7 +1664,6 @@ static int cxl_switch_decoder_init(struct cxl_port *port,
|
|||
return -EINVAL;
|
||||
|
||||
cxlsd->nr_targets = nr_targets;
|
||||
seqlock_init(&cxlsd->target_lock);
|
||||
return cxl_decoder_init(port, &cxlsd->cxld);
|
||||
}
|
||||
|
||||
|
|
|
@ -404,7 +404,6 @@ struct cxl_endpoint_decoder {
|
|||
/**
|
||||
* struct cxl_switch_decoder - Switch specific CXL HDM Decoder
|
||||
* @cxld: base cxl_decoder object
|
||||
* @target_lock: coordinate coherent reads of the target list
|
||||
* @nr_targets: number of elements in @target
|
||||
* @target: active ordered target list in current decoder configuration
|
||||
*
|
||||
|
@ -416,7 +415,6 @@ struct cxl_endpoint_decoder {
|
|||
*/
|
||||
struct cxl_switch_decoder {
|
||||
struct cxl_decoder cxld;
|
||||
seqlock_t target_lock;
|
||||
int nr_targets;
|
||||
struct cxl_dport *target[];
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue