]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/btrfs/free-space-cache.c
Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux...
[karo-tx-linux.git] / fs / btrfs / free-space-cache.c
index 73f3de7a083c2aab0b48e0e0a53f61044dba794e..2b0a627cb5f94e414d3c9751f5e8e384e39c42f9 100644 (file)
@@ -274,18 +274,32 @@ struct io_ctl {
 };
 
 static int io_ctl_init(struct io_ctl *io_ctl, struct inode *inode,
-                      struct btrfs_root *root)
+                      struct btrfs_root *root, int write)
 {
+       int num_pages;
+       int check_crcs = 0;
+
+       num_pages = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
+                   PAGE_CACHE_SHIFT;
+
+       if (btrfs_ino(inode) != BTRFS_FREE_INO_OBJECTID)
+               check_crcs = 1;
+
+       /* Make sure we can fit our crcs into the first page */
+       if (write && check_crcs &&
+           (num_pages * sizeof(u32)) >= PAGE_CACHE_SIZE)
+               return -ENOSPC;
+
        memset(io_ctl, 0, sizeof(struct io_ctl));
-       io_ctl->num_pages = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
-               PAGE_CACHE_SHIFT;
-       io_ctl->pages = kzalloc(sizeof(struct page *) * io_ctl->num_pages,
-                               GFP_NOFS);
+
+       io_ctl->pages = kzalloc(sizeof(struct page *) * num_pages, GFP_NOFS);
        if (!io_ctl->pages)
                return -ENOMEM;
+
+       io_ctl->num_pages = num_pages;
        io_ctl->root = root;
-       if (btrfs_ino(inode) != BTRFS_FREE_INO_OBJECTID)
-               io_ctl->check_crcs = 1;
+       io_ctl->check_crcs = check_crcs;
+
        return 0;
 }
 
@@ -666,6 +680,13 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
        generation = btrfs_free_space_generation(leaf, header);
        btrfs_release_path(path);
 
