Skip to content

Commit d79526b

Browse files
committed
Merge tag 'spi-fix-v7.0-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi fixes from Mark Brown: "There's a relatively large but ultimately simple fix for spidev here which addresses some ABBA races by simplifying down to just using a single lock, it's not clear to me that there was ever any benefit in having the two separate locks in the first place. We also have simple missing error check fix in in the wpcm-fiu driver" * tag 'spi-fix-v7.0-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: spi: spidev: fix lock inversion between spi_lock and buf_lock spi: wpcm-fiu: Fix potential NULL pointer dereference in wpcm_fiu_probe()
2 parents 0de6219 + 40534d1 commit d79526b

2 files changed

Lines changed: 23 additions & 42 deletions

File tree

drivers/spi/spi-wpcm-fiu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,11 +459,11 @@ static int wpcm_fiu_probe(struct platform_device *pdev)
459459

460460
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory");
461461
fiu->memory = devm_ioremap_resource(dev, res);
462-
fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL);
463462
if (IS_ERR(fiu->memory))
464463
return dev_err_probe(dev, PTR_ERR(fiu->memory),
465464
"Failed to map flash memory window\n");
466465

466+
fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL);
467467
fiu->shm_regmap = syscon_regmap_lookup_by_phandle_optional(dev->of_node, "nuvoton,shm");
468468

469469
wpcm_fiu_hw_init(fiu);

drivers/spi/spidev.c

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ struct spidev_data {
7474
struct list_head device_entry;
7575

7676
/* TX/RX buffers are NULL unless this device is open (users > 0) */
77-
struct mutex buf_lock;
7877
unsigned users;
7978
u8 *tx_buffer;
8079
u8 *rx_buffer;
@@ -102,24 +101,6 @@ spidev_sync_unlocked(struct spi_device *spi, struct spi_message *message)
102101
return status;
103102
}
104103

105-
static ssize_t
106-
spidev_sync(struct spidev_data *spidev, struct spi_message *message)
107-
{
108-
ssize_t status;
109-
struct spi_device *spi;
110-
111-
mutex_lock(&spidev->spi_lock);
112-
spi = spidev->spi;
113-
114-
if (spi == NULL)
115-
status = -ESHUTDOWN;
116-
else
117-
status = spidev_sync_unlocked(spi, message);
118-
119-
mutex_unlock(&spidev->spi_lock);
120-
return status;
121-
}
122-
123104
static inline ssize_t
124105
spidev_sync_write(struct spidev_data *spidev, size_t len)
125106
{
@@ -132,7 +113,8 @@ spidev_sync_write(struct spidev_data *spidev, size_t len)
132113

133114
spi_message_init(&m);
134115
spi_message_add_tail(&t, &m);
135-
return spidev_sync(spidev, &m);
116+
117+
return spidev_sync_unlocked(spidev->spi, &m);
136118
}
137119

138120
static inline ssize_t
@@ -147,7 +129,8 @@ spidev_sync_read(struct spidev_data *spidev, size_t len)
147129

148130
spi_message_init(&m);
149131
spi_message_add_tail(&t, &m);
150-
return spidev_sync(spidev, &m);
132+
133+
return spidev_sync_unlocked(spidev->spi, &m);
151134
}
152135

153136
/*-------------------------------------------------------------------------*/
@@ -157,15 +140,19 @@ static ssize_t
157140
spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
158141
{
159142
struct spidev_data *spidev;
160-
ssize_t status;
143+
ssize_t status = -ESHUTDOWN;
161144

162145
/* chipselect only toggles at start or end of operation */
163146
if (count > bufsiz)
164147
return -EMSGSIZE;
165148

166149
spidev = filp->private_data;
167150

168-
mutex_lock(&spidev->buf_lock);
151+
mutex_lock(&spidev->spi_lock);
152+
153+
if (spidev->spi == NULL)
154+
goto err_spi_removed;
155+
169156
status = spidev_sync_read(spidev, count);
170157
if (status > 0) {
171158
unsigned long missing;
@@ -176,7 +163,9 @@ spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
176163
else
177164
status = status - missing;
178165
}
179-
mutex_unlock(&spidev->buf_lock);
166+
167+
err_spi_removed:
168+
mutex_unlock(&spidev->spi_lock);
180169

181170
return status;
182171
}
@@ -187,7 +176,7 @@ spidev_write(struct file *filp, const char __user *buf,
187176
size_t count, loff_t *f_pos)
188177
{
189178
struct spidev_data *spidev;
190-
ssize_t status;
179+
ssize_t status = -ESHUTDOWN;
191180
unsigned long missing;
192181

193182
/* chipselect only toggles at start or end of operation */
@@ -196,13 +185,19 @@ spidev_write(struct file *filp, const char __user *buf,
196185

197186
spidev = filp->private_data;
198187

199-
mutex_lock(&spidev->buf_lock);
188+
mutex_lock(&spidev->spi_lock);
189+
190+
if (spidev->spi == NULL)
191+
goto err_spi_removed;
192+
200193
missing = copy_from_user(spidev->tx_buffer, buf, count);
201194
if (missing == 0)
202195
status = spidev_sync_write(spidev, count);
203196
else
204197
status = -EFAULT;
205-
mutex_unlock(&spidev->buf_lock);
198+
199+
err_spi_removed:
200+
mutex_unlock(&spidev->spi_lock);
206201

207202
return status;
208203
}
@@ -379,14 +374,6 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
379374

380375
ctlr = spi->controller;
381376

382-
/* use the buffer lock here for triple duty:
383-
* - prevent I/O (from us) so calling spi_setup() is safe;
384-
* - prevent concurrent SPI_IOC_WR_* from morphing
385-
* data fields while SPI_IOC_RD_* reads them;
386-
* - SPI_IOC_MESSAGE needs the buffer locked "normally".
387-
*/
388-
mutex_lock(&spidev->buf_lock);
389-
390377
switch (cmd) {
391378
/* read requests */
392379
case SPI_IOC_RD_MODE:
@@ -510,7 +497,6 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
510497
break;
511498
}
512499

513-
mutex_unlock(&spidev->buf_lock);
514500
spi_dev_put(spi);
515501
mutex_unlock(&spidev->spi_lock);
516502
return retval;
@@ -541,9 +527,6 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd,
541527
return -ESHUTDOWN;
542528
}
543529

544-
/* SPI_IOC_MESSAGE needs the buffer locked "normally" */
545-
mutex_lock(&spidev->buf_lock);
546-
547530
/* Check message and copy into scratch area */
548531
ioc = spidev_get_ioc_message(cmd, u_ioc, &n_ioc);
549532
if (IS_ERR(ioc)) {
@@ -564,7 +547,6 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd,
564547
kfree(ioc);
565548

566549
done:
567-
mutex_unlock(&spidev->buf_lock);
568550
spi_dev_put(spi);
569551
mutex_unlock(&spidev->spi_lock);
570552
return retval;
@@ -802,7 +784,6 @@ static int spidev_probe(struct spi_device *spi)
802784
/* Initialize the driver data */
803785
spidev->spi = spi;
804786
mutex_init(&spidev->spi_lock);
805-
mutex_init(&spidev->buf_lock);
806787

807788
INIT_LIST_HEAD(&spidev->device_entry);
808789

0 commit comments

Comments
 (0)