Skip to content

Commit

Permalink
spi: Fix spi device unregister flow
Browse files Browse the repository at this point in the history
[ Upstream commit c7299fe ]

When an SPI device is unregistered, the spi->controller->cleanup() is
called in the device's release callback. That's wrong for a couple of
reasons:

1. spi_dev_put() can be called before spi_add_device() is called. And
   it's spi_add_device() that calls spi_setup(). This will cause clean()
   to get called without the spi device ever being setup.

2. There's no guarantee that the controller's driver would be present by
   the time the spi device's release function gets called.

3. It also causes "sleeping in atomic context" stack dump[1] when device
   link deletion code does a put_device() on the spi device.

Fix these issues by simply moving the cleanup from the device release
callback to the actual spi_unregister_device() function.

[1] - https://lore.kernel.org/lkml/CAHp75Vc=FCGcUyS0v6fnxme2YJ+qD+Y-hQDQLa2JhWNON9VmsQ@mail.gmail.com/

Signed-off-by: Saravana Kannan <saravanak@google.com>
Link: https://lore.kernel.org/r/20210426235638.1285530-1-saravanak@google.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Saravana Kannan authored and gregkh committed Jun 16, 2021
1 parent cb24d57 commit 4b8b7bc
Showing 1 changed file with 12 additions and 6 deletions.
18 changes: 12 additions & 6 deletions drivers/spi/spi.c
Expand Up @@ -47,10 +47,6 @@ static void spidev_release(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);

/* spi controllers may cleanup for released devices */
if (spi->controller->cleanup)
spi->controller->cleanup(spi);

spi_controller_put(spi->controller);
kfree(spi->driver_override);
kfree(spi);
Expand Down Expand Up @@ -550,6 +546,12 @@ static int spi_dev_check(struct device *dev, void *data)
return 0;
}

static void spi_cleanup(struct spi_device *spi)
{
if (spi->controller->cleanup)
spi->controller->cleanup(spi);
}

/**
* spi_add_device - Add spi_device allocated with spi_alloc_device
* @spi: spi_device to register
Expand Down Expand Up @@ -614,11 +616,13 @@ int spi_add_device(struct spi_device *spi)

/* Device may be bound to an active driver when this returns */
status = device_add(&spi->dev);
if (status < 0)
if (status < 0) {
dev_err(dev, "can't add %s, status %d\n",
dev_name(&spi->dev), status);
else
spi_cleanup(spi);
} else {
dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
}

done:
mutex_unlock(&spi_add_lock);
Expand Down Expand Up @@ -705,6 +709,8 @@ void spi_unregister_device(struct spi_device *spi)
if (!spi)
return;

spi_cleanup(spi);

if (spi->dev.of_node) {
of_node_clear_flag(spi->dev.of_node, OF_POPULATED);
of_node_put(spi->dev.of_node);
Expand Down

0 comments on commit 4b8b7bc

Please sign in to comment.