+       if (!BTRFS_I(inode)->generation) {
+               btrfs_info(root->fs_info,
+                          "The free space cache file (%llu) is invalid. skip it\n",
+                          offset);
+               return 0;
+       }
+
        if (BTRFS_I(inode)->generation != generation) {
                btrfs_err(root->fs_info,
                        "free space inode generation (%llu) "
@@ -677,7 +698,7 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
        if (!num_entries)
                return 0;
 
-       ret = io_ctl_init(&io_ctl, inode, root);
+       ret = io_ctl_init(&io_ctl, inode, root, 0);
        if (ret)
                return ret;
 
@@ -831,7 +852,7 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
 
        if (!matched) {
                __btrfs_remove_free_space_cache(ctl);
-               btrfs_err(fs_info, "block group %llu has wrong amount of free space",
+               btrfs_warn(fs_info, "block group %llu has wrong amount of free space",
                        block_group->key.objectid);
                ret = -1;
        }
@@ -843,7 +864,7 @@ out:
                spin_unlock(&block_group->lock);
                ret = 0;
 
-               btrfs_err(fs_info, "failed to load free space cache for block group %llu",
+               btrfs_warn(fs_info, "failed to load free space cache for block group %llu, rebuild it now",
                        block_group->key.objectid);
        }
 
@@ -851,90 +872,44 @@ out:
        return ret;
 }
 
-/**
- * __btrfs_write_out_cache - write out cached info to an inode
- * @root - the root the inode belongs to
- * @ctl - the free space cache we are going to write out
- * @block_group - the block_group for this cache if it belongs to a block_group
- * @trans - the trans handle
- * @path - the path to use
- * @offset - the offset for the key we'll insert
- *
- * This function writes out a free space cache struct to disk for quick recovery
- * on mount.  This will return 0 if it was successfull in writing the cache out,
- * and -1 if it was not.
- */
-static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
-                                  struct btrfs_free_space_ctl *ctl,
-                                  struct btrfs_block_group_cache *block_group,
-                                  struct btrfs_trans_handle *trans,
-                                  struct btrfs_path *path, u64 offset)
+static noinline_for_stack
+int write_cache_extent_entries(struct io_ctl *io_ctl,
+                             struct btrfs_free_space_ctl *ctl,
+                             struct btrfs_block_group_cache *block_group,
+                             int *entries, int *bitmaps,
+                             struct list_head *bitmap_list)
 {
-       struct btrfs_free_space_header *header;
-       struct extent_buffer *leaf;
-       struct rb_node *node;
-       struct list_head *pos, *n;
-       struct extent_state *cached_state = NULL;
-       struct btrfs_free_cluster *cluster = NULL;
-       struct extent_io_tree *unpin = NULL;
-       struct io_ctl io_ctl;
-       struct list_head bitmap_list;
-       struct btrfs_key key;
-       u64 start, extent_start, extent_end, len;
-       int entries = 0;
-       int bitmaps = 0;
        int ret;
-       int err = -1;
-
-       INIT_LIST_HEAD(&bitmap_list);
-
-       if (!i_size_read(inode))
-               return -1;
-
-       ret = io_ctl_init(&io_ctl, inode, root);
-       if (ret)
-               return -1;
+       struct btrfs_free_cluster *cluster = NULL;
+       struct rb_node *node = rb_first(&ctl->free_space_offset);
 
        /* Get the cluster for this block_group if it exists */
-       if (block_group && !list_empty(&block_group->cluster_list))
+       if (block_group && !list_empty(&block_group->cluster_list)) {
                cluster = list_entry(block_group->cluster_list.next,
                                     struct btrfs_free_cluster,
                                     block_group_list);
+       }
 
-       /* Lock all pages first so we can lock the extent safely. */
-       io_ctl_prepare_pages(&io_ctl, inode, 0);
-
-       lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
-                        0, &cached_state);
-
-       node = rb_first(&ctl->free_space_offset);
        if (!node && cluster) {
                node = rb_first(&cluster->root);
                cluster = NULL;
        }
 
-       /* Make sure we can fit our crcs into the first page */
-       if (io_ctl.check_crcs &&
-           (io_ctl.num_pages * sizeof(u32)) >= PAGE_CACHE_SIZE)
-               goto out_nospc;
-
-       io_ctl_set_generation(&io_ctl, trans->transid);
-
        /* Write out the extent entries */
        while (node) {
                struct btrfs_free_space *e;
 
                e = rb_entry(node, struct btrfs_free_space, offset_index);
-               entries++;
+               *entries += 1;
 
-               ret = io_ctl_add_entry(&io_ctl, e->offset, e->bytes,
+               ret = io_ctl_add_entry(io_ctl, e->offset, e->bytes,
                                       e->bitmap);
                if (ret)
-                       goto out_nospc;
+                       goto fail;
 
                if (e->bitmap) {
-                       list_add_tail(&e->list, &bitmap_list);
-                       bitmaps++;
+                       list_add_tail(&e->list, bitmap_list);
+                       *bitmaps += 1;
                }
                node = rb_next(node);
                if (!node && cluster) {
@@ -942,136 +917,289 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
                        cluster = NULL;
                }
        }
+       return 0;
+fail:
+       return -ENOSPC;
+}
+
+static noinline_for_stack int
+update_cache_item(struct btrfs_trans_handle *trans,
+                 struct btrfs_root *root,
+                 struct inode *inode,
+                 struct btrfs_path *path, u64 offset,
+                 int entries, int bitmaps)
+{
+       struct btrfs_key key;
+       struct btrfs_free_space_header *header;
+       struct extent_buffer *leaf;
+       int ret;
+
+       key.objectid = BTRFS_FREE_SPACE_OBJECTID;
+       key.offset = offset;
+       key.type = 0;
+
+       ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
+       if (ret < 0) {
+               clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,
+                                EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL,
+                                GFP_NOFS);
+               goto fail;
+       }
+       leaf = path->nodes[0];
+       if (ret > 0) {
+               struct btrfs_key found_key;
+               ASSERT(path->slots[0]);
+               path->slots[0]--;
+               btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
+               if (found_key.objectid != BTRFS_FREE_SPACE_OBJECTID ||
+                   found_key.offset != offset) {
+                       clear_extent_bit(&BTRFS_I(inode)->io_tree, 0,
+                                        inode->i_size - 1,
+                                        EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0,
+                                        NULL, GFP_NOFS);
+                       btrfs_release_path(path);
+                       goto fail;
+               }
+       }
+
+       BTRFS_I(inode)->generation = trans->transid;
+       header = btrfs_item_ptr(leaf, path->slots[0],
+                               struct btrfs_free_space_header);
+       btrfs_set_free_space_entries(leaf, header, entries);
+       btrfs_set_free_space_bitmaps(leaf, header, bitmaps);
+       btrfs_set_free_space_generation(leaf, header, trans->transid);
+       btrfs_mark_buffer_dirty(leaf);
+       btrfs_release_path(path);
+
+       return 0;
+
+fail:
+       return -1;
+}
+
+static noinline_for_stack int
+write_pinned_extent_entries(struct btrfs_root *root,
+                           struct btrfs_block_group_cache *block_group,
+                           struct io_ctl *io_ctl,
+                           int *entries)
+{
+       u64 start, extent_start, extent_end, len;
+       struct extent_io_tree *unpin = NULL;
+       int ret;
+
+       if (!block_group)
+               return 0;
 
        /*
         * We want to add any pinned extents to our free space cache
         * so we don't leak the space
-        */
-
-       /*
+        *
         * We shouldn't have switched the pinned extents yet so this is the
         * right one
         */
        unpin = root->fs_info->pinned_extents;
 
-       if (block_group)
-               start = block_group->key.objectid;
+       start = block_group->key.objectid;
 
-       while (block_group && (start < block_group->key.objectid +
-                              block_group->key.offset)) {
+       while (start < block_group->key.objectid + block_group->key.offset) {
                ret = find_first_extent_bit(unpin, start,
                                            &extent_start, &extent_end,
                                            EXTENT_DIRTY, NULL);
-               if (ret) {
-                       ret = 0;
-                       break;
-               }
+               if (ret)
+                       return 0;
 
                /* This pinned extent is out of our range */
                if (extent_start >= block_group->key.objectid +
                    block_group->key.offset)
-                       break;
+                       return 0;
 
                extent_start = max(extent_start, start);
                extent_end = min(block_group->key.objectid +
                                 block_group->key.offset, extent_end + 1);
                len = extent_end - extent_start;
 
-               entries++;
-               ret = io_ctl_add_entry(&io_ctl, extent_start, len, NULL);
+               *entries += 1;
+               ret = io_ctl_add_entry(io_ctl, extent_start, len, NULL);
                if (ret)
-                       goto out_nospc;
+                       return -ENOSPC;
 
                start = extent_end;
        }
 
+       return 0;
+}
+
+static noinline_for_stack int
+write_bitmap_entries(struct io_ctl *io_ctl, struct list_head *bitmap_list)
+{
+       struct list_head *pos, *n;
+       int ret;
+
        /* Write out the bitmaps */
-       list_for_each_safe(pos, n, &bitmap_list) {
+       list_for_each_safe(pos, n, bitmap_list) {
                struct btrfs_free_space *entry =
                        list_entry(pos, struct btrfs_free_space, list);
 
-               ret = io_ctl_add_bitmap(&io_ctl, entry->bitmap);
+               ret = io_ctl_add_bitmap(io_ctl, entry->bitmap);
                if (ret)
-                       goto out_nospc;
+                       return -ENOSPC;
                list_del_init(&entry->list);
        }
 
-       /* Zero out the rest of the pages just to make sure */
-       io_ctl_zero_remaining_pages(&io_ctl);
-
-       ret = btrfs_dirty_pages(root, inode, io_ctl.pages, io_ctl.num_pages,
-                               0, i_size_read(inode), &cached_state);
-       io_ctl_drop_pages(&io_ctl);
-       unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0,
-                            i_size_read(inode) - 1, &cached_state, GFP_NOFS);
+       return 0;
+}
 
-       if (ret)
-               goto out;
+static int flush_dirty_cache(struct inode *inode)
+{
+       int ret;
 
        ret = btrfs_wait_ordered_range(inode, 0, (u64)-1);
-       if (ret) {
+       if (ret)
                clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,
                                 EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL,
                                 GFP_NOFS);
-               goto out;
-       }
 
-       key.objectid = BTRFS_FREE_SPACE_OBJECTID;
-       key.offset = offset;
-       key.type = 0;
+       return ret;
+}
 
