qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/2] linux-user: implement FS_IOC_FIEMAP ioctl
@ 2011-01-06 15:04 Peter Maydell
  2011-01-06 15:04 ` [Qemu-devel] [PATCH 1/2] linux-user: Support ioctls whose parameter size is not constant Peter Maydell
  2011-01-06 15:04 ` [Qemu-devel] [PATCH 2/2] linux-user: Implement FS_IOC_FIEMAP ioctl Peter Maydell
  0 siblings, 2 replies; 3+ messages in thread
From: Peter Maydell @ 2011-01-06 15:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio

This patchset implements support for the Linux FS_IOC_FIEMAP ioctl.
This is used by apt (or possibly one of the programs it runs) when
it is installing packages. The major effect of this fix is that qemu
no longer spits out warnings about the ioctl being unimplemented when
you use it to install new packages into an Ubuntu ARM chroot.

Peter Maydell (2):
  linux-user: Support ioctls whose parameter size is not constant
  linux-user: Implement FS_IOC_FIEMAP ioctl

 linux-user/ioctls.h        |    4 ++
 linux-user/syscall.c       |  106 ++++++++++++++++++++++++++++++++++++++++++-
 linux-user/syscall_defs.h  |    1 +
 linux-user/syscall_types.h |   16 +++++++
 4 files changed, 124 insertions(+), 3 deletions(-)

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [Qemu-devel] [PATCH 1/2] linux-user: Support ioctls whose parameter size is not constant
  2011-01-06 15:04 [Qemu-devel] [PATCH 0/2] linux-user: implement FS_IOC_FIEMAP ioctl Peter Maydell
@ 2011-01-06 15:04 ` Peter Maydell
  2011-01-06 15:04 ` [Qemu-devel] [PATCH 2/2] linux-user: Implement FS_IOC_FIEMAP ioctl Peter Maydell
  1 sibling, 0 replies; 3+ messages in thread
From: Peter Maydell @ 2011-01-06 15:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio

Some ioctls (for example FS_IOC_FIEMAP) use structures whose size is
not constant. The generic argument conversion code in do_ioctl()
cannot handle this, so add support for implementing a special-case
handler for a particular ioctl which does the conversion itself.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 linux-user/syscall.c |   18 +++++++++++++++---
 1 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c3e8706..7436c3f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2965,13 +2965,19 @@ enum {
 #undef STRUCT
 #undef STRUCT_SPECIAL
 
-typedef struct IOCTLEntry {
+typedef struct IOCTLEntry IOCTLEntry;
+
+typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
+                             int fd, abi_long cmd, abi_long arg);
+
+struct IOCTLEntry {
     unsigned int target_cmd;
     unsigned int host_cmd;
     const char *name;
     int access;
+    do_ioctl_fn *do_ioctl;
     const argtype arg_type[5];
-} IOCTLEntry;
+};
 
 #define IOC_R 0x0001
 #define IOC_W 0x0002
