diff -rupN linux-2.6.18-164.6.1_1/fs/ext3/ioctl.c linux-2.6.18-164.6.1_2/fs/ext3/ioctl.c --- linux-2.6.18-164.6.1_1/fs/ext3/ioctl.c 2009-12-22 12:37:55.000000000 +0530 +++ linux-2.6.18-164.6.1_2/fs/ext3/ioctl.c 2009-12-22 12:40:44.000000000 +0530 @@ -16,6 +16,70 @@ #include #include +/* So that the fiemap access checks can't overflow on 32 bit machines. */ +#define FIEMAP_MAX_EXTENTS (UINT_MAX / sizeof(struct fiemap_extent)) + +static int fiemap_check_ranges(struct super_block *sb, + u64 start, u64 len, u64 *new_len) +{ + *new_len = len; + + if (len == 0) + return -EINVAL; + + if (start > sb->s_maxbytes) + return -EFBIG; + + /* + * Shrink request scope to what the fs can actually handle. + */ + if ((len > sb->s_maxbytes) || + (sb->s_maxbytes - len) < start) + *new_len = sb->s_maxbytes - start; + + return 0; +} + +int ioctl_fiemap(struct inode *inode, struct file *filp, unsigned long arg) +{ + struct fiemap fiemap; + u64 len; + struct fiemap_extent_info fieinfo = {0, }; + struct super_block *sb = inode->i_sb; + int error = 0; + + if (copy_from_user(&fiemap, (struct fiemap __user *) arg, + sizeof(struct fiemap))) + return -EFAULT; + + if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS) + return -EINVAL; + + error = fiemap_check_ranges(sb, fiemap.fm_start, fiemap.fm_length, + &len); + if (error) + return error; + + fieinfo.fi_flags = fiemap.fm_flags; + fieinfo.fi_extents_max = fiemap.fm_extent_count; + fieinfo.fi_extents_start = (struct fiemap_extent *)(arg + sizeof(fiemap)); + + if (fiemap.fm_extent_count != 0 && + !access_ok(VERIFY_WRITE, (void *)arg, + offsetof(typeof(fiemap), fm_extents[fiemap.fm_extent_count]))) + return -EFAULT; + + if (fieinfo.fi_flags & FIEMAP_FLAG_SYNC) + filemap_write_and_wait(inode->i_mapping); + + error = ext3_fiemap(inode, &fieinfo, fiemap.fm_start, len); + fiemap.fm_flags = fieinfo.fi_flags; + fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped; + if (copy_to_user((char *)arg, &fiemap, sizeof(fiemap))) + error = -EFAULT; + + return error; +} int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) @@ -276,7 +340,9 @@ flags_err: return err; } - + case EXT3_IOC_FIEMAP: { + return ioctl_fiemap(inode, filp, arg); + } default: return -ENOTTY; diff -rupN linux-2.6.18-164.6.1_1/include/linux/ext3_fs.h linux-2.6.18-164.6.1_2/include/linux/ext3_fs.h --- linux-2.6.18-164.6.1_1/include/linux/ext3_fs.h 2009-12-22 12:37:55.000000000 +0530 +++ linux-2.6.18-164.6.1_2/include/linux/ext3_fs.h 2009-12-22 12:43:02.000000000 +0530 @@ -260,6 +260,7 @@ struct ext3_new_group_data { #define EXT3_IOC_SETVERSION _IOW('f', 4, long) #define EXT3_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) #define EXT3_IOC_GROUP_ADD _IOW('f', 8,struct ext3_new_group_input) +#define EXT3_IOC_FIEMAP _IOWR('f', 11, struct fiemap) #define EXT3_IOC_GETVERSION_OLD _IOR('v', 1, long) #define EXT3_IOC_SETVERSION_OLD _IOW('v', 2, long) #ifdef CONFIG_JBD_DEBUG