Merge branch 'delayed_inode' into inode_numbers
Conflicts: fs/btrfs/inode.c fs/btrfs/ioctl.c fs/btrfs/transaction.c Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
commit
dcc6d07322
@ -7,4 +7,4 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
|
||||
extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
|
||||
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
|
||||
export.o tree-log.o acl.o free-space-cache.o zlib.o lzo.o \
|
||||
compression.o delayed-ref.o relocation.o
|
||||
compression.o delayed-ref.o relocation.o delayed-inode.o
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "extent_map.h"
|
||||
#include "extent_io.h"
|
||||
#include "ordered-data.h"
|
||||
#include "delayed-inode.h"
|
||||
|
||||
/* in memory btrfs inode */
|
||||
struct btrfs_inode {
|
||||
@ -158,9 +159,13 @@ struct btrfs_inode {
|
||||
*/
|
||||
unsigned force_compress:4;
|
||||
|
||||
struct btrfs_delayed_node *delayed_node;
|
||||
|
||||
struct inode vfs_inode;
|
||||
};
|
||||
|
||||
extern unsigned char btrfs_filetype_table[];
|
||||
|
||||
static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
|
||||
{
|
||||
return container_of(inode, struct btrfs_inode, vfs_inode);
|
||||
|
@ -38,11 +38,6 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
|
||||
struct extent_buffer *src_buf);
|
||||
static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_path *path, int level, int slot);
|
||||
static int setup_items_for_insert(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_path *path,
|
||||
struct btrfs_key *cpu_key, u32 *data_size,
|
||||
u32 total_data, u32 total_size, int nr);
|
||||
|
||||
|
||||
struct btrfs_path *btrfs_alloc_path(void)
|
||||
{
|
||||
@ -3559,11 +3554,10 @@ out:
|
||||
* to save stack depth by doing the bulk of the work in a function
|
||||
* that doesn't call btrfs_search_slot
|
||||
*/
|
||||
static noinline_for_stack int
|
||||
setup_items_for_insert(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_path *path,
|
||||
struct btrfs_key *cpu_key, u32 *data_size,
|
||||
u32 total_data, u32 total_size, int nr)
|
||||
int setup_items_for_insert(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_path *path,
|
||||
struct btrfs_key *cpu_key, u32 *data_size,
|
||||
u32 total_data, u32 total_size, int nr)
|
||||
{
|
||||
struct btrfs_item *item;
|
||||
int i;
|
||||
|
@ -870,6 +870,7 @@ struct btrfs_block_group_cache {
|
||||
struct reloc_control;
|
||||
struct btrfs_device;
|
||||
struct btrfs_fs_devices;
|
||||
struct btrfs_delayed_root;
|
||||
struct btrfs_fs_info {
|
||||
u8 fsid[BTRFS_FSID_SIZE];
|
||||
u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
|
||||
@ -896,7 +897,10 @@ struct btrfs_fs_info {
|
||||
/* logical->physical extent mapping */
|
||||
struct btrfs_mapping_tree mapping_tree;
|
||||
|
||||
/* block reservation for extent, checksum and root tree */
|
||||
/*
|
||||
* block reservation for extent, checksum, root tree and
|
||||
* delayed dir index item
|
||||
*/
|
||||
struct btrfs_block_rsv global_block_rsv;
|
||||
/* block reservation for delay allocation */
|
||||
struct btrfs_block_rsv delalloc_block_rsv;
|
||||
@ -1023,6 +1027,7 @@ struct btrfs_fs_info {
|
||||
* for the sys_munmap function call path
|
||||
*/
|
||||
struct btrfs_workers fixup_workers;
|
||||
struct btrfs_workers delayed_workers;
|
||||
struct task_struct *transaction_kthread;
|
||||
struct task_struct *cleaner_kthread;
|
||||
int thread_pool_size;
|
||||
@ -1080,6 +1085,8 @@ struct btrfs_fs_info {
|
||||
|
||||
/* filesystem state */
|
||||
u64 fs_state;
|
||||
|
||||
struct btrfs_delayed_root *delayed_root;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1172,6 +1179,11 @@ struct btrfs_root {
|
||||
/* red-black tree that keeps track of in-memory inodes */
|
||||
struct rb_root inode_tree;
|
||||
|
||||
/*
|
||||
* radix tree that keeps track of delayed nodes of every inode,
|
||||
* protected by inode_lock
|
||||
*/
|
||||
struct radix_tree_root delayed_nodes_tree;
|
||||
/*
|
||||
* right now this just gets used so that a root has its own devid
|
||||
* for stat. It may be used for more later
|
||||
@ -2110,6 +2122,13 @@ static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info)
|
||||
}
|
||||
|
||||
/* extent-tree.c */
|
||||
static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root,
|
||||
int num_items)
|
||||
{
|
||||
return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
|
||||
3 * num_items;
|
||||
}
|
||||
|
||||
void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
|
||||
int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, unsigned long count);
|
||||
@ -2305,6 +2324,8 @@ void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p);
|
||||
struct btrfs_path *btrfs_alloc_path(void);
|
||||
void btrfs_free_path(struct btrfs_path *p);
|
||||
void btrfs_set_path_blocking(struct btrfs_path *p);
|
||||
void btrfs_clear_path_blocking(struct btrfs_path *p,
|
||||
struct extent_buffer *held);
|
||||
void btrfs_unlock_up_safe(struct btrfs_path *p, int level);
|
||||
|
||||
int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
@ -2316,6 +2337,10 @@ static inline int btrfs_del_item(struct btrfs_trans_handle *trans,
|
||||
return btrfs_del_items(trans, root, path, path->slots[0], 1);
|
||||
}
|
||||
|
||||
int setup_items_for_insert(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_path *path,
|
||||
struct btrfs_key *cpu_key, u32 *data_size,
|
||||
u32 total_data, u32 total_size, int nr);
|
||||
int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_key *key, void *data, u32 data_size);
|
||||
int btrfs_insert_some_items(struct btrfs_trans_handle *trans,
|
||||
@ -2379,7 +2404,7 @@ void btrfs_check_and_init_root_item(struct btrfs_root_item *item);
|
||||
/* dir-item.c */
|
||||
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, const char *name,
|
||||
int name_len, u64 dir,
|
||||
int name_len, struct inode *dir,
|
||||
struct btrfs_key *location, u8 type, u64 index);
|
||||
struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
|
1694
fs/btrfs/delayed-inode.c
Normal file
1694
fs/btrfs/delayed-inode.c
Normal file
File diff suppressed because it is too large
Load Diff
141
fs/btrfs/delayed-inode.h
Normal file
141
fs/btrfs/delayed-inode.h
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Fujitsu. All rights reserved.
|
||||
* Written by Miao Xie <miaox@cn.fujitsu.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License v2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 021110-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __DELAYED_TREE_OPERATION_H
|
||||
#define __DELAYED_TREE_OPERATION_H
|
||||
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/wait.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "ctree.h"
|
||||
|
||||
/* types of the delayed item */
|
||||
#define BTRFS_DELAYED_INSERTION_ITEM 1
|
||||
#define BTRFS_DELAYED_DELETION_ITEM 2
|
||||
|
||||
struct btrfs_delayed_root {
|
||||
spinlock_t lock;
|
||||
struct list_head node_list;
|
||||
/*
|
||||
* Used for delayed nodes which is waiting to be dealt with by the
|
||||
* worker. If the delayed node is inserted into the work queue, we
|
||||
* drop it from this list.
|
||||
*/
|
||||
struct list_head prepare_list;
|
||||
atomic_t items; /* for delayed items */
|
||||
int nodes; /* for delayed nodes */
|
||||
wait_queue_head_t wait;
|
||||
};
|
||||
|
||||
struct btrfs_delayed_node {
|
||||
u64 inode_id;
|
||||
u64 bytes_reserved;
|
||||
struct btrfs_root *root;
|
||||
/* Used to add the node into the delayed root's node list. */
|
||||
struct list_head n_list;
|
||||
/*
|
||||
* Used to add the node into the prepare list, the nodes in this list
|
||||
* is waiting to be dealt with by the async worker.
|
||||
*/
|
||||
struct list_head p_list;
|
||||
struct rb_root ins_root;
|
||||
struct rb_root del_root;
|
||||
struct mutex mutex;
|
||||
struct btrfs_inode_item inode_item;
|
||||
atomic_t refs;
|
||||
u64 index_cnt;
|
||||
bool in_list;
|
||||
bool inode_dirty;
|
||||
int count;
|
||||
};
|
||||
|
||||
struct btrfs_delayed_item {
|
||||
struct rb_node rb_node;
|
||||
struct btrfs_key key;
|
||||
struct list_head tree_list; /* used for batch insert/delete items */
|
||||
struct list_head readdir_list; /* used for readdir items */
|
||||
u64 bytes_reserved;
|
||||
struct btrfs_block_rsv *block_rsv;
|
||||
struct btrfs_delayed_node *delayed_node;
|
||||
atomic_t refs;
|
||||
int ins_or_del;
|
||||
u32 data_len;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
static inline void btrfs_init_delayed_root(
|
||||
struct btrfs_delayed_root *delayed_root)
|
||||
{
|
||||
atomic_set(&delayed_root->items, 0);
|
||||
delayed_root->nodes = 0;
|
||||
spin_lock_init(&delayed_root->lock);
|
||||
init_waitqueue_head(&delayed_root->wait);
|
||||
INIT_LIST_HEAD(&delayed_root->node_list);
|
||||
INIT_LIST_HEAD(&delayed_root->prepare_list);
|
||||
}
|
||||
|
||||
int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, const char *name,
|
||||
int name_len, struct inode *dir,
|
||||
struct btrfs_disk_key *disk_key, u8 type,
|
||||
u64 index);
|
||||
|
||||
int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct inode *dir,
|
||||
u64 index);
|
||||
|
||||
int btrfs_inode_delayed_dir_index_count(struct inode *inode);
|
||||
|
||||
int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
|
||||
void btrfs_balance_delayed_items(struct btrfs_root *root);
|
||||
|
||||
int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
|
||||
struct inode *inode);
|
||||
/* Used for evicting the inode. */
|
||||
void btrfs_remove_delayed_node(struct inode *inode);
|
||||
void btrfs_kill_delayed_inode_items(struct inode *inode);
|
||||
|
||||
|
||||
int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct inode *inode);
|
||||
|
||||
/* Used for drop dead root */
|
||||
void btrfs_kill_all_delayed_nodes(struct btrfs_root *root);
|
||||
|
||||
/* Used for readdir() */
|
||||
void btrfs_get_delayed_items(struct inode *inode, struct list_head *ins_list,
|
||||
struct list_head *del_list);
|
||||
void btrfs_put_delayed_items(struct list_head *ins_list,
|
||||
struct list_head *del_list);
|
||||
int btrfs_should_delete_dir_index(struct list_head *del_list,
|
||||
u64 index);
|
||||
int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent,
|
||||
filldir_t filldir,
|
||||
struct list_head *ins_list);
|
||||
|
||||
/* for init */
|
||||
int __init btrfs_delayed_inode_init(void);
|
||||
void btrfs_delayed_inode_exit(void);
|
||||
#endif
|
@ -124,8 +124,9 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
|
||||
* to use for the second index (if one is created).
|
||||
*/
|
||||
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, const char *name, int name_len, u64 dir,
|
||||
struct btrfs_key *location, u8 type, u64 index)
|
||||
*root, const char *name, int name_len,
|
||||
struct inode *dir, struct btrfs_key *location,
|
||||
u8 type, u64 index)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret2 = 0;
|
||||
@ -137,13 +138,17 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
struct btrfs_disk_key disk_key;
|
||||
u32 data_size;
|
||||
|
||||
key.objectid = dir;
|
||||
key.objectid = dir->i_ino;
|
||||
btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
|
||||
key.offset = btrfs_name_hash(name, name_len);
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
path->leave_spinning = 1;
|
||||
|
||||
btrfs_cpu_key_to_disk(&disk_key, location);
|
||||
|
||||
data_size = sizeof(*dir_item) + name_len;
|
||||
dir_item = insert_with_overflow(trans, root, path, &key, data_size,
|
||||
name, name_len);
|
||||
@ -155,7 +160,6 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
}
|
||||
|
||||
leaf = path->nodes[0];
|
||||
btrfs_cpu_key_to_disk(&disk_key, location);
|
||||
btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
|
||||
btrfs_set_dir_type(leaf, dir_item, type);
|
||||
btrfs_set_dir_data_len(leaf, dir_item, 0);
|
||||
@ -174,27 +178,9 @@ second_insert:
|
||||
}
|
||||
btrfs_release_path(root, path);
|
||||
|
||||
btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
|
||||
key.offset = index;
|
||||
dir_item = insert_with_overflow(trans, root, path, &key, data_size,
|
||||
name, name_len);
|
||||
if (IS_ERR(dir_item)) {
|
||||
ret2 = PTR_ERR(dir_item);
|
||||
goto out_free;
|
||||
}
|
||||
leaf = path->nodes[0];
|
||||
btrfs_cpu_key_to_disk(&disk_key, location);
|
||||
btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
|
||||
btrfs_set_dir_type(leaf, dir_item, type);
|
||||
btrfs_set_dir_data_len(leaf, dir_item, 0);
|
||||
btrfs_set_dir_name_len(leaf, dir_item, name_len);
|
||||
btrfs_set_dir_transid(leaf, dir_item, trans->transid);
|
||||
name_ptr = (unsigned long)(dir_item + 1);
|
||||
write_extent_buffer(leaf, name, name_ptr, name_len);
|
||||
btrfs_mark_buffer_dirty(leaf);
|
||||
|
||||
ret2 = btrfs_insert_delayed_dir_index(trans, root, name, name_len, dir,
|
||||
&disk_key, type, index);
|
||||
out_free:
|
||||
|
||||
btrfs_free_path(path);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -1059,6 +1059,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
|
||||
root->name = NULL;
|
||||
root->in_sysfs = 0;
|
||||
root->inode_tree = RB_ROOT;
|
||||
INIT_RADIX_TREE(&root->delayed_nodes_tree, GFP_ATOMIC);
|
||||
root->block_rsv = NULL;
|
||||
root->orphan_block_rsv = NULL;
|
||||
|
||||
@ -1707,6 +1708,13 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||
|
||||
INIT_LIST_HEAD(&fs_info->ordered_extents);
|
||||
spin_lock_init(&fs_info->ordered_extent_lock);
|
||||
fs_info->delayed_root = kmalloc(sizeof(struct btrfs_delayed_root),
|
||||
GFP_NOFS);
|
||||
if (!fs_info->delayed_root) {
|
||||
err = -ENOMEM;
|
||||
goto fail_iput;
|
||||
}
|
||||
btrfs_init_delayed_root(fs_info->delayed_root);
|
||||
|
||||
sb->s_blocksize = 4096;
|
||||
sb->s_blocksize_bits = blksize_bits(4096);
|
||||
@ -1774,7 +1782,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||
bh = btrfs_read_dev_super(fs_devices->latest_bdev);
|
||||
if (!bh) {
|
||||
err = -EINVAL;
|
||||
goto fail_iput;
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
memcpy(&fs_info->super_copy, bh->b_data, sizeof(fs_info->super_copy));
|
||||
@ -1786,7 +1794,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||
|
||||
disk_super = &fs_info->super_copy;
|
||||
if (!btrfs_super_root(disk_super))
|
||||
goto fail_iput;
|
||||
goto fail_alloc;
|
||||
|
||||
/* check FS state, whether FS is broken. */
|
||||
fs_info->fs_state |= btrfs_super_flags(disk_super);
|
||||
@ -1802,7 +1810,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||
ret = btrfs_parse_options(tree_root, options);
|
||||
if (ret) {
|
||||
err = ret;
|
||||
goto fail_iput;
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
features = btrfs_super_incompat_flags(disk_super) &
|
||||
@ -1812,7 +1820,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||
"unsupported optional features (%Lx).\n",
|
||||
(unsigned long long)features);
|
||||
err = -EINVAL;
|
||||
goto fail_iput;
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
features = btrfs_super_incompat_flags(disk_super);
|
||||
@ -1828,7 +1836,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||
"unsupported option features (%Lx).\n",
|
||||
(unsigned long long)features);
|
||||
err = -EINVAL;
|
||||
goto fail_iput;
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
btrfs_init_workers(&fs_info->generic_worker,
|
||||
@ -1875,6 +1883,9 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||
&fs_info->generic_worker);
|
||||
btrfs_init_workers(&fs_info->endio_freespace_worker, "freespace-write",
|
||||
1, &fs_info->generic_worker);
|
||||
btrfs_init_workers(&fs_info->delayed_workers, "delayed-meta",
|
||||
fs_info->thread_pool_size,
|
||||
&fs_info->generic_worker);
|
||||
|
||||
/*
|
||||
* endios are largely parallel and should have a very
|
||||
@ -1896,6 +1907,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||
btrfs_start_workers(&fs_info->endio_meta_write_workers, 1);
|
||||
btrfs_start_workers(&fs_info->endio_write_workers, 1);
|
||||
btrfs_start_workers(&fs_info->endio_freespace_worker, 1);
|
||||
btrfs_start_workers(&fs_info->delayed_workers, 1);
|
||||
|
||||
fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super);
|
||||
fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages,
|
||||
@ -2152,6 +2164,9 @@ fail_sb_buffer:
|
||||
btrfs_stop_workers(&fs_info->endio_write_workers);
|
||||
btrfs_stop_workers(&fs_info->endio_freespace_worker);
|
||||
btrfs_stop_workers(&fs_info->submit_workers);
|
||||
btrfs_stop_workers(&fs_info->delayed_workers);
|
||||
fail_alloc:
|
||||
kfree(fs_info->delayed_root);
|
||||
fail_iput:
|
||||
invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
|
||||
iput(fs_info->btree_inode);
|
||||
@ -2597,6 +2612,7 @@ int close_ctree(struct btrfs_root *root)
|
||||
del_fs_roots(fs_info);
|
||||
|
||||
iput(fs_info->btree_inode);
|
||||
kfree(fs_info->delayed_root);
|
||||
|
||||
btrfs_stop_workers(&fs_info->generic_worker);
|
||||
btrfs_stop_workers(&fs_info->fixup_workers);
|
||||
@ -2608,6 +2624,7 @@ int close_ctree(struct btrfs_root *root)
|
||||
btrfs_stop_workers(&fs_info->endio_write_workers);
|
||||
btrfs_stop_workers(&fs_info->endio_freespace_worker);
|
||||
btrfs_stop_workers(&fs_info->submit_workers);
|
||||
btrfs_stop_workers(&fs_info->delayed_workers);
|
||||
|
||||
btrfs_close_devices(fs_info->fs_devices);
|
||||
btrfs_mapping_tree_free(&fs_info->mapping_tree);
|
||||
@ -2681,6 +2698,29 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
|
||||
u64 num_dirty;
|
||||
unsigned long thresh = 32 * 1024 * 1024;
|
||||
|
||||
if (current->flags & PF_MEMALLOC)
|
||||
return;
|
||||
|
||||
btrfs_balance_delayed_items(root);
|
||||
|
||||
num_dirty = root->fs_info->dirty_metadata_bytes;
|
||||
|
||||
if (num_dirty > thresh) {
|
||||
balance_dirty_pages_ratelimited_nr(
|
||||
root->fs_info->btree_inode->i_mapping, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
|
||||
{
|
||||
/*
|
||||
* looks as though older kernels can get into trouble with
|
||||
* this code, they end up stuck in balance_dirty_pages forever
|
||||
*/
|
||||
u64 num_dirty;
|
||||
unsigned long thresh = 32 * 1024 * 1024;
|
||||
|
||||
if (current->flags & PF_MEMALLOC)
|
||||
return;
|
||||
|
||||
|
@ -71,6 +71,7 @@ int btrfs_insert_dev_radix(struct btrfs_root *root,
|
||||
u64 block_start,
|
||||
u64 num_blocks);
|
||||
void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
|
||||
void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
|
||||
int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
|
||||
void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
|
||||
void btrfs_mark_buffer_dirty_nonblocking(struct extent_buffer *buf);
|
||||
|
@ -3975,12 +3975,6 @@ static void release_global_block_rsv(struct btrfs_fs_info *fs_info)
|
||||
WARN_ON(fs_info->chunk_block_rsv.reserved > 0);
|
||||
}
|
||||
|
||||
static u64 calc_trans_metadata_size(struct btrfs_root *root, int num_items)
|
||||
{
|
||||
return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
|
||||
3 * num_items;
|
||||
}
|
||||
|
||||
int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
int num_items)
|
||||
@ -3991,7 +3985,7 @@ int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
|
||||
if (num_items == 0 || root->fs_info->chunk_root == root)
|
||||
return 0;
|
||||
|
||||
num_bytes = calc_trans_metadata_size(root, num_items);
|
||||
num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
|
||||
ret = btrfs_block_rsv_add(trans, root, &root->fs_info->trans_block_rsv,
|
||||
num_bytes);
|
||||
if (!ret) {
|
||||
@ -4030,14 +4024,14 @@ int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
|
||||
* If all of the metadata space is used, we can commit
|
||||
* transaction and use space it freed.
|
||||
*/
|
||||
u64 num_bytes = calc_trans_metadata_size(root, 4);
|
||||
u64 num_bytes = btrfs_calc_trans_metadata_size(root, 4);
|
||||
return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
|
||||
}
|
||||
|
||||
void btrfs_orphan_release_metadata(struct inode *inode)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
u64 num_bytes = calc_trans_metadata_size(root, 4);
|
||||
u64 num_bytes = btrfs_calc_trans_metadata_size(root, 4);
|
||||
btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes);
|
||||
}
|
||||
|
||||
@ -4051,7 +4045,7 @@ int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
|
||||
* two for root back/forward refs, two for directory entries
|
||||
* and one for root of the snapshot.
|
||||
*/
|
||||
u64 num_bytes = calc_trans_metadata_size(root, 5);
|
||||
u64 num_bytes = btrfs_calc_trans_metadata_size(root, 5);
|
||||
dst_rsv->space_info = src_rsv->space_info;
|
||||
return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
|
||||
}
|
||||
@ -4080,7 +4074,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
|
||||
|
||||
if (nr_extents > reserved_extents) {
|
||||
nr_extents -= reserved_extents;
|
||||
to_reserve = calc_trans_metadata_size(root, nr_extents);
|
||||
to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
|
||||
} else {
|
||||
nr_extents = 0;
|
||||
to_reserve = 0;
|
||||
@ -4134,7 +4128,7 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
|
||||
|
||||
to_free = calc_csum_metadata_size(inode, num_bytes);
|
||||
if (nr_extents > 0)
|
||||
to_free += calc_trans_metadata_size(root, nr_extents);
|
||||
to_free += btrfs_calc_trans_metadata_size(root, nr_extents);
|
||||
|
||||
btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv,
|
||||
to_free);
|
||||
|
113
fs/btrfs/inode.c
113
fs/btrfs/inode.c
@ -2659,11 +2659,26 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
|
||||
struct extent_buffer *leaf;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If root is tree root, it means this inode is used to
|
||||
* store free space information. And these inodes are updated
|
||||
* when committing the transaction, so they needn't delaye to
|
||||
* be updated, or deadlock will occured.
|
||||
*/
|
||||
if (!is_free_space_inode(root, inode)) {
|
||||
ret = btrfs_delayed_update_inode(trans, root, inode);
|
||||
if (!ret)
|
||||
btrfs_set_inode_last_trans(trans, inode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
BUG_ON(!path);
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
path->leave_spinning = 1;
|
||||
ret = btrfs_lookup_inode(trans, root, path,
|
||||
&BTRFS_I(inode)->location, 1);
|
||||
ret = btrfs_lookup_inode(trans, root, path, &BTRFS_I(inode)->location,
|
||||
1);
|
||||
if (ret) {
|
||||
if (ret > 0)
|
||||
ret = -ENOENT;
|
||||
@ -2673,7 +2688,7 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
|
||||
btrfs_unlock_up_safe(path, 1);
|
||||
leaf = path->nodes[0];
|
||||
inode_item = btrfs_item_ptr(leaf, path->slots[0],
|
||||
struct btrfs_inode_item);
|
||||
struct btrfs_inode_item);
|
||||
|
||||
fill_inode_item(trans, leaf, inode_item, inode);
|
||||
btrfs_mark_buffer_dirty(leaf);
|
||||
@ -2684,7 +2699,6 @@ failed:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* unlink helper that gets used here in inode.c and in the tree logging
|
||||
* recovery code. It remove a link in a directory with a given name, and
|
||||
@ -2737,18 +2751,9 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
|
||||
goto err;
|
||||
}
|
||||
|
||||
di = btrfs_lookup_dir_index_item(trans, root, path, dir_ino,
|
||||
index, name, name_len, -1);
|
||||
if (IS_ERR(di)) {
|
||||
ret = PTR_ERR(di);
|
||||
ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
if (!di) {
|
||||
ret = -ENOENT;
|
||||
goto err;
|
||||
}
|
||||
ret = btrfs_delete_one_dir_name(trans, root, path, di);
|
||||
btrfs_release_path(root, path);
|
||||
|
||||
ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
|
||||
inode, dir_ino);
|
||||
@ -2939,6 +2944,14 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
|
||||
index = btrfs_inode_ref_index(path->nodes[0], ref);
|
||||
btrfs_release_path(root, path);
|
||||
|
||||
/*
|
||||
* This is a commit root search, if we can lookup inode item and other
|
||||
* relative items in the commit root, it means the transaction of
|
||||
* dir/file creation has been committed, and the dir index item that we
|
||||
* delay to insert has also been inserted into the commit root. So
|
||||
* we needn't worry about the delayed insertion of the dir index item
|
||||
* here.
|
||||
*/
|
||||
di = btrfs_lookup_dir_index_item(trans, root, path, dir_ino, index,
|
||||
dentry->d_name.name, dentry->d_name.len, 0);
|
||||
if (IS_ERR(di)) {
|
||||
@ -3045,24 +3058,16 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
|
||||
btrfs_release_path(root, path);
|
||||
index = key.offset;
|
||||
}
|
||||
|
||||
di = btrfs_lookup_dir_index_item(trans, root, path, dir_ino,
|
||||
index, name, name_len, -1);
|
||||
BUG_ON(!di || IS_ERR(di));
|
||||
|
||||
leaf = path->nodes[0];
|
||||
btrfs_dir_item_key_to_cpu(leaf, di, &key);
|
||||
WARN_ON(key.type != BTRFS_ROOT_ITEM_KEY || key.objectid != objectid);
|
||||
ret = btrfs_delete_one_dir_name(trans, root, path, di);
|
||||
BUG_ON(ret);
|
||||
btrfs_release_path(root, path);
|
||||
|
||||
ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
|
||||
BUG_ON(ret);
|
||||
|
||||
btrfs_i_size_write(dir, dir->i_size - name_len * 2);
|
||||
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
|
||||
ret = btrfs_update_inode(trans, root, dir);
|
||||
BUG_ON(ret);
|
||||
|
||||
btrfs_free_path(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3323,6 +3328,15 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
|
||||
if (root->ref_cows || root == root->fs_info->tree_root)
|
||||
btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0);
|
||||
|
||||
/*
|
||||
* This function is also used to drop the items in the log tree before
|
||||
* we relog the inode, so if root != BTRFS_I(inode)->root, it means
|
||||
* it is used to drop the loged items. So we shouldn't kill the delayed
|
||||
* items.
|
||||
*/
|
||||
if (min_type == 0 && root == BTRFS_I(inode)->root)
|
||||
btrfs_kill_delayed_inode_items(inode);
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
BUG_ON(!path);
|
||||
path->reada = -1;
|
||||
@ -4232,7 +4246,7 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
return d_splice_alias(inode, dentry);
|
||||
}
|
||||
|
||||
static unsigned char btrfs_filetype_table[] = {
|
||||
unsigned char btrfs_filetype_table[] = {
|
||||
DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
|
||||
};
|
||||
|
||||
@ -4246,6 +4260,8 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
|
||||
struct btrfs_key key;
|
||||
struct btrfs_key found_key;
|
||||
struct btrfs_path *path;
|
||||
struct list_head ins_list;
|
||||
struct list_head del_list;
|
||||
int ret;
|
||||
struct extent_buffer *leaf;
|
||||
int slot;
|
||||
@ -4258,6 +4274,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
|
||||
char tmp_name[32];
|
||||
char *name_ptr;
|
||||
int name_len;
|
||||
int is_curr = 0; /* filp->f_pos points to the current index? */
|
||||
|
||||
/* FIXME, use a real flag for deciding about the key type */
|
||||
if (root->fs_info->tree_root == root)
|
||||
@ -4280,8 +4297,16 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
|
||||
filp->f_pos = 2;
|
||||
}
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
path->reada = 2;
|
||||
|
||||
if (key_type == BTRFS_DIR_INDEX_KEY) {
|
||||
INIT_LIST_HEAD(&ins_list);
|
||||
INIT_LIST_HEAD(&del_list);
|
||||
btrfs_get_delayed_items(inode, &ins_list, &del_list);
|
||||
}
|
||||
|
||||
btrfs_set_key_type(&key, key_type);
|
||||
key.offset = filp->f_pos;
|
||||
key.objectid = btrfs_ino(inode);
|
||||
@ -4311,8 +4336,13 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
|
||||
break;
|
||||
if (found_key.offset < filp->f_pos)
|
||||
goto next;
|
||||
if (key_type == BTRFS_DIR_INDEX_KEY &&
|
||||
btrfs_should_delete_dir_index(&del_list,
|
||||
found_key.offset))
|
||||
goto next;
|
||||
|
||||
filp->f_pos = found_key.offset;
|
||||
is_curr = 1;
|
||||
|
||||
di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
|
||||
di_cur = 0;
|
||||
@ -4367,6 +4397,15 @@ next:
|
||||
path->slots[0]++;
|
||||
}
|
||||
|
||||
if (key_type == BTRFS_DIR_INDEX_KEY) {
|
||||
if (is_curr)
|
||||
filp->f_pos++;
|
||||
ret = btrfs_readdir_delayed_dir_index(filp, dirent, filldir,
|
||||
&ins_list);
|
||||
if (ret)
|
||||
goto nopos;
|
||||
}
|
||||
|
||||
/* Reached end of directory/root. Bump pos past the last item. */
|
||||
if (key_type == BTRFS_DIR_INDEX_KEY)
|
||||
/*
|
||||
@ -4379,6 +4418,8 @@ next:
|
||||
nopos:
|
||||
ret = 0;
|
||||
err:
|
||||
if (key_type == BTRFS_DIR_INDEX_KEY)
|
||||
btrfs_put_delayed_items(&ins_list, &del_list);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
@ -4459,6 +4500,8 @@ void btrfs_dirty_inode(struct inode *inode)
|
||||
}
|
||||
}
|
||||
btrfs_end_transaction(trans, root);
|
||||
if (BTRFS_I(inode)->delayed_node)
|
||||
btrfs_balance_delayed_items(root);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4527,9 +4570,12 @@ int btrfs_set_inode_index(struct inode *dir, u64 *index)
|
||||
int ret = 0;
|
||||
|
||||
if (BTRFS_I(dir)->index_cnt == (u64)-1) {
|
||||
ret = btrfs_set_inode_index_count(dir);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = btrfs_inode_delayed_dir_index_count(dir);
|
||||
if (ret) {
|
||||
ret = btrfs_set_inode_index_count(dir);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
*index = BTRFS_I(dir)->index_cnt;
|
||||
@ -4701,7 +4747,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
|
||||
|
||||
if (ret == 0) {
|
||||
ret = btrfs_insert_dir_item(trans, root, name, name_len,
|
||||
parent_ino, &key,
|
||||
parent_inode, &key,
|
||||
btrfs_inode_type(inode), index);
|
||||
BUG_ON(ret);
|
||||
|
||||
@ -6816,6 +6862,8 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
|
||||
ei->dummy_inode = 0;
|
||||
ei->force_compress = BTRFS_COMPRESS_NONE;
|
||||
|
||||
ei->delayed_node = NULL;
|
||||
|
||||
inode = &ei->vfs_inode;
|
||||
extent_map_tree_init(&ei->extent_tree, GFP_NOFS);
|
||||
extent_io_tree_init(&ei->io_tree, &inode->i_data, GFP_NOFS);
|
||||
@ -6906,6 +6954,7 @@ void btrfs_destroy_inode(struct inode *inode)
|
||||
inode_tree_del(inode);
|
||||
btrfs_drop_extent_cache(inode, 0, (u64)-1, 0);
|
||||
free:
|
||||
btrfs_remove_delayed_node(inode);
|
||||
call_rcu(&inode->i_rcu, btrfs_i_callback);
|
||||
}
|
||||
|
||||
|
@ -422,7 +422,7 @@ static noinline int create_subvol(struct btrfs_root *root,
|
||||
BUG_ON(ret);
|
||||
|
||||
ret = btrfs_insert_dir_item(trans, root,
|
||||
name, namelen, btrfs_ino(dir), &key,
|
||||
name, namelen, dir, &key,
|
||||
BTRFS_FT_DIR, index);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <linux/magic.h>
|
||||
#include <linux/slab.h>
|
||||
#include "compat.h"
|
||||
#include "delayed-inode.h"
|
||||
#include "ctree.h"
|
||||
#include "disk-io.h"
|
||||
#include "transaction.h"
|
||||
@ -1206,10 +1207,14 @@ static int __init init_btrfs_fs(void)
|
||||
if (err)
|
||||
goto free_extent_io;
|
||||
|
||||
err = btrfs_interface_init();
|
||||
err = btrfs_delayed_inode_init();
|
||||
if (err)
|
||||
goto free_extent_map;
|
||||
|
||||
err = btrfs_interface_init();
|
||||
if (err)
|
||||
goto free_delayed_inode;
|
||||
|
||||
err = register_filesystem(&btrfs_fs_type);
|
||||
if (err)
|
||||
goto unregister_ioctl;
|
||||
@ -1219,6 +1224,8 @@ static int __init init_btrfs_fs(void)
|
||||
|
||||
unregister_ioctl:
|
||||
btrfs_interface_exit();
|
||||
free_delayed_inode:
|
||||
btrfs_delayed_inode_exit();
|
||||
free_extent_map:
|
||||
extent_map_exit();
|
||||
free_extent_io:
|
||||
@ -1235,6 +1242,7 @@ free_sysfs:
|
||||
static void __exit exit_btrfs_fs(void)
|
||||
{
|
||||
btrfs_destroy_cachep();
|
||||
btrfs_delayed_inode_exit();
|
||||
extent_map_exit();
|
||||
extent_io_exit();
|
||||
btrfs_interface_exit();
|
||||
|
@ -488,19 +488,40 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
|
||||
int btrfs_end_transaction(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
return __btrfs_end_transaction(trans, root, 0, 1);
|
||||
int ret;
|
||||
|
||||
ret = __btrfs_end_transaction(trans, root, 0, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
return __btrfs_end_transaction(trans, root, 1, 1);
|
||||
int ret;
|
||||
|
||||
ret = __btrfs_end_transaction(trans, root, 1, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_end_transaction_nolock(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
return __btrfs_end_transaction(trans, root, 0, 0);
|
||||
int ret;
|
||||
|
||||
ret = __btrfs_end_transaction(trans, root, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
return __btrfs_end_transaction(trans, root, 1, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -974,7 +995,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||
BUG_ON(ret);
|
||||
ret = btrfs_insert_dir_item(trans, parent_root,
|
||||
dentry->d_name.name, dentry->d_name.len,
|
||||
btrfs_ino(parent_inode), &key,
|
||||
parent_inode, &key,
|
||||
BTRFS_FT_DIR, index);
|
||||
BUG_ON(ret);
|
||||
|
||||
@ -1044,6 +1065,14 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans,
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(pending, head, list) {
|
||||
/*
|
||||
* We must deal with the delayed items before creating
|
||||
* snapshots, or we will create a snapthot with inconsistent
|
||||
* information.
|
||||
*/
|
||||
ret = btrfs_run_delayed_items(trans, fs_info->fs_root);
|
||||
BUG_ON(ret);
|
||||
|
||||
ret = create_pending_snapshot(trans, fs_info, pending);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
@ -1297,6 +1326,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
|
||||
BUG_ON(ret);
|
||||
}
|
||||
|
||||
ret = btrfs_run_delayed_items(trans, root);
|
||||
BUG_ON(ret);
|
||||
|
||||
/*
|
||||
* rename don't use btrfs_join_transaction, so, once we
|
||||
* set the transaction to blocked above, we aren't going
|
||||
@ -1323,6 +1355,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
|
||||
ret = create_pending_snapshots(trans, root->fs_info);
|
||||
BUG_ON(ret);
|
||||
|
||||
ret = btrfs_run_delayed_items(trans, root);
|
||||
BUG_ON(ret);
|
||||
|
||||
ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
|
||||
BUG_ON(ret);
|
||||
|
||||
@ -1439,6 +1474,8 @@ int btrfs_clean_old_snapshots(struct btrfs_root *root)
|
||||
root = list_entry(list.next, struct btrfs_root, root_list);
|
||||
list_del(&root->root_list);
|
||||
|
||||
btrfs_kill_all_delayed_nodes(root);
|
||||
|
||||
if (btrfs_header_backref_rev(root->node) <
|
||||
BTRFS_MIXED_BACKREF_REV)
|
||||
btrfs_drop_snapshot(root, NULL, 0);
|
||||
|
@ -115,6 +115,8 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
|
||||
int wait_for_unblock);
|
||||
int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
int btrfs_should_end_transaction(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
void btrfs_throttle(struct btrfs_root *root);
|
||||
|
@ -2774,6 +2774,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
|
||||
max_key.type = (u8)-1;
|
||||
max_key.offset = (u64)-1;
|
||||
|
||||
ret = btrfs_commit_inode_delayed_items(trans, inode);
|
||||
if (ret) {
|
||||
btrfs_free_path(path);
|
||||
btrfs_free_path(dst_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&BTRFS_I(inode)->log_mutex);
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user