ext4: defragmentation code cleanup
[firefly-linux-kernel-4.4.55.git] / fs / ext4 / move_extent.c
index 4e81d47aa8cb8af0553b93c1cb7dcbbea2d5d0a8..309ca899a7310f9b92402eedce6609867b18cb7b 100644 (file)
  */
 static inline int
 get_ext_path(struct inode *inode, ext4_lblk_t lblock,
-               struct ext4_ext_path **path)
+               struct ext4_ext_path **orig_path)
 {
        int ret = 0;
+       struct ext4_ext_path *path;
 
-       *path = ext4_ext_find_extent(inode, lblock, *path);
-       if (IS_ERR(*path)) {
-               ret = PTR_ERR(*path);
-               *path = NULL;
-       } else if ((*path)[ext_depth(inode)].p_ext == NULL)
+       path = ext4_ext_find_extent(inode, lblock, *orig_path);
+       if (IS_ERR(path))
+               ret = PTR_ERR(path);
+       else if (path[ext_depth(inode)].p_ext == NULL)
                ret = -ENODATA;
+       else
+               *orig_path = path;
 
        return ret;
 }
@@ -142,12 +144,13 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path,
 }
 
 /**
- * double_down_write_data_sem - Acquire two inodes' write lock of i_data_sem
+ * ext4_double_down_write_data_sem - Acquire two inodes' write lock
+ *                                   of i_data_sem
  *
  * Acquire write lock of i_data_sem of the two inodes
  */