-       ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
-       if (ret < 0) {
-               clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,
-                                EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL,
-                                GFP_NOFS);
-               goto out;
+static void noinline_for_stack
+cleanup_write_cache_enospc(struct inode *inode,
+                          struct io_ctl *io_ctl,
+                          struct extent_state **cached_state,
+                          struct list_head *bitmap_list)
+{
+       struct list_head *pos, *n;
+
+       list_for_each_safe(pos, n, bitmap_list) {
+               struct btrfs_free_space *entry =
+                       list_entry(pos, struct btrfs_free_space, list);
+               list_del_init(&entry->list);
        }
-       leaf = path->nodes[0];
-       if (ret > 0) {
-               struct btrfs_key found_key;
-               ASSERT(path->slots[0]);
-               path->slots[0]--;
-               btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
-               if (found_key.objectid != BTRFS_FREE_SPACE_OBJECTID ||
-                   found_key.offset != offset) {
-                       clear_extent_bit(&BTRFS_I(inode)->io_tree, 0,
-                                        inode->i_size - 1,
-                                        EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0,
-                                        NULL, GFP_NOFS);
-                       btrfs_release_path(path);
+       io_ctl_drop_pages(io_ctl);
+       unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0,
+                            i_size_read(inode) - 1, cached_state,
+                            GFP_NOFS);
+}
+
+/**
+ * __btrfs_write_out_cache - write out cached info to an inode
+ * @root - the root the inode belongs to
+ * @ctl - the free space cache we are going to write out
+ * @block_group - the block_group for this cache if it belongs to a block_group
+ * @trans - the trans handle
+ * @path - the path to use
+ * @offset - the offset for the key we'll insert
+ *
+ * This function writes out a free space cache struct to disk for quick recovery
+ * on mount.  This will return 0 if it was successfull in writing the cache out,
+ * and -1 if it was not.
+ */
+static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
+                                  struct btrfs_free_space_ctl *ctl,
+                                  struct btrfs_block_group_cache *block_group,
+                                  struct btrfs_trans_handle *trans,
+                                  struct btrfs_path *path, u64 offset)
+{
+       struct extent_state *cached_state = NULL;
+       struct io_ctl io_ctl;
+       LIST_HEAD(bitmap_list);
+       int entries = 0;
+       int bitmaps = 0;
+       int ret;
+
+       if (!i_size_read(inode))
+               return -1;
+
+       ret = io_ctl_init(&io_ctl, inode, root, 1);
+       if (ret)
+               return -1;
+
+       if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA)) {
+               down_write(&block_group->data_rwsem);
+               spin_lock(&block_group->lock);
+               if (block_group->delalloc_bytes) {
+                       block_group->disk_cache_state = BTRFS_DC_WRITTEN;
+                       spin_unlock(&block_group->lock);
+                       up_write(&block_group->data_rwsem);
+                       BTRFS_I(inode)->generation = 0;
+                       ret = 0;
                        goto out;
                }
+               spin_unlock(&block_group->lock);
        }
 
