This allows creating a device-mapper device, opening it, and setting it
to be deleted when unused in a single atomic operation.

Signed-off-by: Demi Marie Obenour <d...@invisiblethingslab.com>
---
 drivers/md/dm-ioctl.c         | 67 +++++++++++++++++++++++++++++------
 include/uapi/linux/dm-ioctl.h | 16 ++++++++-
 2 files changed, 72 insertions(+), 11 deletions(-)

diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 
36fc6ae4737a05ab53ab67a8ccee525cb5fda082..05438dedcd17b7cac470fcc5a9721d67daad4bfb
 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -853,9 +853,21 @@ static void __dev_status(struct mapped_device *md, struct 
dm_ioctl *param)
 
 static int dev_create(struct file *filp, struct dm_ioctl *param, size_t 
param_size)
 {
-       int r, m = DM_ANY_MINOR;
+       int r, m = DM_ANY_MINOR, fd;
        struct mapped_device *md;
 
+       /* Do not allow unknown flags */
+       if (param->flags > (2 * DM_FILE_DESCRIPTOR_FLAG - 1))
+               return -EINVAL;
+
+       /*
+        * Do not allow creating a device that would just be destroyed
+        * before the ioctl returns.
+        */
+       if ((param->flags & DM_DEFERRED_REMOVE) &&
+           !(param->flags & DM_FILE_DESCRIPTOR_FLAG))
+               return -EINVAL;
+
        r = check_name(param->name);
        if (r)
                return r;
@@ -867,20 +879,55 @@ static int dev_create(struct file *filp, struct dm_ioctl 
*param, size_t param_si
        if (r)
                return r;
 
-       r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);
-       if (r) {
-               dm_put(md);
-               dm_destroy(md);
-               return r;
-       }
-
        param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
 
+       r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);
+       if (r)
+               goto out_put;
+
+       if (param->flags & DM_FILE_DESCRIPTOR_FLAG) {
+               struct block_device *bdev = dm_disk(md)->part0;
+               struct file *file;
+
+               fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC);
+               if (fd < 0) {
+                       r = fd;
+                       goto out_put;
+               }
+
+               file = blkdev_get_file(bdev, O_RDWR|O_CLOEXEC, NULL);
+               if (IS_ERR(file)) {
+                       r = PTR_ERR(file);
+                       goto out_put_fd;
+               }
+
+               /*
+                * Simulate opening the device.  The other checks in
+                * dm_blk_open() are not necessary becuase we have a reference
+                * to the `struct md`.
+                */
+               atomic_inc(&md->open_count);
+               fd_install(fd, file);
+               param->file_descriptor = fd;
+       }
+
+       /*
+        * If userspace requests it, automatically delete the device
+        * when it is no longer used
+        */
+       if (param->flags & DM_DEFERRED_REMOVE)
+               set_bit(DMF_DEFERRED_REMOVE, &md->flags);
+
        __dev_status(md, param);
-
        dm_put(md);
-
        return 0;
+
+out_put_fd:
+       put_unused_fd(fd);
+out_put:
+       dm_put(md);
+       dm_destroy(md);
+       return r;
 }
 
 /*
diff --git a/include/uapi/linux/dm-ioctl.h b/include/uapi/linux/dm-ioctl.h
index 
7edf335778bae1cb206f6dd4d44e9cf7fb9da35c..30a6260ed7e06ff71fad1675dd4e7f9325d752a6
 100644
--- a/include/uapi/linux/dm-ioctl.h
+++ b/include/uapi/linux/dm-ioctl.h
@@ -136,7 +136,13 @@ struct dm_ioctl {
         * For output, the ioctls return the event number, not the cookie.
         */
        __u32 event_nr;         /* in/out */
-       __u32 padding;
+
+       union {
+               /* Padding for named devices */
+               __u32 padding;
+               /* For anonymous devices, this is a file descriptor. */
+               __u32 file_descriptor;
+       };
 
        __u64 dev;              /* in/out */
 
@@ -382,4 +388,12 @@ enum {
  */
 #define DM_IMA_MEASUREMENT_FLAG        (1 << 19) /* In */
 
+/*
+ * If set in a DM_DEV_CREATE ioctl(), sets the file_descriptor field
+ * to a valid file descriptor.  This can be combined with DM_DEFERRED_REMOVE
+ * to cause the device to be destroyed when the file descriptor is closed
+ * and is otherwise unused.
+ */
+#define DM_FILE_DESCRIPTOR_FLAG                (1 << 20) /* In */
+
 #endif                         /* _LINUX_DM_IOCTL_H */
-- 
Sincerely,
Demi Marie Obenour (she/her/hers)
Invisible Things Lab

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel

Reply via email to