-static void
-double_down_write_data_sem(struct inode *first, struct inode *second)
+void
+ext4_double_down_write_data_sem(struct inode *first, struct inode *second)
 {
        if (first < second) {
                down_write(&EXT4_I(first)->i_data_sem);
@@ -160,14 +163,15 @@ double_down_write_data_sem(struct inode *first, struct inode *second)
 }
 
 /**
- * double_up_write_data_sem - Release two inodes' write lock of i_data_sem
+ * ext4_double_up_write_data_sem - Release two inodes' write lock of i_data_sem
  *
  * @orig_inode:                original inode structure to be released its lock first
  * @donor_inode:       donor inode structure to be released its lock second
  * Release write lock of i_data_sem of two inodes (orig and donor).
  */
-static void
-double_up_write_data_sem(struct inode *orig_inode, struct inode *donor_inode)
+void
+ext4_double_up_write_data_sem(struct inode *orig_inode,
+                             struct inode *donor_inode)
 {
        up_write(&EXT4_I(orig_inode)->i_data_sem);
        up_write(&EXT4_I(donor_inode)->i_data_sem);
@@ -611,24 +615,25 @@ mext_check_coverage(struct inode *inode, ext4_lblk_t from, ext4_lblk_t count,
 {
        struct ext4_ext_path *path = NULL;
        struct ext4_extent *ext;
+       int ret = 0;
        ext4_lblk_t last = from + count;
        while (from < last) {
                *err = get_ext_path(inode, from, &path);
                if (*err)
-                       return 0;
+                       goto out;
                ext = path[ext_depth(inode)].p_ext;
-               if (!ext) {
-                       ext4_ext_drop_refs(path);
-                       return 0;
-               }
-               if (uninit != ext4_ext_is_uninitialized(ext)) {
-                       ext4_ext_drop_refs(path);
-                       return 0;
-               }
+               if (uninit != ext4_ext_is_uninitialized(ext))
+                       goto out;
                from += ext4_ext_get_actual_len(ext);
                ext4_ext_drop_refs(path);
        }
-       return 1;
+       ret = 1;
+out:
+       if (path) {
+               ext4_ext_drop_refs(path);
+               kfree(path);
+       }
+       return ret;
 }
 
 /**
@@ -666,6 +671,14 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode,
        int replaced_count = 0;
        int dext_alen;
 
+       *err = ext4_es_remove_extent(orig_inode, from, count);
+       if (*err)
+               goto out;
+
+       *err = ext4_es_remove_extent(donor_inode, from, count);
+       if (*err)
+               goto out;
+
        /* Get the original extent for the block "orig_off" */
        *err = get_ext_path(orig_inode, orig_off, &orig_path);
        if (*err)
@@ -726,6 +739,7 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode,
                donor_off += dext_alen;
                orig_off += dext_alen;
 
+               BUG_ON(replaced_count > count);
                /* Already moved the expected blocks */
                if (replaced_count >= count)
                        break;
@@ -803,7 +817,13 @@ mext_page_double_lock(struct inode *inode1, struct inode *inode2,
                page_cache_release(page[0]);
                return -ENOMEM;
        }
-
+       /*
+        * grab_cache_page_write_begin() may not wait on page's writeback if
+        * BDI not demand that. But it is reasonable to be very conservative
+        * here and explicitly wait on page's writeback
+        */
+       wait_on_page_writeback(page[0]);
+       wait_on_page_writeback(page[1]);
        if (inode1 > inode2) {
                struct page *tmp;
                tmp = page[0];
@@ -845,7 +865,6 @@ mext_page_mkuptodate(struct page *page, unsigned from, unsigned to)
                if (buffer_uptodate(bh))
                        continue;
                if (!buffer_mapped(bh)) {
-                       int err = 0;
                        err = ext4_get_block(inode, block, bh, 0);
                        if (err) {
                                SetPageError(page);
@@ -965,7 +984,7 @@ again:
         * necessary, just swap data blocks between orig and donor.
         */
        if (uninit) {
-               double_down_write_data_sem(orig_inode, donor_inode);
+               ext4_double_down_write_data_sem(orig_inode, donor_inode);
                /* If any of extents in range became initialized we have to
                 * fallback to data copying */
                uninit = mext_check_coverage(orig_inode, orig_blk_offset,
@@ -979,7 +998,7 @@ again:
                        goto drop_data_sem;
 
                if (!uninit) {
-                       double_up_write_data_sem(orig_inode, donor_inode);
+                       ext4_double_up_write_data_sem(orig_inode, donor_inode);
                        goto data_copy;
                }
                if ((page_has_private(pagep[0]) &&
@@ -993,7 +1012,7 @@ again:
                                                donor_inode, orig_blk_offset,
                                                block_len_in_page, err);
        drop_data_sem:
-               double_up_write_data_sem(orig_inode, donor_inode);
+               ext4_double_up_write_data_sem(orig_inode, donor_inode);
                goto unlock_pages;
        }
 data_copy:
@@ -1022,7 +1041,7 @@ data_copy:
        }
        /* Perform all necessary steps similar write_begin()/write_end()
         * but keeping in mind that i_size will not change */
-       *err = __block_write_begin(pagep[0], from, from + replaced_size,
+       *err = __block_write_begin(pagep[0], from, replaced_size,
                                   ext4_get_block);
        if (!*err)
                *err = block_commit_write(pagep[0], from, from + replaced_size);
@@ -1054,11 +1073,11 @@ repair_branches:
         * Extents are swapped already, but we are not able to copy data.
         * Try to swap extents to it's original places
         */
-       double_down_write_data_sem(orig_inode, donor_inode);
+       ext4_double_down_write_data_sem(orig_inode, donor_inode);
        replaced_count = mext_replace_branches(handle, donor_inode, orig_inode,
                                               orig_blk_offset,
                                               block_len_in_page, &err2);
-       double_up_write_data_sem(orig_inode, donor_inode);
+       ext4_double_up_write_data_sem(orig_inode, donor_inode);
        if (replaced_count != block_len_in_page) {
                EXT4_ERROR_INODE_BLOCK(orig_inode, (sector_t)(orig_blk_offset),
                                       "Unable to copy data block,"
@@ -1198,15 +1217,15 @@ mext_check_arguments(struct inode *orig_inode,
 }
 
 /**
- * mext_inode_double_lock - Lock i_mutex on both @inode1 and @inode2
+ * ext4_inode_double_lock - Lock i_mutex on both @inode1 and @inode2
  *
  * @inode1:    the inode structure
  * @inode2:    the inode structure
  *
  * Lock two inodes' i_mutex
  */
-static void
-mext_inode_double_lock(struct inode *inode1, struct inode *inode2)
+void
+ext4_inode_double_lock(struct inode *inode1, struct inode *inode2)
 {
        BUG_ON(inode1 == inode2);
        if (inode1 < inode2) {
@@ -1219,15 +1238,15 @@ mext_inode_double_lock(struct inode *inode1, struct inode *inode2)
 }
 
 /**
- * mext_inode_double_unlock - Release i_mutex on both @inode1 and @inode2
+ * ext4_inode_double_unlock - Release i_mutex on both @inode1 and @inode2
  *
  * @inode1:     the inode that is released first
  * @inode2:     the inode that is released second
  *
  */
 
-static void
-mext_inode_double_unlock(struct inode *inode1, struct inode *inode2)
+void
+ext4_inode_double_unlock(struct inode *inode1, struct inode *inode2)
 {
        mutex_unlock(&inode1->i_mutex);
        mutex_unlock(&inode2->i_mutex);
@@ -1322,7 +1341,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
                return -EINVAL;
        }
        /* Protect orig and donor inodes against a truncate */
-       mext_inode_double_lock(orig_inode, donor_inode);
+       ext4_inode_double_lock(orig_inode, donor_inode);
 
        /* Wait for all existing dio workers */
        ext4_inode_block_unlocked_dio(orig_inode);
@@ -1331,7 +1350,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
        inode_dio_wait(donor_inode);
 
        /* Protect extent tree against block allocations via delalloc */
-       double_down_write_data_sem(orig_inode, donor_inode);
+       ext4_double_down_write_data_sem(orig_inode, donor_inode);
        /* Check the filesystem environment whether move_extent can be done */
        ret = mext_check_arguments(orig_inode, donor_inode, orig_start,
                                    donor_start, &len);
@@ -1455,7 +1474,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
                 * b. racing with ->readpage, ->write_begin, and ext4_get_block
                 *    in move_extent_per_page
                 */
-               double_up_write_data_sem(orig_inode, donor_inode);
+               ext4_double_up_write_data_sem(orig_inode, donor_inode);
 
                while (orig_page_offset <= seq_end_page) {
 
@@ -1489,7 +1508,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
                                block_len_in_page = rest_blocks;
                }
 
-               double_down_write_data_sem(orig_inode, donor_inode);
+               ext4_double_down_write_data_sem(orig_inode, donor_inode);
                if (ret < 0)
                        break;
 
@@ -1527,10 +1546,10 @@ out:
                ext4_ext_drop_refs(holecheck_path);
                kfree(holecheck_path);
        }
-       double_up_write_data_sem(orig_inode, donor_inode);
+       ext4_double_up_write_data_sem(orig_inode, donor_inode);
        ext4_inode_resume_unlocked_dio(orig_inode);
        ext4_inode_resume_unlocked_dio(donor_inode);
-       mext_inode_double_unlock(orig_inode, donor_inode);
+       ext4_inode_double_unlock(orig_inode, donor_inode);
 
        return ret;
 }