- Reserve the free blocks in the target area, not to be
  used by other process.

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-RESERVE_BLOCK/fs/ext4/extents.c 
Online-Defrag_linux-2.6.19-rc6-git-BLOCK_RELEASE/fs/ext4/extents.c
--- Online-Defrag_linux-2.6.19-rc6-git-RESERVE_BLOCK/fs/ext4/extents.c  
2007-06-19 21:40:55.000000000 +0900
+++ Online-Defrag_linux-2.6.19-rc6-git-BLOCK_RELEASE/fs/ext4/extents.c  
2007-06-19 20:19:14.000000000 +0900
@@ -2619,6 +2619,182 @@ out:
 }
 
 /**
+ * ext4_ext_defrag_reserve - reserve blocks for defrag
+ * @inode      target inode
+ * @goal       block reservation goal
+ * @len                blocks count to reserve
+ *
+ * This function returns 0 if succeeded, otherwise
+ * returns error value
+ */
+
+int ext4_ext_defrag_reserve(struct inode * inode, ext4_fsblk_t goal, int len)
+{
+       struct super_block *sb = NULL;
+       handle_t *handle = NULL;
+       struct buffer_head *bitmap_bh = NULL;
+       struct ext4_block_alloc_info *block_i;
+       struct ext4_reserve_window_node * my_rsv = NULL;
+       unsigned short windowsz = 0;
+       unsigned long group_no;
+       ext4_grpblk_t grp_target_blk;
+       int err = 0;
+
+       mutex_lock(&EXT4_I(inode)->truncate_mutex);
+
+       handle = ext4_journal_start(inode, EXT4_RESERVE_TRANS_BLOCKS);
+       if (IS_ERR(handle)) {
+               err = PTR_ERR(handle);
+               handle = NULL;
+               goto out;
+       }
+
+       if (S_ISREG(inode->i_mode) && (!EXT4_I(inode)->i_block_alloc_info)) {
+               ext4_init_block_alloc_info(inode);
+       } else if (!S_ISREG(inode->i_mode)) {
+               printk(KERN_ERR "ext4_ext_defrag_reserve:"
+                                " incorrect file type\n");
+               err = -1;
+               goto out;
+       }
+
+       sb = inode->i_sb;
+       if (!sb) {
+               printk("ext4_ext_defrag_reserve: nonexistent device\n");
+               err = -ENXIO;
+               goto out;
+       }
+       ext4_get_group_no_and_offset(sb, goal, &group_no,
+                               &grp_target_blk);
+
+       block_i = EXT4_I(inode)->i_block_alloc_info;
+
+       if (!block_i || ((windowsz =
+                       block_i->rsv_window_node.rsv_goal_size) == 0)) {
+               printk("ex4_ext_defrag_reserve: unable to reserve\n");
+               err = -1;
+               goto out;
+       }
+
+       my_rsv = &block_i->rsv_window_node;
+
+       bitmap_bh = read_block_bitmap(sb, group_no);
+       if (!bitmap_bh) {
+               err = -ENOSPC;
+               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;
+
+       err = alloc_new_reservation(my_rsv, grp_target_blk, sb,
+                                               group_no, bitmap_bh);
+       if (err < 0) {
+               printk(KERN_ERR "defrag: reservation faild\n");
+               ext4_discard_reservation(inode);
+               goto out;
+       } else {
+               if (len > EXT4_DEFAULT_RESERVE_BLOCKS) {
+                       try_to_extend_reservation(my_rsv, sb,
+                               len - EXT4_DEFAULT_RESERVE_BLOCKS);
+               }
+       }
+
+out:
+       mutex_unlock(&EXT4_I(inode)->truncate_mutex);
+       ext4_journal_release_buffer(handle, bitmap_bh);
+       brelse(bitmap_bh);
+
+       if (handle)
+               ext4_journal_stop(handle);
+
+       return err;
+}
+
+int goal_in_my_reservation(struct ext4_reserve_window *, ext4_grpblk_t,
+                       unsigned int, struct super_block *);
+int rsv_is_empty(struct ext4_reserve_window *);
+
+/**
+ * ext4_ext_block_within_rsv - Is target extent reserved ?
+ * @ inode       inode of target file
+ * @ ex_start    start physical block number of the extent
+ *               which already moved
+ * @ ex_len      block length of the extent which already moved
+ *
+ * This function returns 0 if succeeded, otherwise
+ * returns error value
+ */
+static int ext4_ext_block_within_rsv(struct inode *inode,
+                               ext4_fsblk_t ex_start, int ex_len)
+{
+       struct super_block *sb = inode->i_sb;
+       struct ext4_block_alloc_info *block_i;
+       unsigned long group_no;
+       ext4_grpblk_t grp_blk;
+       struct ext4_reserve_window_node *rsv;
+
+       block_i = EXT4_I(inode)->i_block_alloc_info;
+       if (block_i && block_i->rsv_window_node.rsv_goal_size > 0) {
+               rsv = &block_i->rsv_window_node;
+               if (rsv_is_empty(&rsv->rsv_window)) {
+                       printk("defrag: Can't defrag due to"
+                               " the empty reservation\n");
+                       return -1;
+               }
+       } else {
+               printk("defrag: No i_block_alloc_info\n");
+               return -1;
+       }
+
+       ext4_get_group_no_and_offset(sb, ex_start, &group_no, &grp_blk);
+
+       if (goal_in_my_reservation(&rsv->rsv_window, grp_blk, group_no, sb)
+           && goal_in_my_reservation(&rsv->rsv_window, grp_blk + ex_len -1,
+               group_no, sb))
+               return 0;
+       return -1;
+}
+
+/*
+ * ext4_ext_fblocks_reserve() -
+ *     reserve free blocks by ext4_ext_defrag_reserve()
+ * @inode:             To get a block group number
+ * @ext_info:          freeblocks distribution which stored extent-like style
+ *  @ext_info->ext[]    an array of struct ext4_extents_data
+ */
+int ext4_ext_fblocks_reserve(struct inode *inode,
+                       struct ext4_extents_info *ext_info)
+{
+       ext4_fsblk_t ex_start = 0;
+       int i;
+       int ret = 0;
+       int len = 0;
+
+       for (i = 0; i < ext_info->entries; i++) {
+               ex_start = ext_info->ext[i].start;
+               len = ext_info->ext[i].len;
+
+               ret = ext4_ext_defrag_reserve(inode, ex_start, len);
+               if (ret < 0)
+                       goto ERR;
+
+               ret = ext4_ext_block_within_rsv(inode, ex_start, len);
+               if (ret < 0)
+                       goto ERR;
+       }
+       return ret;
+
+ERR:
+       mutex_lock(&EXT4_I(inode)->truncate_mutex);
+       ext4_discard_reservation(inode);
+       mutex_unlock(&EXT4_I(inode)->truncate_mutex);
+       return ret;
+}
+
+/**
  * ext4_ext_defrag_victim - Create free space for defrag
  * @filp      target file
  * @ex_info   target extents array to move
@@ -2871,6 +3047,15 @@ int ext4_ext_ioctl(struct inode *inode, 
                                &ext_info, sizeof(ext_info)))
                                return -EFAULT;
                }
+       } else if (cmd == EXT4_IOC_RESERVE_BLOCK) {
+               struct ext4_extents_info ext_info;
+
+               if (copy_from_user(&ext_info,
+                               (struct ext4_extents_info __user *)arg,
+                               sizeof(ext_info)))
+                       return -EFAULT;
+
+               err = ext4_ext_fblocks_reserve(inode, &ext_info);
        } else if (cmd == EXT4_IOC_MOVE_VICTIM) {
                struct ext4_extents_info ext_info;
 
-
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to