Btrfs: fix page cache memory leak
Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
committed by
David Woodhouse
parent
090d18753c
commit
35b7e47610
@@ -22,9 +22,7 @@ int set_radix_bit(struct radix_tree_root *radix, unsigned long bit)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
memset(bits + 1, 0, BIT_ARRAY_BYTES - sizeof(unsigned long));
|
memset(bits + 1, 0, BIT_ARRAY_BYTES - sizeof(unsigned long));
|
||||||
bits[0] = slot;
|
bits[0] = slot;
|
||||||
radix_tree_preload(GFP_NOFS);
|
|
||||||
ret = radix_tree_insert(radix, slot, bits);
|
ret = radix_tree_insert(radix, slot, bits);
|
||||||
radix_tree_preload_end();
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
struct btrfs_trans_handle;
|
struct btrfs_trans_handle;
|
||||||
struct btrfs_transaction;
|
struct btrfs_transaction;
|
||||||
|
extern struct kmem_cache *btrfs_trans_handle_cachep;
|
||||||
|
extern struct kmem_cache *btrfs_transaction_cachep;
|
||||||
|
extern struct kmem_cache *btrfs_bit_radix_cachep;
|
||||||
extern struct kmem_cache *btrfs_path_cachep;
|
extern struct kmem_cache *btrfs_path_cachep;
|
||||||
|
|
||||||
#define BTRFS_MAGIC "_BtRfS_M"
|
#define BTRFS_MAGIC "_BtRfS_M"
|
||||||
|
@@ -4,7 +4,8 @@
|
|||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
|
|
||||||
struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle *trans,
|
static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
|
||||||
|
*trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct btrfs_path *path,
|
struct btrfs_path *path,
|
||||||
struct btrfs_key *cpu_key,
|
struct btrfs_key *cpu_key,
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
#include <linux/swap.h>
|
#include <linux/swap.h>
|
||||||
#include <linux/radix-tree.h>
|
#include <linux/radix-tree.h>
|
||||||
#include <linux/file.h>
|
#include <linux/writeback.h>
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
@@ -694,7 +694,7 @@ static int free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int del_fs_roots(struct btrfs_fs_info *fs_info)
|
static int del_fs_roots(struct btrfs_fs_info *fs_info)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct btrfs_root *gang[8];
|
struct btrfs_root *gang[8];
|
||||||
@@ -781,3 +781,7 @@ void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf)
|
|||||||
brelse(buf);
|
brelse(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void btrfs_btree_balance_dirty(struct btrfs_root *root)
|
||||||
|
{
|
||||||
|
balance_dirty_pages_ratelimited(root->fs_info->btree_inode->i_mapping);
|
||||||
|
}
|
||||||
|
@@ -55,4 +55,6 @@ int btrfs_insert_dev_radix(struct btrfs_root *root,
|
|||||||
u64 num_blocks);
|
u64 num_blocks);
|
||||||
int btrfs_map_bh_to_logical(struct btrfs_root *root, struct buffer_head *bh,
|
int btrfs_map_bh_to_logical(struct btrfs_root *root, struct buffer_head *bh,
|
||||||
u64 logical);
|
u64 logical);
|
||||||
|
int btrfs_releasepage(struct page *page, gfp_t flags);
|
||||||
|
void btrfs_btree_balance_dirty(struct btrfs_root *root);
|
||||||
#endif
|
#endif
|
||||||
|
@@ -322,18 +322,10 @@ static int update_block_group(struct btrfs_trans_handle *trans,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int try_remove_page(struct address_space *mapping, unsigned long index)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
ret = invalidate_mapping_pages(mapping, index, index);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
|
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
|
||||||
btrfs_root *root)
|
btrfs_root *root)
|
||||||
{
|
{
|
||||||
unsigned long gang[8];
|
unsigned long gang[8];
|
||||||
struct inode *btree_inode = root->fs_info->btree_inode;
|
|
||||||
u64 first = 0;
|
u64 first = 0;
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
@@ -348,9 +340,6 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
|
|||||||
first = gang[0];
|
first = gang[0];
|
||||||
for (i = 0; i < ret; i++) {
|
for (i = 0; i < ret; i++) {
|
||||||
clear_radix_bit(pinned_radix, gang[i]);
|
clear_radix_bit(pinned_radix, gang[i]);
|
||||||
try_remove_page(btree_inode->i_mapping,
|
|
||||||
gang[i] << (PAGE_CACHE_SHIFT -
|
|
||||||
btree_inode->i_blkbits));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -983,6 +972,7 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
break;
|
break;
|
||||||
if (wret < 0)
|
if (wret < 0)
|
||||||
ret = wret;
|
ret = wret;
|
||||||
|
btrfs_btree_balance_dirty(root);
|
||||||
}
|
}
|
||||||
for (i = 0; i <= orig_level; i++) {
|
for (i = 0; i <= orig_level; i++) {
|
||||||
if (path->nodes[i]) {
|
if (path->nodes[i]) {
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include "hash.h"
|
||||||
#define DELTA 0x9E3779B9
|
#define DELTA 0x9E3779B9
|
||||||
|
|
||||||
static void TEA_transform(__u32 buf[2], __u32 const in[])
|
static void TEA_transform(__u32 buf[2], __u32 const in[])
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
|
#include "print-tree.h"
|
||||||
|
|
||||||
void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l)
|
void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l)
|
||||||
{
|
{
|
||||||
|
@@ -18,14 +18,14 @@
|
|||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "ioctl.h"
|
#include "ioctl.h"
|
||||||
|
|
||||||
void btrfs_fsinfo_release(struct kobject *obj)
|
static void btrfs_fsinfo_release(struct kobject *obj)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fsinfo = container_of(obj,
|
struct btrfs_fs_info *fsinfo = container_of(obj,
|
||||||
struct btrfs_fs_info, kobj);
|
struct btrfs_fs_info, kobj);
|
||||||
kfree(fsinfo);
|
kfree(fsinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct kobj_type btrfs_fsinfo_ktype = {
|
static struct kobj_type btrfs_fsinfo_ktype = {
|
||||||
.release = btrfs_fsinfo_release,
|
.release = btrfs_fsinfo_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -148,7 +148,6 @@ static void fill_inode_item(struct btrfs_inode_item *item,
|
|||||||
BTRFS_I(inode)->block_group->key.objectid);
|
BTRFS_I(inode)->block_group->key.objectid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int btrfs_update_inode(struct btrfs_trans_handle *trans,
|
static int btrfs_update_inode(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct inode *inode)
|
struct inode *inode)
|
||||||
@@ -251,6 +250,7 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
|
|||||||
ret = btrfs_unlink_trans(trans, root, dir, dentry);
|
ret = btrfs_unlink_trans(trans, root, dir, dentry);
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
mutex_unlock(&root->fs_info->fs_mutex);
|
mutex_unlock(&root->fs_info->fs_mutex);
|
||||||
|
btrfs_btree_balance_dirty(root);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,6 +324,7 @@ out:
|
|||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
mutex_unlock(&root->fs_info->fs_mutex);
|
mutex_unlock(&root->fs_info->fs_mutex);
|
||||||
ret = btrfs_end_transaction(trans, root);
|
ret = btrfs_end_transaction(trans, root);
|
||||||
|
btrfs_btree_balance_dirty(root);
|
||||||
if (ret && !err)
|
if (ret && !err)
|
||||||
err = ret;
|
err = ret;
|
||||||
return err;
|
return err;
|
||||||
@@ -449,6 +450,7 @@ static void btrfs_delete_inode(struct inode *inode)
|
|||||||
btrfs_free_inode(trans, root, inode);
|
btrfs_free_inode(trans, root, inode);
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
mutex_unlock(&root->fs_info->fs_mutex);
|
mutex_unlock(&root->fs_info->fs_mutex);
|
||||||
|
btrfs_btree_balance_dirty(root);
|
||||||
return;
|
return;
|
||||||
no_delete:
|
no_delete:
|
||||||
clear_inode(inode);
|
clear_inode(inode);
|
||||||
@@ -481,7 +483,7 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fixup_tree_root_location(struct btrfs_root *root,
|
static int fixup_tree_root_location(struct btrfs_root *root,
|
||||||
struct btrfs_key *location,
|
struct btrfs_key *location,
|
||||||
struct btrfs_root **sub_root)
|
struct btrfs_root **sub_root)
|
||||||
{
|
{
|
||||||
@@ -512,7 +514,7 @@ int fixup_tree_root_location(struct btrfs_root *root,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_init_locked_inode(struct inode *inode, void *p)
|
static int btrfs_init_locked_inode(struct inode *inode, void *p)
|
||||||
{
|
{
|
||||||
struct btrfs_iget_args *args = p;
|
struct btrfs_iget_args *args = p;
|
||||||
inode->i_ino = args->ino;
|
inode->i_ino = args->ino;
|
||||||
@@ -520,14 +522,14 @@ int btrfs_init_locked_inode(struct inode *inode, void *p)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_find_actor(struct inode *inode, void *opaque)
|
static int btrfs_find_actor(struct inode *inode, void *opaque)
|
||||||
{
|
{
|
||||||
struct btrfs_iget_args *args = opaque;
|
struct btrfs_iget_args *args = opaque;
|
||||||
return (args->ino == inode->i_ino &&
|
return (args->ino == inode->i_ino &&
|
||||||
args->root == BTRFS_I(inode)->root);
|
args->root == BTRFS_I(inode)->root);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid,
|
static struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid,
|
||||||
struct btrfs_root *root)
|
struct btrfs_root *root)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
@@ -790,6 +792,7 @@ static void btrfs_dirty_inode(struct inode *inode)
|
|||||||
btrfs_update_inode(trans, root, inode);
|
btrfs_update_inode(trans, root, inode);
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
mutex_unlock(&root->fs_info->fs_mutex);
|
mutex_unlock(&root->fs_info->fs_mutex);
|
||||||
|
btrfs_btree_balance_dirty(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
|
static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
|
||||||
@@ -913,6 +916,7 @@ out_unlock:
|
|||||||
inode_dec_link_count(inode);
|
inode_dec_link_count(inode);
|
||||||
iput(inode);
|
iput(inode);
|
||||||
}
|
}
|
||||||
|
btrfs_btree_balance_dirty(root);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1002,6 +1006,7 @@ out_unlock:
|
|||||||
mutex_unlock(&root->fs_info->fs_mutex);
|
mutex_unlock(&root->fs_info->fs_mutex);
|
||||||
if (drop_on_err)
|
if (drop_on_err)
|
||||||
iput(inode);
|
iput(inode);
|
||||||
|
btrfs_btree_balance_dirty(root);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1099,7 +1104,6 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock,
|
|||||||
found_type != BTRFS_EXTENT_DATA_KEY) {
|
found_type != BTRFS_EXTENT_DATA_KEY) {
|
||||||
extent_end = 0;
|
extent_end = 0;
|
||||||
extent_start = 0;
|
extent_start = 0;
|
||||||
btrfs_release_path(root, path);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
found_type = btrfs_file_extent_type(item);
|
found_type = btrfs_file_extent_type(item);
|
||||||
@@ -1135,7 +1139,6 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock,
|
|||||||
btrfs_map_bh_to_logical(root, result, 0);
|
btrfs_map_bh_to_logical(root, result, 0);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
btrfs_release_path(root, path);
|
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -1231,13 +1234,13 @@ static int __btrfs_write_full_page(struct inode *inode, struct page *page,
|
|||||||
} else if (!buffer_mapped(bh) && buffer_dirty(bh)) {
|
} else if (!buffer_mapped(bh) && buffer_dirty(bh)) {
|
||||||
WARN_ON(bh->b_size != blocksize);
|
WARN_ON(bh->b_size != blocksize);
|
||||||
err = btrfs_get_block(inode, block, bh, 0);
|
err = btrfs_get_block(inode, block, bh, 0);
|
||||||
if (err)
|
if (err) {
|
||||||
|
printk("writepage going to recovery err %d\n", err);
|
||||||
goto recover;
|
goto recover;
|
||||||
|
}
|
||||||
if (buffer_new(bh)) {
|
if (buffer_new(bh)) {
|
||||||
/* blockdev mappings never come here */
|
/* blockdev mappings never come here */
|
||||||
clear_buffer_new(bh);
|
clear_buffer_new(bh);
|
||||||
unmap_underlying_metadata(bh->b_bdev,
|
|
||||||
bh->b_blocknr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bh = bh->b_this_page;
|
bh = bh->b_this_page;
|
||||||
@@ -1303,11 +1306,6 @@ done:
|
|||||||
if (uptodate)
|
if (uptodate)
|
||||||
SetPageUptodate(page);
|
SetPageUptodate(page);
|
||||||
end_page_writeback(page);
|
end_page_writeback(page);
|
||||||
/*
|
|
||||||
* The page and buffer_heads can be released at any time from
|
|
||||||
* here on.
|
|
||||||
*/
|
|
||||||
wbc->pages_skipped++; /* We didn't write this page */
|
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -1409,10 +1407,11 @@ static void btrfs_truncate(struct inode *inode)
|
|||||||
btrfs_set_trans_block_group(trans, inode);
|
btrfs_set_trans_block_group(trans, inode);
|
||||||
ret = btrfs_truncate_in_trans(trans, root, inode);
|
ret = btrfs_truncate_in_trans(trans, root, inode);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
btrfs_update_inode(trans, root, inode);
|
||||||
ret = btrfs_end_transaction(trans, root);
|
ret = btrfs_end_transaction(trans, root);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
mutex_unlock(&root->fs_info->fs_mutex);
|
mutex_unlock(&root->fs_info->fs_mutex);
|
||||||
mark_inode_dirty(inode);
|
btrfs_btree_balance_dirty(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1777,10 +1776,15 @@ static int prepare_pages(struct btrfs_root *root,
|
|||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto failed_release;
|
goto failed_release;
|
||||||
}
|
}
|
||||||
|
cancel_dirty_page(pages[i], PAGE_CACHE_SIZE);
|
||||||
|
wait_on_page_writeback(pages[i]);
|
||||||
offset = pos & (PAGE_CACHE_SIZE -1);
|
offset = pos & (PAGE_CACHE_SIZE -1);
|
||||||
this_write = min(PAGE_CACHE_SIZE - offset, write_bytes);
|
this_write = min(PAGE_CACHE_SIZE - offset, write_bytes);
|
||||||
create_empty_buffers(pages[i], root->fs_info->sb->s_blocksize,
|
if (!page_has_buffers(pages[i])) {
|
||||||
|
create_empty_buffers(pages[i],
|
||||||
|
root->fs_info->sb->s_blocksize,
|
||||||
(1 << BH_Uptodate));
|
(1 << BH_Uptodate));
|
||||||
|
}
|
||||||
head = page_buffers(pages[i]);
|
head = page_buffers(pages[i]);
|
||||||
bh = head;
|
bh = head;
|
||||||
do {
|
do {
|
||||||
@@ -1820,7 +1824,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
|
|||||||
struct inode *inode = file->f_path.dentry->d_inode;
|
struct inode *inode = file->f_path.dentry->d_inode;
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct page *pages[8];
|
struct page *pages[8];
|
||||||
struct page *pinned[2] = { NULL, NULL };
|
struct page *pinned[2];
|
||||||
unsigned long first_index;
|
unsigned long first_index;
|
||||||
unsigned long last_index;
|
unsigned long last_index;
|
||||||
u64 start_pos;
|
u64 start_pos;
|
||||||
@@ -1829,6 +1833,8 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
|
|||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
struct btrfs_key ins;
|
struct btrfs_key ins;
|
||||||
|
|
||||||
|
pinned[0] = NULL;
|
||||||
|
pinned[1] = NULL;
|
||||||
if (file->f_flags & O_DIRECT)
|
if (file->f_flags & O_DIRECT)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
pos = *ppos;
|
pos = *ppos;
|
||||||
@@ -1858,6 +1864,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
|
|||||||
if (!PageUptodate(pinned[0])) {
|
if (!PageUptodate(pinned[0])) {
|
||||||
ret = mpage_readpage(pinned[0], btrfs_get_block);
|
ret = mpage_readpage(pinned[0], btrfs_get_block);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
wait_on_page_locked(pinned[0]);
|
||||||
} else {
|
} else {
|
||||||
unlock_page(pinned[0]);
|
unlock_page(pinned[0]);
|
||||||
}
|
}
|
||||||
@@ -1869,6 +1876,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
|
|||||||
if (!PageUptodate(pinned[1])) {
|
if (!PageUptodate(pinned[1])) {
|
||||||
ret = mpage_readpage(pinned[1], btrfs_get_block);
|
ret = mpage_readpage(pinned[1], btrfs_get_block);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
wait_on_page_locked(pinned[1]);
|
||||||
} else {
|
} else {
|
||||||
unlock_page(pinned[1]);
|
unlock_page(pinned[1]);
|
||||||
}
|
}
|
||||||
@@ -1940,6 +1948,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
|
|||||||
num_written += write_bytes;
|
num_written += write_bytes;
|
||||||
|
|
||||||
balance_dirty_pages_ratelimited(inode->i_mapping);
|
balance_dirty_pages_ratelimited(inode->i_mapping);
|
||||||
|
btrfs_btree_balance_dirty(root);
|
||||||
cond_resched();
|
cond_resched();
|
||||||
}
|
}
|
||||||
out_unlock:
|
out_unlock:
|
||||||
@@ -2165,6 +2174,7 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
|
|||||||
iput(inode);
|
iput(inode);
|
||||||
|
|
||||||
mutex_unlock(&root->fs_info->fs_mutex);
|
mutex_unlock(&root->fs_info->fs_mutex);
|
||||||
|
btrfs_btree_balance_dirty(root);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2220,6 +2230,7 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
|
|||||||
ret = btrfs_commit_transaction(trans, root);
|
ret = btrfs_commit_transaction(trans, root);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
mutex_unlock(&root->fs_info->fs_mutex);
|
mutex_unlock(&root->fs_info->fs_mutex);
|
||||||
|
btrfs_btree_balance_dirty(root);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2295,6 +2306,7 @@ out:
|
|||||||
mutex_unlock(&root->fs_info->fs_mutex);
|
mutex_unlock(&root->fs_info->fs_mutex);
|
||||||
out_nolock:
|
out_nolock:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
|
btrfs_btree_balance_dirty(root);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@@ -199,8 +199,9 @@ struct dirty_root {
|
|||||||
struct btrfs_root *root;
|
struct btrfs_root *root;
|
||||||
};
|
};
|
||||||
|
|
||||||
int add_dirty_roots(struct btrfs_trans_handle *trans,
|
static int add_dirty_roots(struct btrfs_trans_handle *trans,
|
||||||
struct radix_tree_root *radix, struct list_head *list)
|
struct radix_tree_root *radix,
|
||||||
|
struct list_head *list)
|
||||||
{
|
{
|
||||||
struct dirty_root *dirty;
|
struct dirty_root *dirty;
|
||||||
struct btrfs_root *gang[8];
|
struct btrfs_root *gang[8];
|
||||||
@@ -246,7 +247,8 @@ int add_dirty_roots(struct btrfs_trans_handle *trans,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int drop_dirty_roots(struct btrfs_root *tree_root, struct list_head *list)
|
static int drop_dirty_roots(struct btrfs_root *tree_root,
|
||||||
|
struct list_head *list)
|
||||||
{
|
{
|
||||||
struct dirty_root *dirty;
|
struct dirty_root *dirty;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
|
Reference in New Issue
Block a user