vfs: vfs-level fiemap interface From: Eric Sandeen Basic vfs-level fiemap infrastructure, which sets up a new ->fiemap inode operation. Signed-off-by: Eric Sandeen --- (and I think also signed-off-by Andreas and/or Kalpak as well should also go here, since it's their work originally.) --- fs/ioctl.c | 30 ++++++++++++++++++++++++++++++ include/linux/fiemap.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fs.h | 3 +++ 3 files changed, 82 insertions(+) Index: linux-2.6.26-rc1/include/linux/fiemap.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.26-rc1/include/linux/fiemap.h 2008-05-05 17:10:22.000000000 -0700 @@ -0,0 +1,49 @@ +/* + * FIEMAP ioctl infrastructure. + * + * Copyright (C) 2007 Cluster File Systems, Inc + * + * Author: Kalpak Shah + * Andreas Dilger + */ + +#ifndef _LINUX_FIEMAP_H +#define _LINUX_FIEMAP_H + +struct fiemap_extent { + __u64 fe_offset; /* offset in bytes for the start of the extent */ + __u64 fe_length; /* length in bytes for the extent */ + __u32 fe_flags; /* returned FIEMAP_EXTENT_* flags for the extent */ + __u32 fe_lun; /* logical device number for extent (starting at 0)*/ +}; + +struct fiemap { + __u64 fm_start; /* logical starting byte offset (in/out) */ + __u64 fm_length; /* logical length of map (in/out) */ + __u32 fm_flags; /* FIEMAP_FLAG_* flags for request (in/out) */ + __u32 fm_extent_count; /* number of extents in fm_extents (in/out) */ + __u64 fm_end_offset; /* logical offset of end of mapping in last ioctl (out) */ + struct fiemap_extent fm_extents[0]; +}; + +#define FIEMAP_FLAG_SYNC 0x00000001 /* sync file data before map */ +#define FIEMAP_FLAG_HSM_READ 0x00000002 /* get data from HSM before map */ +#define FIEMAP_FLAG_NUM_EXTENTS 0x00000004 /* return only number of extents */ +#define FIEMAP_FLAG_INCOMPAT 0xff000000 /* error for unknown flags in here */ + +#define FIEMAP_FLAG_LUN_OFFSET 0x01000000 /* use lun offsets, instead of + * logical file offsets */ + +#define FIEMAP_EXTENT_HOLE 0x00000001 /* has no data or space allocation */ +#define FIEMAP_EXTENT_UNWRITTEN 0x00000002 /* space allocated, but no data */ +#define FIEMAP_EXTENT_UNKNOWN 0x00000004 /* in use, location unknown */ +#define FIEMAP_EXTENT_ERROR 0x00000008 /* mapping error, errno in fe_start*/ +#define FIEMAP_EXTENT_NO_DIRECT 0x00000010 /* cannot access data directly */ +#define FIEMAP_EXTENT_LAST 0x00000020 /* last extent in the file */ +#define FIEMAP_EXTENT_DELALLOC 0x00000040 /* has data but not yet written, + * must have EXTENT_UNKNOWN set */ +#define FIEMAP_EXTENT_SECONDARY 0x00000080 /* data (also) in secondary storage, + * not in primary if EXTENT_UNKNOWN*/ +#define FIEMAP_EXTENT_EOF 0x00000100 /* if fm_start+fm_len is beyond EOF*/ + +#endif /* _LINUX_FIEMAP_H */ Index: linux-2.6.26-rc1/include/linux/fs.h =================================================================== --- linux-2.6.26-rc1.orig/include/linux/fs.h 2008-05-05 17:10:08.000000000 -0700 +++ linux-2.6.26-rc1/include/linux/fs.h 2008-05-05 17:10:22.000000000 -0700 @@ -228,6 +228,7 @@ extern int dir_notify_enable; #define FS_IOC_SETFLAGS _IOW('f', 2, long) #define FS_IOC_GETVERSION _IOR('v', 1, long) #define FS_IOC_SETVERSION _IOW('v', 2, long) +#define FS_IOC_FIEMAP _IOWR('f', 10, struct fiemap) #define FS_IOC32_GETFLAGS _IOR('f', 1, int) #define FS_IOC32_SETFLAGS _IOW('f', 2, int) #define FS_IOC32_GETVERSION _IOR('v', 1, int) @@ -288,6 +289,7 @@ extern int dir_notify_enable; #include #include #include +#include #include #include @@ -1273,6 +1275,7 @@ struct inode_operations { void (*truncate_range)(struct inode *, loff_t, loff_t); long (*fallocate)(struct inode *inode, int mode, loff_t offset, loff_t len); + int (*fiemap) (struct inode *, unsigned long arg); }; struct seq_file; Index: linux-2.6.26-rc1/fs/ioctl.c =================================================================== --- linux-2.6.26-rc1.orig/fs/ioctl.c 2008-05-05 17:10:08.000000000 -0700 +++ linux-2.6.26-rc1/fs/ioctl.c 2008-05-05 17:10:22.000000000 -0700 @@ -71,6 +71,34 @@ static int ioctl_fibmap(struct file *fil return put_user(res, p); } +static int ioctl_fiemap(struct file *filp, unsigned long arg) +{ + struct fiemap fiemap_s; + struct inode *inode = filp->f_path.dentry->d_inode; + int error = 0; + + if (!inode->i_op->fiemap) + return -EOPNOTSUPP; + + if (copy_from_user(&fiemap_s, (struct fiemap __user *)arg, + sizeof(struct fiemap))) + return -EFAULT; + + /* Need arg sanity checking: + * start >= 0? Must be; unsigned. + * length > 0? (or is -1 valid?) + * extent count non-zero if not FLAG_NUM_EXTENTS + */ + + /* Should fs do this under a lock? */ + if (fiemap_s.fm_flags & FIEMAP_FLAG_SYNC) + filemap_write_and_wait(inode->i_mapping); + + error = inode->i_op->fiemap(inode, arg); + + return error; +} + static int file_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -80,6 +108,8 @@ static int file_ioctl(struct file *filp, switch (cmd) { case FIBMAP: return ioctl_fibmap(filp, p); + case FS_IOC_FIEMAP: + return ioctl_fiemap(filp, arg); case FIGETBSZ: return put_user(inode->i_sb->s_blocksize, p); case FIONREAD: