From patchwork Sat Sep 27 07:27:02 2008 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Akira Fujita X-Patchwork-Id: 1764 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by ozlabs.org (Postfix) with ESMTP id 1500CDDDE3 for ; Sat, 27 Sep 2008 17:27:13 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751397AbYI0H1I (ORCPT ); Sat, 27 Sep 2008 03:27:08 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752005AbYI0H1I (ORCPT ); Sat, 27 Sep 2008 03:27:08 -0400 Received: from TYO202.gate.nec.co.jp ([202.32.8.206]:57358 "EHLO tyo202.gate.nec.co.jp" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751397AbYI0H1F (ORCPT ); Sat, 27 Sep 2008 03:27:05 -0400 Received: from mailgate3.nec.co.jp ([10.7.69.195]) by tyo202.gate.nec.co.jp (8.13.8/8.13.4) with ESMTP id m8R7R3k8004481; Sat, 27 Sep 2008 16:27:03 +0900 (JST) Received: (from root@localhost) by mailgate3.nec.co.jp (8.11.7/3.7W-MAILGATE-NEC) id m8R7R3A20418; Sat, 27 Sep 2008 16:27:03 +0900 (JST) Received: from matabe.jp.nec.com (matabe.jp.nec.com [10.26.220.20]) by mailsv.nec.co.jp (8.13.8/8.13.4) with ESMTP id m8R7R3Yv029330; Sat, 27 Sep 2008 16:27:03 +0900 (JST) Received: from [10.64.168.93] ([10.64.168.93] [10.64.168.93]) by mail.jp.nec.com with ESMTP; Sat, 27 Sep 2008 16:27:02 +0900 Message-ID: <48DDE046.6030206@rs.jp.nec.com> Date: Sat, 27 Sep 2008 16:27:02 +0900 From: Akira Fujita User-Agent: Thunderbird 2.0.0.14 (Windows/20080421) MIME-Version: 1.0 To: linux-ext4@vger.kernel.org CC: linux-fsdevel@vger.kernel.org Subject: [RFC][PATCH 8/12]ext4: Add the EXT4_IOC_FIEMAP_INO ioctl Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org ext4: online defrag -- Add the EXT4_IOC_FIEMAP_INO ioctl. From: Akira Fujita The EXT4_IOC_FIEMAP_INO is used to get extents information of inode which set to ioctl. The defragger uses this ioctl to check the fragment condition and to get extents information in the specified block group. This ioctl is brand new, the EXT4_IOC_EXTENTS_INFO ioctl used to do the same thing in the previous version. Signed-off-by: Akira Fujita Signed-off-by: Takashi Sato --- fs/ext4/defrag.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/ext4/ext4.h | 7 ++++ fs/ext4/extents.c | 2 +- fs/ext4/ioctl.c | 3 +- 4 files changed, 115 insertions(+), 2 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/fs/ext4/defrag.c b/fs/ext4/defrag.c index 941414b..f7c99de 100644 --- a/fs/ext4/defrag.c +++ b/fs/ext4/defrag.c @@ -20,6 +20,8 @@ #include "ext4_extents.h" #include "group.h" +#define FIEMAP_MAX_EXTENTS (UINT_MAX / sizeof(struct fiemap_extent)) + /** * ext4_defrag_next_extent - Search for the next extent and set it to "extent" * @@ -91,6 +93,106 @@ err: } /** + * ext4_defrag_fiemap_ino - Get extents information by inode number + * + * @filp: pointer to file + * @arg: pointer to fiemap_ino + * @fiemap_ino->ino: an inode number which is used to get + * extent information + * @fiemap_ino->fiemap: request for fiemap ioctl + * + * This function returns 0 if succeed, otherwise returns error value. + */ +static int +ext4_defrag_fiemap_ino(struct file *filp, unsigned long arg) +{ + struct fiemap_ino fiemap_ino; + struct fiemap_extent_info fieinfo = { 0, }; + struct inode *inode; + struct super_block *sb = filp->f_dentry->d_inode->i_sb; + u64 len = 0; + int err = 0; + + if (copy_from_user(&fiemap_ino, (struct fiemap_ino __user *)arg, + sizeof(struct fiemap_ino))) + return -EFAULT; + + /* Special inodes shouldn't be choiced */ + if (fiemap_ino.ino < EXT4_GOOD_OLD_FIRST_INO) + return -ENOENT; + + inode = ext4_iget(sb, fiemap_ino.ino); + if (IS_ERR(inode)) + return PTR_ERR(inode); + + /* Return -ENOENT if a file does not exist */ + if (!inode->i_nlink || !S_ISREG(inode->i_mode)) { + err = -ENOENT; + goto out; + } + + if (!inode->i_op->fiemap) { + err = -EOPNOTSUPP; + goto out; + } + + if (fiemap_ino.fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS) { + err = -EINVAL; + goto out; + } + + if (fiemap_ino.fiemap.fm_length == 0) { + err = -EINVAL; + goto out; + } + + if (fiemap_ino.fiemap.fm_start > sb->s_maxbytes) { + err = -EFBIG; + goto out; + } + + /* + * Check offset and length + * If the specified range exceeds the max file size, + * adjust the length. + */ + if ((fiemap_ino.fiemap.fm_length > sb->s_maxbytes) || + (sb->s_maxbytes - fiemap_ino.fiemap.fm_length) + < fiemap_ino.fiemap.fm_start) + len = sb->s_maxbytes - fiemap_ino.fiemap.fm_start; + else + len = fiemap_ino.fiemap.fm_length; + + fieinfo.fi_flags = fiemap_ino.fiemap.fm_flags; + fieinfo.fi_extents_max = fiemap_ino.fiemap.fm_extent_count; + fieinfo.fi_extents_start = + (struct fiemap_extent *)(arg + sizeof(fiemap_ino)); + + if (fiemap_ino.fiemap.fm_extent_count != 0 && + !access_ok(VERIFY_WRITE, fieinfo.fi_extents_start, + fieinfo.fi_extents_max * sizeof(struct fiemap_extent))) { + err = -EFAULT; + goto out; + } + + if (fieinfo.fi_flags & FIEMAP_FLAG_SYNC) + filemap_write_and_wait(inode->i_mapping); + + err = inode->i_op->fiemap(inode, &fieinfo, + fiemap_ino.fiemap.fm_start, len); + if (!err) { + fiemap_ino.fiemap.fm_flags = fieinfo.fi_flags; + fiemap_ino.fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped; + if (copy_to_user((char *)arg, &fiemap_ino, sizeof(fiemap_ino))) + err = -EFAULT; + } + +out: + iput(inode); + return err; +} + +/** * ext4_defrag_fblocks_distribution - Search free blocks distribution * * @org_inode: original inode @@ -237,6 +339,9 @@ int ext4_defrag_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, err = copy_to_user( (struct ext4_extents_info __user *)arg, &ext_info, sizeof(ext_info)); + } else if (cmd == EXT4_IOC_FIEMAP_INO) { + + err = ext4_defrag_fiemap_ino(filp, arg); } else if (cmd == EXT4_IOC_DEFRAG) { struct ext4_ext_defrag_data defrag; struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es; diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index ffe687b..8d008c8 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -306,6 +306,7 @@ struct ext4_new_group_data { #define EXT4_IOC_FIBMAP _IOW('f', 16, ext4_fsblk_t) #define EXT4_IOC_GROUP_INFO _IOW('f', 17, struct ext4_group_data_info) #define EXT4_IOC_FREE_BLOCKS_INFO _IOW('f', 18, struct ext4_extents_info) +#define EXT4_IOC_FIEMAP_INO _IOW('f', 19, struct fiemap_ino) /* * ioctl commands in 32 bit emulation @@ -358,6 +359,11 @@ struct ext4_extents_info { struct ext4_extent_data ext[DEFRAG_MAX_ENT]; }; +struct fiemap_ino { + __u64 ino; + struct fiemap fiemap; +}; + #define EXT4_TRANS_META_BLOCKS 4 /* bitmap + group desc + sb + inode */ /* @@ -1321,6 +1327,7 @@ extern int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block, unsigned long max_blocks, struct buffer_head *bh, int create, int extend_disksize, int flag); +extern int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start); #endif /* __KERNEL__ */ #endif /* _EXT4_H */ diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 6e2ccb8..7fcf72d 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2110,7 +2110,7 @@ ext4_ext_more_to_rm(struct ext4_ext_path *path) return 1; } -static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start) +int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start) { struct super_block *sb = inode->i_sb; int depth = ext_depth(inode); diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 40bc2e1..a0e4915 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -259,7 +259,8 @@ setversion_out: case EXT4_IOC_FIBMAP: case EXT4_IOC_DEFRAG: case EXT4_IOC_GROUP_INFO: - case EXT4_IOC_FREE_BLOCKS_INFO: { + case EXT4_IOC_FREE_BLOCKS_INFO: + case EXT4_IOC_FIEMAP_INO: { return ext4_defrag_ioctl(inode, filp, cmd, arg); } case EXT4_IOC_GROUP_ADD: {