linux-user: Implement FS_IOC_FIEMAP ioctl
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> Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
This commit is contained in:
parent
d2ef05bb44
commit
285da2b9a8
@ -76,6 +76,10 @@
|
|||||||
#ifdef FIGETBSZ
|
#ifdef FIGETBSZ
|
||||||
IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG))
|
IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG))
|
||||||
#endif
|
#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(SIOCATMARK, 0, TYPE_NULL)
|
||||||
IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
|
IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
|
||||||
|
@ -83,6 +83,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
|
|||||||
#include <linux/kd.h>
|
#include <linux/kd.h>
|
||||||
#include <linux/mtio.h>
|
#include <linux/mtio.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
#include <linux/fiemap.h>
|
||||||
#include <linux/fb.h>
|
#include <linux/fb.h>
|
||||||
#include <linux/vt.h>
|
#include <linux/vt.h>
|
||||||
#include "linux_loop.h"
|
#include "linux_loop.h"
|
||||||
@ -2985,6 +2986,93 @@ struct IOCTLEntry {
|
|||||||
|
|
||||||
#define MAX_STRUCT_SIZE 4096
|
#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[] = {
|
static IOCTLEntry ioctl_entries[] = {
|
||||||
#define IOCTL(cmd, access, ...) \
|
#define IOCTL(cmd, access, ...) \
|
||||||
{ TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
|
{ TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
|
||||||
|
@ -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_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_FIBMAP TARGET_IO(0x00,1) /* bmap access */
|
||||||
#define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */
|
#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 */
|
/* cdrom commands */
|
||||||
#define TARGET_CDROMPAUSE 0x5301 /* Pause Audio Operation */
|
#define TARGET_CDROMPAUSE 0x5301 /* Pause Audio Operation */
|
||||||
|
@ -165,3 +165,19 @@ STRUCT(vt_stat,
|
|||||||
TYPE_SHORT, /* v_active */
|
TYPE_SHORT, /* v_active */
|
||||||
TYPE_SHORT, /* v_signal */
|
TYPE_SHORT, /* v_signal */
|
||||||
TYPE_SHORT) /* v_state */
|
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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user