Introduce a new mechanism in configfs to prevent the deletion of certain item/group. This is particularly useful in scenarios where userspace should not be allowed
to modify the configfs structure under some conditions, such as in VKMS.

Signed-off-by: Louis Chauvet <louis.chau...@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_configfs.c | 21 +++++++++++++++++++++
 fs/configfs/dir.c                    |  8 +++++++-
 include/linux/configfs.h             |  1 +
 3 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index 8a7d954399e9..0a196a28ed4a 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -393,9 +393,30 @@ static struct configfs_item_operations plane_item_operations = {
        .release        = &plane_release,
 };

+int allow_drop_plane_group(struct config_group *group, struct config_item *item)
+{
+       struct vkms_configfs_plane *plane;
+       bool enabled;
+
+       plane = plane_item_to_vkms_configfs_plane(item);
+
+       mutex_lock(&plane->dev->lock);
+       enabled = plane->dev->enabled;
+       mutex_unlock(&plane->dev->lock);
+
+       if (enabled)
+               return -EBUSY;
+       return 0;
+}
+
+static struct configfs_group_operations plane_group_operation ={
+       .allow_drop_item = &allow_drop_plane_group,
+};
+
 static const struct config_item_type plane_item_type = {
        .ct_attrs       = plane_item_attrs,
        .ct_item_ops    = &plane_item_operations,
+       .ct_group_ops   = &plane_group_operation,
        .ct_owner       = THIS_MODULE,
 };

diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 7d10278db30d..a103196af0f9 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -1544,7 +1544,13 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)

        /* Drop reference from above, item already holds one. */
        config_item_put(parent_item);
-
+ if (item->ci_type && item->ci_type->ct_group_ops && item->ci_type->ct_group_ops->allow_drop_item) { + ret = item->ci_type->ct_group_ops->allow_drop_item(to_config_group(parent_item), item);
+               if (ret) {
+                       config_item_put(item);
+                       return ret;
+               }
+       }
        if (item->ci_type)
                dead_item_owner = item->ci_type->ct_owner;

diff --git a/include/linux/configfs.h b/include/linux/configfs.h
index 7fc52a78d6cd..92933397590d 100644
--- a/include/linux/configfs.h
+++ b/include/linux/configfs.h
@@ -216,6 +216,7 @@ struct configfs_group_operations {
struct config_item *(*make_item)(struct config_group *group, const char *name); struct config_group *(*make_group)(struct config_group *group, const char *name); void (*disconnect_notify)(struct config_group *group, struct config_item *item); + int (*allow_drop_item)(struct config_group *group, struct config_item *item);
        void (*drop_item)(struct config_group *group, struct config_item *item);
bool (*is_visible)(struct config_item *item, struct configfs_attribute *attr, int n); bool (*is_bin_visible)(struct config_item *item, struct configfs_bin_attribute *attr,
--
2.48.1

Reply via email to