@@ -2981,7 +2987,9 @@ typedef struct IOCTLEntry {
 
 static IOCTLEntry ioctl_entries[] = {
 #define IOCTL(cmd, access, ...) \
-    { TARGET_ ## cmd, cmd, #cmd, access, {  __VA_ARGS__ } },
+    { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
+#define IOCTL_SPECIAL(cmd, access, dofn, ...)                      \
+    { TARGET_ ## cmd, cmd, #cmd, access, dofn, {  __VA_ARGS__ } },
 #include "ioctls.h"
     { 0, 0, },
 };
@@ -3011,6 +3019,10 @@ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
 #if defined(DEBUG)
     gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
 #endif
+    if (ie->do_ioctl) {
+        return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
+    }
+
     switch(arg_type[0]) {
     case TYPE_NULL:
         /* no argument */
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [Qemu-devel] [PATCH 2/2] linux-user: Implement FS_IOC_FIEMAP ioctl
  2011-01-06 15:04 [Qemu-devel] [PATCH 0/2] linux-user: implement FS_IOC_FIEMAP ioctl Peter Maydell
  2011-01-06 15:04 ` [Qemu-devel] [PATCH 1/2] linux-user: Support ioctls whose parameter size is not constant Peter Maydell
@ 2011-01-06 15:04 ` Peter Maydell
  1 sibling, 0 replies; 3+ messages in thread
From: Peter Maydell @ 2011-01-06 15:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: Riku Voipio

Implement the FS_IOC_FIEMAP ioctl using the new support for
custom handling of ioctls; this is needed because the struct
that is passed includes a variable-length array.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 linux-user/ioctls.h        |    4 ++
 linux-user/syscall.c       |   88 ++++++++++++++++++++++++++++++++++++++++++++
 linux-user/syscall_defs.h  |    1 +
 linux-user/syscall_types.h |   16 ++++++++
 4 files changed, 109 insertions(+), 0 deletions(-)

diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 769e1bc..538e257 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -76,6 +76,10 @@
 #ifdef FIGETBSZ
      IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG))
 #endif
+#ifdef FS_IOC_FIEMAP
+     IOCTL_SPECIAL(FS_IOC_FIEMAP, IOC_W | IOC_R, do_ioctl_fs_ioc_fiemap,
+                   MK_PTR(MK_STRUCT(STRUCT_fiemap)))
+#endif
 
   IOCTL(SIOCATMARK, 0, TYPE_NULL)
   IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 7436c3f..488bf02 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -83,6 +83,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 #include <linux/kd.h>
 #include <linux/mtio.h>
 #include <linux/fs.h>
+#include <linux/fiemap.h>
 #include <linux/fb.h>
 #include <linux/vt.h>
 #include "linux_loop.h"
@@ -2985,6 +2986,93 @@ struct IOCTLEntry {
 
 #define MAX_STRUCT_SIZE 4096
 
+/* So fiemap access checks don't overflow on 32 bit systems.
+ * This is very slightly smaller than the limit imposed by
+ * the underlying kernel.
+ */
+#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap))  \
+                            / sizeof(struct fiemap_extent))
+
+static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
+                                       int fd, abi_long cmd, abi_long arg)
+{
+    /* The parameter for this ioctl is a struct fiemap followed
+     * by an array of struct fiemap_extent whose size is set
+     * in fiemap->fm_extent_count. The array is filled in by the
+     * ioctl.
+     */
+    int target_size_in, target_size_out;
+    struct fiemap *fm;
+    const argtype *arg_type = ie->arg_type;
+    const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
+    void *argptr, *p;
+    abi_long ret;
+    int i, extent_size = thunk_type_size(extent_arg_type, 0);
+    uint32_t outbufsz;
+    int free_fm = 0;
+
+    assert(arg_type[0] == TYPE_PTR);
+    assert(ie->access == IOC_RW);
+    arg_type++;
+    target_size_in = thunk_type_size(arg_type, 0);
+    argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
+    if (!argptr) {
+        return -TARGET_EFAULT;
+    }
+    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+    unlock_user(argptr, arg, 0);
+    fm = (struct fiemap *)buf_temp;
+    if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
+        return -TARGET_EINVAL;
+    }
+
+    outbufsz = sizeof (*fm) +
+        (sizeof(struct fiemap_extent) * fm->fm_extent_count);
+
+    if (outbufsz > MAX_STRUCT_SIZE) {
+        /* We can't fit all the extents into the fixed size buffer.
+         * Allocate one that is large enough and use it instead.
+         */
+        fm = malloc(outbufsz);
+        if (!fm) {
+            return -TARGET_ENOMEM;
+        }
+        memcpy(fm, buf_temp, sizeof(struct fiemap));
+        free_fm = 1;
+    }
+    ret = get_errno(ioctl(fd, ie->host_cmd, fm));
+    if (!is_error(ret)) {
+        target_size_out = target_size_in;
+        /* An extent_count of 0 means we were only counting the extents
+         * so there are no structs to copy
+         */
+        if (fm->fm_extent_count != 0) {
+            target_size_out += fm->fm_mapped_extents * extent_size;
+        }
+        argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
+        if (!argptr) {
+            ret = -TARGET_EFAULT;
+        } else {
+            /* Convert the struct fiemap */
+            thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
+            if (fm->fm_extent_count != 0) {
+                p = argptr + target_size_in;
+                /* ...and then all the struct fiemap_extents */
+                for (i = 0; i < fm->fm_mapped_extents; i++) {
+                    thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
+                                  THUNK_TARGET);
+                    p += extent_size;
+                }
+            }
+            unlock_user(argptr, arg, target_size_out);
+        }
+    }
+    if (free_fm) {
+        free(fm);
+    }
+    return ret;
+}
+
 static IOCTLEntry ioctl_entries[] = {
 #define IOCTL(cmd, access, ...) \
     { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 20c93d0..d02a9bf 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -783,6 +783,7 @@ struct target_pollfd {
 #define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */
 #define TARGET_FIBMAP     TARGET_IO(0x00,1)  /* bmap access */
 #define TARGET_FIGETBSZ   TARGET_IO(0x00,2)  /* get the block size used for bmap */
+#define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap)
 
 /* cdrom commands */
 #define TARGET_CDROMPAUSE		0x5301 /* Pause Audio Operation */
diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
index 340dbd3..0e67cd8 100644
--- a/linux-user/syscall_types.h
+++ b/linux-user/syscall_types.h
@@ -165,3 +165,19 @@ STRUCT(vt_stat,
        TYPE_SHORT, /* v_active */
        TYPE_SHORT, /* v_signal */
        TYPE_SHORT) /* v_state */
+
+STRUCT(fiemap_extent,
+       TYPE_ULONGLONG, /* fe_logical */
+       TYPE_ULONGLONG, /* fe_physical */
+       TYPE_ULONGLONG, /* fe_length */
+       MK_ARRAY(TYPE_ULONGLONG, 2), /* fe_reserved64[2] */
+       TYPE_INT, /* fe_flags */
+       MK_ARRAY(TYPE_INT, 3)) /* fe_reserved[3] */
+
+STRUCT(fiemap,
+       TYPE_ULONGLONG, /* fm_start */
+       TYPE_ULONGLONG, /* fm_length */
+       TYPE_INT, /* fm_flags */
+       TYPE_INT, /* fm_mapped_extents */
+       TYPE_INT, /* fm_extent_count */
+       TYPE_INT) /* fm_reserved */
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2011-01-06 15:22 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-01-06 15:04 [Qemu-devel] [PATCH 0/2] linux-user: implement FS_IOC_FIEMAP ioctl Peter Maydell
2011-01-06 15:04 ` [Qemu-devel] [PATCH 1/2] linux-user: Support ioctls whose parameter size is not constant Peter Maydell
2011-01-06 15:04 ` [Qemu-devel] [PATCH 2/2] linux-user: Implement FS_IOC_FIEMAP ioctl Peter Maydell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).