-       BTRFS_I(inode)->generation = trans->transid;
-       header = btrfs_item_ptr(leaf, path->slots[0],
-                               struct btrfs_free_space_header);
-       btrfs_set_free_space_entries(leaf, header, entries);
-       btrfs_set_free_space_bitmaps(leaf, header, bitmaps);
-       btrfs_set_free_space_generation(leaf, header, trans->transid);
-       btrfs_mark_buffer_dirty(leaf);
-       btrfs_release_path(path);
+       /* Lock all pages first so we can lock the extent safely. */
+       io_ctl_prepare_pages(&io_ctl, inode, 0);
+
+       lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
+                        0, &cached_state);
+
+       io_ctl_set_generation(&io_ctl, trans->transid);
+
+       /* Write out the extent entries in the free space cache */
+       ret = write_cache_extent_entries(&io_ctl, ctl,
+                                        block_group, &entries, &bitmaps,
+                                        &bitmap_list);
+       if (ret)
+               goto out_nospc;
+
+       /*
+        * Some spaces that are freed in the current transaction are pinned,
+        * they will be added into free space cache after the transaction is
+        * committed, we shouldn't lose them.
+        */
+       ret = write_pinned_extent_entries(root, block_group, &io_ctl, &entries);
+       if (ret)
+               goto out_nospc;
+
+       /* At last, we write out all the bitmaps. */
+       ret = write_bitmap_entries(&io_ctl, &bitmap_list);
+       if (ret)
+               goto out_nospc;
+
+       /* Zero out the rest of the pages just to make sure */
+       io_ctl_zero_remaining_pages(&io_ctl);
+
+       /* Everything is written out, now we dirty the pages in the file. */
+       ret = btrfs_dirty_pages(root, inode, io_ctl.pages, io_ctl.num_pages,
+                               0, i_size_read(inode), &cached_state);
+       if (ret)
+               goto out_nospc;
+
+       if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA))
+               up_write(&block_group->data_rwsem);
+       /*
+        * Release the pages and unlock the extent, we will flush
+        * them out later
+        */
+       io_ctl_drop_pages(&io_ctl);
+
+       unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0,
+                            i_size_read(inode) - 1, &cached_state, GFP_NOFS);
+
+       /* Flush the dirty pages in the cache file. */
+       ret = flush_dirty_cache(inode);
+       if (ret)
+               goto out;
 
