]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
gpio: virtuser: lock up configfs that an instantiated device depends on
authorKoichiro Den <koichiro.den@canonical.com>
Fri, 3 Jan 2025 14:18:28 +0000 (23:18 +0900)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Fri, 3 Jan 2025 16:15:04 +0000 (17:15 +0100)
Once a virtuser device is instantiated and actively used, allowing rmdir
for its configfs serves no purpose and can be confusing. Userspace
interacts with the virtual consumer at arbitrary times, meaning it
depends on its existence.

Make the subsystem itself depend on the configfs entry for a virtuser
device while it is in active use.

Signed-off-by: Koichiro Den <koichiro.den@canonical.com>
Link: https://lore.kernel.org/r/20250103141829.430662-4-koichiro.den@canonical.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
drivers/gpio/gpio-virtuser.c

index d6244f0d3bc75221a1ea4361a783243855e3dbb2..e89f299f214009484d6389e3e41a9fcc5a0ca3c4 100644 (file)
@@ -1546,6 +1546,30 @@ gpio_virtuser_device_deactivate(struct gpio_virtuser_device *dev)
        dev->pdev = NULL;
 }
 
+static void
+gpio_virtuser_device_lockup_configfs(struct gpio_virtuser_device *dev, bool lock)
+{
+       struct configfs_subsystem *subsys = dev->group.cg_subsys;
+       struct gpio_virtuser_lookup_entry *entry;
+       struct gpio_virtuser_lookup *lookup;
+
+       /*
+        * The device only needs to depend on leaf lookup entries. This is
+        * sufficient to lock up all the configfs entries that the
+        * instantiated, alive device depends on.
+        */
+       list_for_each_entry(lookup, &dev->lookup_list, siblings) {
+               list_for_each_entry(entry, &lookup->entry_list, siblings) {
+                       if (lock)
+                               WARN_ON(configfs_depend_item_unlocked(
+                                               subsys, &entry->group.cg_item));
+                       else
+                               configfs_undepend_item_unlocked(
+                                               &entry->group.cg_item);
+               }
+       }
+}
+
 static ssize_t
 gpio_virtuser_device_config_live_store(struct config_item *item,
                                       const char *page, size_t count)
@@ -1558,15 +1582,24 @@ gpio_virtuser_device_config_live_store(struct config_item *item,
        if (ret)
                return ret;
 
-       guard(mutex)(&dev->lock);
+       if (live)
+               gpio_virtuser_device_lockup_configfs(dev, true);
 
-       if (live == gpio_virtuser_device_is_live(dev))
-               return -EPERM;
+       scoped_guard(mutex, &dev->lock) {
+               if (live == gpio_virtuser_device_is_live(dev))
+                       ret = -EPERM;
+               else if (live)
+                       ret = gpio_virtuser_device_activate(dev);
+               else
+                       gpio_virtuser_device_deactivate(dev);
+       }
 
-       if (live)
-               ret = gpio_virtuser_device_activate(dev);
-       else
-               gpio_virtuser_device_deactivate(dev);
+       /*
+        * Undepend is required only if device disablement (live == 0)
+        * succeeds or if device enablement (live == 1) fails.
+        */
+       if (live == !!ret)
+               gpio_virtuser_device_lockup_configfs(dev, false);
 
        return ret ?: count;
 }