[PATCH] dm: support ioctls on mapped devices
authorMilan Broz <mbroz@redhat.com>
Tue, 3 Oct 2006 08:15:15 +0000 (01:15 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Tue, 3 Oct 2006 15:04:13 +0000 (08:04 -0700)
Extend the core device-mapper infrastructure to accept arbitrary ioctls on a
mapped device provided that it has exactly one target and it is capable of
supporting ioctls.

[We can't use unlocked_ioctl because we need 'inode': 'file' might be NULL.
Is it worth changing this?]

Signed-off-by: Milan Broz <mbroz@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Arnd Bergmann <arnd@arndb.de> wrote:

> Am Wednesday 21 June 2006 21:31 schrieb Alasdair G Kergon:
> > static struct block_device_operations dm_blk_dops = {
> > .open = dm_blk_open,
> > .release = dm_blk_close,
> > +.ioctl = dm_blk_ioctl,
> > .getgeo = dm_blk_getgeo,
> > .owner = THIS_MODULE
>
> I guess this also needs a ->compat_ioctl method, otherwise it won't
> work for ioctl numbers that have a compat_ioctl implementation in the
> low-level device driver.

Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/md/dm.c
include/linux/device-mapper.h
include/linux/dm-ioctl.h

index c99bf9f..5792686 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/idr.h>
 #include <linux/hdreg.h>
 #include <linux/blktrace_api.h>
+#include <linux/smp_lock.h>
 
 #define DM_MSG_PREFIX "core"
 
@@ -288,6 +289,45 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return dm_get_geometry(md, geo);
 }
 
+static int dm_blk_ioctl(struct inode *inode, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+{
+       struct mapped_device *md;
+       struct dm_table *map;
+       struct dm_target *tgt;
+       int r = -ENOTTY;
+
+       /* We don't really need this lock, but we do need 'inode'. */
+       unlock_kernel();
+
+       md = inode->i_bdev->bd_disk->private_data;
+
+       map = dm_get_table(md);
+
+       if (!map || !dm_table_get_size(map))
+               goto out;
+
+       /* We only support devices that have a single target */
+       if (dm_table_get_num_targets(map) != 1)
+               goto out;
+
+       tgt = dm_table_get_target(map, 0);
+
+       if (dm_suspended(md)) {
+               r = -EAGAIN;
+               goto out;
+       }
+
+       if (tgt->type->ioctl)
+               r = tgt->type->ioctl(tgt, inode, file, cmd, arg);
+
+out:
+       dm_table_put(map);
+
+       lock_kernel();
+       return r;
+}
+
 static inline struct dm_io *alloc_io(struct mapped_device *md)
 {
        return mempool_alloc(md->io_pool, GFP_NOIO);
@@ -1377,6 +1417,7 @@ int dm_suspended(struct mapped_device *md)
 static struct block_device_operations dm_blk_dops = {
        .open = dm_blk_open,
        .release = dm_blk_close,
+       .ioctl = dm_blk_ioctl,
        .getgeo = dm_blk_getgeo,
        .owner = THIS_MODULE
 };
index e3d1c33..d44a996 100644 (file)
@@ -64,6 +64,10 @@ typedef int (*dm_status_fn) (struct dm_target *ti, status_type_t status_type,
 
 typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv);
 
+typedef int (*dm_ioctl_fn) (struct dm_target *ti, struct inode *inode,
+                           struct file *filp, unsigned int cmd,
+                           unsigned long arg);
+
 void dm_error(const char *message);
 
 /*
@@ -91,6 +95,7 @@ struct target_type {
        dm_resume_fn resume;
        dm_status_fn status;
        dm_message_fn message;
+       dm_ioctl_fn ioctl;
 };
 
 struct io_restrictions {
index 9623bb6..b349b76 100644 (file)
@@ -285,7 +285,7 @@ typedef char ioctl_struct[308];
 #define DM_DEV_SET_GEOMETRY    _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR       4
-#define DM_VERSION_MINOR       7
+#define DM_VERSION_MINOR       8
 #define DM_VERSION_PATCHLEVEL  0
 #define DM_VERSION_EXTRA       "-ioctl (2006-06-24)"