-       err = 0;
+       /* Update the cache item to tell everyone this cache file is valid. */
+       ret = update_cache_item(trans, root, inode, path, offset,
+                               entries, bitmaps);
 out:
        io_ctl_free(&io_ctl);
-       if (err) {
+       if (ret) {
                invalidate_inode_pages2(inode->i_mapping);
                BTRFS_I(inode)->generation = 0;
        }
        btrfs_update_inode(trans, root, inode);
-       return err;
+       return ret;
 
 out_nospc:
-       list_for_each_safe(pos, n, &bitmap_list) {
-               struct btrfs_free_space *entry =
-                       list_entry(pos, struct btrfs_free_space, list);
-               list_del_init(&entry->list);
-       }
-       io_ctl_drop_pages(&io_ctl);
-       unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0,
-                            i_size_read(inode) - 1, &cached_state, GFP_NOFS);
+       cleanup_write_cache_enospc(inode, &io_ctl, &cached_state, &bitmap_list);
+
+       if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA))
+               up_write(&block_group->data_rwsem);
+
        goto out;
 }
 
@@ -1091,6 +1219,12 @@ int btrfs_write_out_cache(struct btrfs_root *root,
                spin_unlock(&block_group->lock);
                return 0;
        }
+
+       if (block_group->delalloc_bytes) {
+               block_group->disk_cache_state = BTRFS_DC_WRITTEN;
+               spin_unlock(&block_group->lock);
+               return 0;
+       }
        spin_unlock(&block_group->lock);
 
        inode = lookup_free_space_inode(root, block_group, path);