2007-06-21 01:53:40

by Takashi Sato

[permalink] [raw]
Subject: [RFC][PATCH 4/10] Get free blocks distribution of the target block group

- Get free blocks distribution of the target block group to know
how many free blocks it has.

Signed-off-by: Takashi Sato <[email protected]>
Signed-off-by: Akira Fujita <[email protected]>
---
diff -X Online-Defrag_linux-2.6.19-rc6-git/Documentation/dontdiff -upNr Online-Defrag_linux-2.6.19-rc6-git-FREE_BLOCKS_INFO/fs/ext4/extents.c Online-Defrag_linux-2.6.19-rc6-git-EXTENTS_INFO/fs/ext4/extents.c
--- Online-Defrag_linux-2.6.19-rc6-git-FREE_BLOCKS_INFO/fs/ext4/extents.c 2007-06-20 09:05:37.000000000 +0900
+++ Online-Defrag_linux-2.6.19-rc6-git-EXTENTS_INFO/fs/ext4/extents.c 2007-06-20 08:50:57.000000000 +0900
@@ -2478,6 +2478,99 @@ ext4_ext_next_extent(struct inode *inode
return 1;
}

+/**
+ * ext4_ext_fblocks_distribution - Search free block distribution
+ * @filp target file
+ * @ex_info ext4_extents_info
+ *
+ * This function returns 0 if succeeded, otherwise
+ * returns error value
+ */
+static int ext4_ext_fblocks_distribution(struct inode *inode,
+ struct ext4_extents_info *ext_info)
+{
+ handle_t *handle;
+ struct buffer_head *bitmap_bh = NULL;
+ struct super_block *sb = inode->i_sb;
+ struct ext4_super_block *es;
+ unsigned long group_no;
+ int max_entries = ext_info->max_entries;
+ ext4_grpblk_t blocks_per_group;
+ ext4_grpblk_t start;
+ ext4_grpblk_t end;
+ int num = 0;
+ int len = 0;
+ int i = 0;
+ int err = 0;
+ int block_set = 0;
+ int start_block = 0;
+
+ if (!sb) {
+ printk("ext4_ext_fblock_distribution: nonexitent device\n");
+ return -ENOSPC;
+ }
+ es = EXT4_SB(sb)->s_es;
+
+ group_no = (inode->i_ino -1) / EXT4_INODES_PER_GROUP(sb);
+ start = ext_info->offset;
+ blocks_per_group = EXT4_BLOCKS_PER_GROUP(sb);
+ end = blocks_per_group -1;
+
+ handle = ext4_journal_start(inode, 1);
+ if (IS_ERR(handle)) {
+ err = PTR_ERR(handle);
+ return err;
+ }
+
+ bitmap_bh = read_block_bitmap(sb, group_no);
+ if (!bitmap_bh) {
+ err = -EIO;
+ goto out;
+ }
+
+ BUFFER_TRACE(bitmap_bh, "get undo access for new block");
+ err = ext4_journal_get_undo_access(handle, bitmap_bh);
+ if (err)
+ goto out;
+
+ for (i = start; i <= end ; i++) {
+ if (bitmap_search_next_usable_block(i, bitmap_bh, i+1) >= 0) {
+ len++;
+ /* if the free block is the first one in a region */
+ if (!block_set) {
+ start_block =
+ i + group_no * blocks_per_group;
+ block_set = 1;
+ }
+ } else if (len) {
+ ext_info->ext[num].start = start_block;
+ ext_info->ext[num].len = len;
+ num++;
+ len = 0;
+ block_set = 0;
+ if (num == max_entries) {
+ ext_info->offset = i + 1;
+ break;
+ }
+ }
+ if ((i == end) && len) {
+ ext_info->ext[num].start = start_block;
+ ext_info->ext[num].len = len;
+ num++;
+ }
+ }
+
+ ext_info->entries = num;
+out:
+ ext4_journal_release_buffer(handle, bitmap_bh);
+ brelse(bitmap_bh);
+
+ if (handle)
+ ext4_journal_stop(handle);
+
+ return err;
+}
+
int ext4_ext_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -2545,6 +2638,21 @@ int ext4_ext_ioctl(struct inode *inode,
if (copy_to_user((struct ext4_group_data_info *)arg,
&grp_data, sizeof(grp_data)))
return -EFAULT;
+ } else if (cmd == EXT4_IOC_FREE_BLOCKS_INFO) {
+ struct ext4_extents_info ext_info;
+
+ if (copy_from_user(&ext_info,
+ (struct ext4_extents_info __user *)arg,
+ sizeof(ext_info)))
+ return -EFAULT;
+
+ BUG_ON(ext_info.ino != inode->i_ino);
+
+ err = ext4_ext_fblocks_distribution(inode, &ext_info);
+
+ if (!err)
+ err = copy_to_user((struct ext4_extents_info*)arg,
+ &ext_info, sizeof(ext_info));
} else if (cmd == EXT4_IOC_DEFRAG) {
struct ext4_ext_defrag_data defrag;