mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	Btrfs: Add a write ahead tree log to optimize synchronous operations
File syncs and directory syncs are optimized by copying their items into a special (copy-on-write) log tree. There is one log tree per subvolume and the btrfs super block points to a tree of log tree roots. After a crash, items are copied out of the log tree and back into the subvolume. See tree-log.c for all the details. Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
		
							parent
							
								
									a1b32a5932
								
							
						
					
					
						commit
						e02119d5a7
					
				
					 17 changed files with 3408 additions and 205 deletions
				
			
		| 
						 | 
				
			
			@ -7,8 +7,7 @@ btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
 | 
			
		|||
	   transaction.o bit-radix.o inode.o file.o tree-defrag.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 \
 | 
			
		||||
	   ref-cache.o acl.o export.o
 | 
			
		||||
 | 
			
		||||
	   ref-cache.o export.o tree-log.o acl.o
 | 
			
		||||
else
 | 
			
		||||
 | 
			
		||||
# Normal Makefile
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,6 +33,7 @@ struct btrfs_inode {
 | 
			
		|||
	struct extent_io_tree io_failure_tree;
 | 
			
		||||
	struct mutex csum_mutex;
 | 
			
		||||
	struct mutex extent_mutex;
 | 
			
		||||
	struct mutex log_mutex;
 | 
			
		||||
	struct inode vfs_inode;
 | 
			
		||||
	struct btrfs_ordered_inode_tree ordered_tree;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -44,10 +45,17 @@ struct btrfs_inode {
 | 
			
		|||
 | 
			
		||||
	struct list_head delalloc_inodes;
 | 
			
		||||
 | 
			
		||||
	/* full 64 bit generation number */
 | 
			
		||||
	u64 generation;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * transid of the trans_handle that last modified this inode
 | 
			
		||||
	 */
 | 
			
		||||
	u64 last_trans;
 | 
			
		||||
	/*
 | 
			
		||||
	 * transid that last logged this inode
 | 
			
		||||
	 */
 | 
			
		||||
	u64 logged_trans;
 | 
			
		||||
	u64 delalloc_bytes;
 | 
			
		||||
	u64 disk_i_size;
 | 
			
		||||
	u32 flags;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,21 @@ static inline struct dentry *d_obtain_alias(struct inode *inode)
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
 | 
			
		||||
static inline void btrfs_drop_nlink(struct inode *inode)
 | 
			
		||||
{
 | 
			
		||||
	inode->i_nlink--;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void btrfs_inc_nlink(struct inode *inode)
 | 
			
		||||
{
 | 
			
		||||
	inode->i_nlink++;
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
# define btrfs_drop_nlink(inode) drop_nlink(inode)
 | 
			
		||||
# define btrfs_inc_nlink(inode)	inc_nlink(inode)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Even if AppArmor isn't enabled, it still has different prototypes.
 | 
			
		||||
 * Add more distro/version pairs here to declare which has AppArmor applied.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,7 +60,7 @@ void btrfs_free_path(struct btrfs_path *p)
 | 
			
		|||
	kmem_cache_free(btrfs_path_cachep, p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p)
 | 
			
		||||
void noinline btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -176,7 +176,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int __btrfs_cow_block(struct btrfs_trans_handle *trans,
 | 
			
		||||
int noinline __btrfs_cow_block(struct btrfs_trans_handle *trans,
 | 
			
		||||
			     struct btrfs_root *root,
 | 
			
		||||
			     struct extent_buffer *buf,
 | 
			
		||||
			     struct extent_buffer *parent, int parent_slot,
 | 
			
		||||
| 
						 | 
				
			
			@ -294,7 +294,7 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int btrfs_cow_block(struct btrfs_trans_handle *trans,
 | 
			
		||||
int noinline btrfs_cow_block(struct btrfs_trans_handle *trans,
 | 
			
		||||
		    struct btrfs_root *root, struct extent_buffer *buf,
 | 
			
		||||
		    struct extent_buffer *parent, int parent_slot,
 | 
			
		||||
		    struct extent_buffer **cow_ret, u64 prealloc_dest)
 | 
			
		||||
| 
						 | 
				
			
			@ -677,7 +677,8 @@ static int noinline check_block(struct btrfs_root *root,
 | 
			
		|||
 *
 | 
			
		||||
 * slot may point to max if the key is bigger than all of the keys
 | 
			
		||||
 */
 | 
			
		||||
static int generic_bin_search(struct extent_buffer *eb, unsigned long p,
 | 
			
		||||
static noinline int generic_bin_search(struct extent_buffer *eb,
 | 
			
		||||
				       unsigned long p,
 | 
			
		||||
				       int item_size, struct btrfs_key *key,
 | 
			
		||||
				       int max, int *slot)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -765,7 +766,7 @@ static int bin_search(struct extent_buffer *eb, struct btrfs_key *key,
 | 
			
		|||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct extent_buffer *read_node_slot(struct btrfs_root *root,
 | 
			
		||||
static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root,
 | 
			
		||||
				   struct extent_buffer *parent, int slot)
 | 
			
		||||
{
 | 
			
		||||
	int level = btrfs_header_level(parent);
 | 
			
		||||
| 
						 | 
				
			
			@ -781,7 +782,7 @@ static struct extent_buffer *read_node_slot(struct btrfs_root *root,
 | 
			
		|||
		       btrfs_node_ptr_generation(parent, slot));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int balance_level(struct btrfs_trans_handle *trans,
 | 
			
		||||
static noinline int balance_level(struct btrfs_trans_handle *trans,
 | 
			
		||||
			 struct btrfs_root *root,
 | 
			
		||||
			 struct btrfs_path *path, int level)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1128,7 +1129,8 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans,
 | 
			
		|||
/*
 | 
			
		||||
 * readahead one full node of leaves
 | 
			
		||||
 */
 | 
			
		||||
static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
 | 
			
		||||
static noinline void reada_for_search(struct btrfs_root *root,
 | 
			
		||||
				      struct btrfs_path *path,
 | 
			
		||||
				      int level, int slot, u64 objectid)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_buffer *node;
 | 
			
		||||
| 
						 | 
				
			
			@ -1201,7 +1203,8 @@ static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void unlock_up(struct btrfs_path *path, int level, int lowest_unlock)
 | 
			
		||||
static noinline void unlock_up(struct btrfs_path *path, int level,
 | 
			
		||||
			       int lowest_unlock)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	int skip_level = level;
 | 
			
		||||
| 
						 | 
				
			
			@ -1759,8 +1762,9 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
 | 
			
		|||
 *
 | 
			
		||||
 * returns 0 on success and < 0 on failure
 | 
			
		||||
 */
 | 
			
		||||
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
 | 
			
		||||
		      *root, struct btrfs_path *path, int level)
 | 
			
		||||
static noinline int split_node(struct btrfs_trans_handle *trans,
 | 
			
		||||
			       struct btrfs_root *root,
 | 
			
		||||
			       struct btrfs_path *path, int level)
 | 
			
		||||
{
 | 
			
		||||
	u64 root_gen;
 | 
			
		||||
	struct extent_buffer *c;
 | 
			
		||||
| 
						 | 
				
			
			@ -1874,7 +1878,8 @@ static int leaf_space_used(struct extent_buffer *l, int start, int nr)
 | 
			
		|||
 * the start of the leaf data.  IOW, how much room
 | 
			
		||||
 * the leaf has left for both items and data
 | 
			
		||||
 */
 | 
			
		||||
int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf)
 | 
			
		||||
int noinline btrfs_leaf_free_space(struct btrfs_root *root,
 | 
			
		||||
				   struct extent_buffer *leaf)
 | 
			
		||||
{
 | 
			
		||||
	int nritems = btrfs_header_nritems(leaf);
 | 
			
		||||
	int ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -2283,9 +2288,11 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
 | 
			
		|||
 *
 | 
			
		||||
 * returns 0 if all went well and < 0 on failure.
 | 
			
		||||
 */
 | 
			
		||||
static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
 | 
			
		||||
		      *root, struct btrfs_key *ins_key,
 | 
			
		||||
		      struct btrfs_path *path, int data_size, int extend)
 | 
			
		||||
static noinline int split_leaf(struct btrfs_trans_handle *trans,
 | 
			
		||||
			       struct btrfs_root *root,
 | 
			
		||||
			       struct btrfs_key *ins_key,
 | 
			
		||||
			       struct btrfs_path *path, int data_size,
 | 
			
		||||
			       int extend)
 | 
			
		||||
{
 | 
			
		||||
	u64 root_gen;
 | 
			
		||||
	struct extent_buffer *l;
 | 
			
		||||
| 
						 | 
				
			
			@ -3079,6 +3086,7 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
 | 
			
		|||
 * was nothing in the tree that matched the search criteria.
 | 
			
		||||
 */
 | 
			
		||||
int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
 | 
			
		||||
			 struct btrfs_key *max_key,
 | 
			
		||||
			 struct btrfs_path *path, int cache_only,
 | 
			
		||||
			 u64 min_trans)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -3093,6 +3101,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
 | 
			
		|||
again:
 | 
			
		||||
	cur = btrfs_lock_root_node(root);
 | 
			
		||||
	level = btrfs_header_level(cur);
 | 
			
		||||
	WARN_ON(path->nodes[level]);
 | 
			
		||||
	path->nodes[level] = cur;
 | 
			
		||||
	path->locks[level] = 1;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3107,6 +3116,8 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
 | 
			
		|||
 | 
			
		||||
		/* at level = 0, we're done, setup the path and exit */
 | 
			
		||||
		if (level == 0) {
 | 
			
		||||
			if (slot >= nritems)
 | 
			
		||||
				goto find_next_key;
 | 
			
		||||
			ret = 0;
 | 
			
		||||
			path->slots[level] = slot;
 | 
			
		||||
			btrfs_item_key_to_cpu(cur, &found_key, slot);
 | 
			
		||||
| 
						 | 
				
			
			@ -3123,6 +3134,8 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
 | 
			
		|||
			u64 blockptr;
 | 
			
		||||
			u64 gen;
 | 
			
		||||
			struct extent_buffer *tmp;
 | 
			
		||||
			struct btrfs_disk_key disk_key;
 | 
			
		||||
 | 
			
		||||
			blockptr = btrfs_node_blockptr(cur, slot);
 | 
			
		||||
			gen = btrfs_node_ptr_generation(cur, slot);
 | 
			
		||||
			if (gen < min_trans) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3132,6 +3145,14 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
 | 
			
		|||
			if (!cache_only)
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			if (max_key) {
 | 
			
		||||
				btrfs_node_key(cur, &disk_key, slot);
 | 
			
		||||
				if (comp_keys(&disk_key, max_key) >= 0) {
 | 
			
		||||
					ret = 1;
 | 
			
		||||
					goto out;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			tmp = btrfs_find_tree_block(root, blockptr,
 | 
			
		||||
					    btrfs_level_size(root, level - 1));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3143,14 +3164,16 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
 | 
			
		|||
				free_extent_buffer(tmp);
 | 
			
		||||
			slot++;
 | 
			
		||||
		}
 | 
			
		||||
find_next_key:
 | 
			
		||||
		/*
 | 
			
		||||
		 * we didn't find a candidate key in this node, walk forward
 | 
			
		||||
		 * and find another one
 | 
			
		||||
		 */
 | 
			
		||||
		if (slot >= nritems) {
 | 
			
		||||
			ret = btrfs_find_next_key(root, path, min_key, level,
 | 
			
		||||
			path->slots[level] = slot;
 | 
			
		||||
			sret = btrfs_find_next_key(root, path, min_key, level,
 | 
			
		||||
						  cache_only, min_trans);
 | 
			
		||||
			if (ret == 0) {
 | 
			
		||||
			if (sret == 0) {
 | 
			
		||||
				btrfs_release_path(root, path);
 | 
			
		||||
				goto again;
 | 
			
		||||
			} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -3351,6 +3374,7 @@ int btrfs_previous_item(struct btrfs_root *root,
 | 
			
		|||
{
 | 
			
		||||
	struct btrfs_key found_key;
 | 
			
		||||
	struct extent_buffer *leaf;
 | 
			
		||||
	u32 nritems;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	while(1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3362,9 +3386,20 @@ int btrfs_previous_item(struct btrfs_root *root,
 | 
			
		|||
			path->slots[0]--;
 | 
			
		||||
		}
 | 
			
		||||
		leaf = path->nodes[0];
 | 
			
		||||
		nritems = btrfs_header_nritems(leaf);
 | 
			
		||||
		if (nritems == 0)
 | 
			
		||||
			return 1;
 | 
			
		||||
		if (path->slots[0] == nritems)
 | 
			
		||||
			path->slots[0]--;
 | 
			
		||||
 | 
			
		||||
		btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
 | 
			
		||||
		if (found_key.type == type)
 | 
			
		||||
			return 0;
 | 
			
		||||
		if (found_key.objectid < min_objectid)
 | 
			
		||||
			break;
 | 
			
		||||
		if (found_key.objectid == min_objectid &&
 | 
			
		||||
		    found_key.type < type)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,6 +77,10 @@ struct btrfs_ordered_sum;
 | 
			
		|||
/* orhpan objectid for tracking unlinked/truncated files */
 | 
			
		||||
#define BTRFS_ORPHAN_OBJECTID -5ULL
 | 
			
		||||
 | 
			
		||||
/* does write ahead logging to speed up fsyncs */
 | 
			
		||||
#define BTRFS_TREE_LOG_OBJECTID -6ULL
 | 
			
		||||
#define BTRFS_TREE_LOG_FIXUP_OBJECTID -7ULL
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * All files have objectids higher than this.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -276,6 +280,7 @@ struct btrfs_super_block {
 | 
			
		|||
	__le64 generation;
 | 
			
		||||
	__le64 root;
 | 
			
		||||
	__le64 chunk_root;
 | 
			
		||||
	__le64 log_root;
 | 
			
		||||
	__le64 total_bytes;
 | 
			
		||||
	__le64 bytes_used;
 | 
			
		||||
	__le64 root_dir_objectid;
 | 
			
		||||
| 
						 | 
				
			
			@ -287,6 +292,7 @@ struct btrfs_super_block {
 | 
			
		|||
	__le32 sys_chunk_array_size;
 | 
			
		||||
	u8 root_level;
 | 
			
		||||
	u8 chunk_root_level;
 | 
			
		||||
	u8 log_root_level;
 | 
			
		||||
	struct btrfs_dev_item dev_item;
 | 
			
		||||
	char label[BTRFS_LABEL_SIZE];
 | 
			
		||||
	u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE];
 | 
			
		||||
| 
						 | 
				
			
			@ -392,7 +398,10 @@ struct btrfs_timespec {
 | 
			
		|||
 * make a new item type
 | 
			
		||||
 */
 | 
			
		||||
struct btrfs_inode_item {
 | 
			
		||||
	/* nfs style generation number */
 | 
			
		||||
	__le64 generation;
 | 
			
		||||
	/* transid that last touched this inode */
 | 
			
		||||
	__le64 transid;
 | 
			
		||||
	__le64 size;
 | 
			
		||||
	__le64 nblocks;
 | 
			
		||||
	__le64 block_group;
 | 
			
		||||
| 
						 | 
				
			
			@ -409,8 +418,13 @@ struct btrfs_inode_item {
 | 
			
		|||
	struct btrfs_timespec otime;
 | 
			
		||||
} __attribute__ ((__packed__));
 | 
			
		||||
 | 
			
		||||
struct btrfs_dir_log_item {
 | 
			
		||||
	__le64 end;
 | 
			
		||||
} __attribute__ ((__packed__));
 | 
			
		||||
 | 
			
		||||
struct btrfs_dir_item {
 | 
			
		||||
	struct btrfs_disk_key location;
 | 
			
		||||
	__le64 transid;
 | 
			
		||||
	__le16 data_len;
 | 
			
		||||
	__le16 name_len;
 | 
			
		||||
	u8 type;
 | 
			
		||||
| 
						 | 
				
			
			@ -505,6 +519,9 @@ struct btrfs_fs_info {
 | 
			
		|||
	struct btrfs_root *tree_root;
 | 
			
		||||
	struct btrfs_root *chunk_root;
 | 
			
		||||
	struct btrfs_root *dev_root;
 | 
			
		||||
 | 
			
		||||
	/* the log root tree is a directory of all the other log roots */
 | 
			
		||||
	struct btrfs_root *log_root_tree;
 | 
			
		||||
	struct radix_tree_root fs_roots_radix;
 | 
			
		||||
 | 
			
		||||
	struct extent_io_tree free_space_cache;
 | 
			
		||||
| 
						 | 
				
			
			@ -518,6 +535,7 @@ struct btrfs_fs_info {
 | 
			
		|||
 | 
			
		||||
	u64 generation;
 | 
			
		||||
	u64 last_trans_committed;
 | 
			
		||||
	u64 last_trans_new_blockgroup;
 | 
			
		||||
	u64 open_ioctl_trans;
 | 
			
		||||
	unsigned long mount_opt;
 | 
			
		||||
	u64 max_extent;
 | 
			
		||||
| 
						 | 
				
			
			@ -527,6 +545,9 @@ struct btrfs_fs_info {
 | 
			
		|||
	wait_queue_head_t transaction_throttle;
 | 
			
		||||
	wait_queue_head_t transaction_wait;
 | 
			
		||||
	wait_queue_head_t async_submit_wait;
 | 
			
		||||
 | 
			
		||||
	wait_queue_head_t tree_log_wait;
 | 
			
		||||
 | 
			
		||||
	struct btrfs_super_block super_copy;
 | 
			
		||||
	struct btrfs_super_block super_for_commit;
 | 
			
		||||
	struct block_device *__bdev;
 | 
			
		||||
| 
						 | 
				
			
			@ -535,6 +556,7 @@ struct btrfs_fs_info {
 | 
			
		|||
	struct backing_dev_info bdi;
 | 
			
		||||
	spinlock_t hash_lock;
 | 
			
		||||
	struct mutex trans_mutex;
 | 
			
		||||
	struct mutex tree_log_mutex;
 | 
			
		||||
	struct mutex transaction_kthread_mutex;
 | 
			
		||||
	struct mutex cleaner_mutex;
 | 
			
		||||
	struct mutex alloc_mutex;
 | 
			
		||||
| 
						 | 
				
			
			@ -544,8 +566,13 @@ struct btrfs_fs_info {
 | 
			
		|||
	struct list_head trans_list;
 | 
			
		||||
	struct list_head hashers;
 | 
			
		||||
	struct list_head dead_roots;
 | 
			
		||||
 | 
			
		||||
	atomic_t nr_async_submits;
 | 
			
		||||
	atomic_t nr_async_bios;
 | 
			
		||||
	atomic_t tree_log_writers;
 | 
			
		||||
	atomic_t tree_log_commit;
 | 
			
		||||
	unsigned long tree_log_batch;
 | 
			
		||||
	u64 tree_log_transid;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * this is used by the balancing code to wait for all the pending
 | 
			
		||||
| 
						 | 
				
			
			@ -583,6 +610,7 @@ struct btrfs_fs_info {
 | 
			
		|||
	struct completion kobj_unregister;
 | 
			
		||||
	int do_barriers;
 | 
			
		||||
	int closing;
 | 
			
		||||
	int log_root_recovering;
 | 
			
		||||
	atomic_t throttles;
 | 
			
		||||
	atomic_t throttle_gen;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -596,6 +624,7 @@ struct btrfs_fs_info {
 | 
			
		|||
	u64 delalloc_bytes;
 | 
			
		||||
	u64 last_alloc;
 | 
			
		||||
	u64 last_data_alloc;
 | 
			
		||||
	u64 last_log_alloc;
 | 
			
		||||
 | 
			
		||||
	spinlock_t ref_cache_lock;
 | 
			
		||||
	u64 total_ref_cache_size;
 | 
			
		||||
| 
						 | 
				
			
			@ -632,6 +661,7 @@ struct btrfs_root {
 | 
			
		|||
	struct btrfs_leaf_ref_tree *ref_tree;
 | 
			
		||||
	struct btrfs_leaf_ref_tree ref_tree_struct;
 | 
			
		||||
	struct btrfs_dirty_root *dirty_root;
 | 
			
		||||
	struct btrfs_root *log_root;
 | 
			
		||||
 | 
			
		||||
	struct btrfs_root_item root_item;
 | 
			
		||||
	struct btrfs_key root_key;
 | 
			
		||||
| 
						 | 
				
			
			@ -640,6 +670,7 @@ struct btrfs_root {
 | 
			
		|||
	struct kobject root_kobj;
 | 
			
		||||
	struct completion kobj_unregister;
 | 
			
		||||
	struct mutex objectid_mutex;
 | 
			
		||||
	struct mutex log_mutex;
 | 
			
		||||
 | 
			
		||||
	u64 objectid;
 | 
			
		||||
	u64 last_trans;
 | 
			
		||||
| 
						 | 
				
			
			@ -692,6 +723,8 @@ struct btrfs_root {
 | 
			
		|||
 * dir items are the name -> inode pointers in a directory.  There is one
 | 
			
		||||
 * for every name in a directory.
 | 
			
		||||
 */
 | 
			
		||||
#define BTRFS_DIR_LOG_ITEM_KEY  14
 | 
			
		||||
#define BTRFS_DIR_LOG_INDEX_KEY 15
 | 
			
		||||
#define BTRFS_DIR_ITEM_KEY	16
 | 
			
		||||
#define BTRFS_DIR_INDEX_KEY	17
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -703,7 +736,8 @@ struct btrfs_root {
 | 
			
		|||
 */
 | 
			
		||||
#define BTRFS_CSUM_ITEM_KEY	19
 | 
			
		||||
 | 
			
		||||
/* reserve 20-31 for other file stuff */
 | 
			
		||||
 | 
			
		||||
/* reserve 21-31 for other file/dir stuff */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * root items point to tree roots.  There are typically in the root
 | 
			
		||||
| 
						 | 
				
			
			@ -938,6 +972,7 @@ BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64);
 | 
			
		|||
 | 
			
		||||
/* struct btrfs_inode_item */
 | 
			
		||||
BTRFS_SETGET_FUNCS(inode_generation, struct btrfs_inode_item, generation, 64);
 | 
			
		||||
BTRFS_SETGET_FUNCS(inode_transid, struct btrfs_inode_item, transid, 64);
 | 
			
		||||
BTRFS_SETGET_FUNCS(inode_size, struct btrfs_inode_item, size, 64);
 | 
			
		||||
BTRFS_SETGET_FUNCS(inode_nblocks, struct btrfs_inode_item, nblocks, 64);
 | 
			
		||||
BTRFS_SETGET_FUNCS(inode_block_group, struct btrfs_inode_item, block_group, 64);
 | 
			
		||||
| 
						 | 
				
			
			@ -1126,10 +1161,13 @@ static inline void btrfs_set_item_key(struct extent_buffer *eb,
 | 
			
		|||
	write_eb_member(eb, item, struct btrfs_item, key, disk_key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BTRFS_SETGET_FUNCS(dir_log_end, struct btrfs_dir_log_item, end, 64);
 | 
			
		||||
 | 
			
		||||
/* struct btrfs_dir_item */
 | 
			
		||||
BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);
 | 
			
		||||
BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
 | 
			
		||||
BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16);
 | 
			
		||||
BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64);
 | 
			
		||||
 | 
			
		||||
static inline void btrfs_dir_item_key(struct extent_buffer *eb,
 | 
			
		||||
				      struct btrfs_dir_item *item,
 | 
			
		||||
| 
						 | 
				
			
			@ -1301,7 +1339,11 @@ BTRFS_SETGET_STACK_FUNCS(super_root_level, struct btrfs_super_block,
 | 
			
		|||
BTRFS_SETGET_STACK_FUNCS(super_chunk_root, struct btrfs_super_block,
 | 
			
		||||
			 chunk_root, 64);
 | 
			
		||||
BTRFS_SETGET_STACK_FUNCS(super_chunk_root_level, struct btrfs_super_block,
 | 
			
		||||
			 chunk_root_level, 64);
 | 
			
		||||
			 chunk_root_level, 8);
 | 
			
		||||
BTRFS_SETGET_STACK_FUNCS(super_log_root, struct btrfs_super_block,
 | 
			
		||||
			 log_root, 64);
 | 
			
		||||
BTRFS_SETGET_STACK_FUNCS(super_log_root_level, struct btrfs_super_block,
 | 
			
		||||
			 log_root_level, 8);
 | 
			
		||||
BTRFS_SETGET_STACK_FUNCS(super_total_bytes, struct btrfs_super_block,
 | 
			
		||||
			 total_bytes, 64);
 | 
			
		||||
BTRFS_SETGET_STACK_FUNCS(super_bytes_used, struct btrfs_super_block,
 | 
			
		||||
| 
						 | 
				
			
			@ -1405,6 +1447,12 @@ static inline struct dentry *fdentry(struct file *file) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
/* extent-tree.c */
 | 
			
		||||
int btrfs_lookup_extent(struct btrfs_root *root, struct btrfs_path *path,
 | 
			
		||||
			u64 start, u64 len);
 | 
			
		||||
int btrfs_update_pinned_extents(struct btrfs_root *root,
 | 
			
		||||
				u64 bytenr, u64 num, int pin);
 | 
			
		||||
int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
 | 
			
		||||
			struct btrfs_root *root, struct extent_buffer *leaf);
 | 
			
		||||
int btrfs_cross_ref_exists(struct btrfs_trans_handle *trans,
 | 
			
		||||
			   struct btrfs_root *root,
 | 
			
		||||
			   struct btrfs_key *key, u64 bytenr);
 | 
			
		||||
| 
						 | 
				
			
			@ -1448,6 +1496,11 @@ int btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
 | 
			
		|||
				u64 root_objectid, u64 ref_generation,
 | 
			
		||||
				u64 owner, u64 owner_offset,
 | 
			
		||||
				struct btrfs_key *ins);
 | 
			
		||||
int btrfs_alloc_logged_extent(struct btrfs_trans_handle *trans,
 | 
			
		||||
				struct btrfs_root *root,
 | 
			
		||||
				u64 root_objectid, u64 ref_generation,
 | 
			
		||||
				u64 owner, u64 owner_offset,
 | 
			
		||||
				struct btrfs_key *ins);
 | 
			
		||||
int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
 | 
			
		||||
				  struct btrfs_root *root,
 | 
			
		||||
				  u64 num_bytes, u64 min_alloc_size,
 | 
			
		||||
| 
						 | 
				
			
			@ -1488,9 +1541,9 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
 | 
			
		|||
			struct btrfs_key *key, int lowest_level,
 | 
			
		||||
			int cache_only, u64 min_trans);
 | 
			
		||||
int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
 | 
			
		||||
			 struct btrfs_key *max_key,
 | 
			
		||||
			 struct btrfs_path *path, int cache_only,
 | 
			
		||||
			 u64 min_trans);
 | 
			
		||||
 | 
			
		||||
int btrfs_cow_block(struct btrfs_trans_handle *trans,
 | 
			
		||||
		    struct btrfs_root *root, struct extent_buffer *buf,
 | 
			
		||||
		    struct extent_buffer *parent, int parent_slot,
 | 
			
		||||
| 
						 | 
				
			
			@ -1656,6 +1709,18 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
 | 
			
		|||
#define PageChecked PageFsMisc
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
 | 
			
		||||
		       struct btrfs_root *root,
 | 
			
		||||
		       struct inode *dir, struct inode *inode,
 | 
			
		||||
		       const char *name, int name_len);
 | 
			
		||||
int btrfs_add_link(struct btrfs_trans_handle *trans,
 | 
			
		||||
		   struct inode *parent_inode, struct inode *inode,
 | 
			
		||||
		   const char *name, int name_len, int add_backref, u64 index);
 | 
			
		||||
int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
 | 
			
		||||
			       struct btrfs_root *root,
 | 
			
		||||
			       struct inode *inode, u64 new_size,
 | 
			
		||||
			       u32 min_type);
 | 
			
		||||
 | 
			
		||||
int btrfs_start_delalloc_inodes(struct btrfs_root *root);
 | 
			
		||||
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end);
 | 
			
		||||
int btrfs_writepages(struct address_space *mapping,
 | 
			
		||||
| 
						 | 
				
			
			@ -1715,6 +1780,7 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 | 
			
		||||
 | 
			
		||||
/* file.c */
 | 
			
		||||
int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync);
 | 
			
		||||
int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end);
 | 
			
		||||
int btrfs_check_file(struct btrfs_root *root, struct inode *inode);
 | 
			
		||||
extern struct file_operations btrfs_file_operations;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,6 +96,7 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
 | 
			
		|||
	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
 | 
			
		||||
	btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR);
 | 
			
		||||
	btrfs_set_dir_name_len(leaf, dir_item, name_len);
 | 
			
		||||
	btrfs_set_dir_transid(leaf, dir_item, trans->transid);
 | 
			
		||||
	btrfs_set_dir_data_len(leaf, dir_item, data_len);
 | 
			
		||||
	name_ptr = (unsigned long)(dir_item + 1);
 | 
			
		||||
	data_ptr = (unsigned long)((char *)name_ptr + name_len);
 | 
			
		||||
| 
						 | 
				
			
			@ -142,6 +143,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
 | 
			
		|||
	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);
 | 
			
		||||
| 
						 | 
				
			
			@ -169,6 +171,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
 | 
			
		|||
	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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,6 +41,7 @@
 | 
			
		|||
#include "async-thread.h"
 | 
			
		||||
#include "locking.h"
 | 
			
		||||
#include "ref-cache.h"
 | 
			
		||||
#include "tree-log.h"
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
 | 
			
		||||
| 
						 | 
				
			
			@ -694,6 +695,18 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int btrfs_write_tree_block(struct extent_buffer *buf)
 | 
			
		||||
{
 | 
			
		||||
	return btrfs_fdatawrite_range(buf->first_page->mapping, buf->start,
 | 
			
		||||
				      buf->start + buf->len - 1, WB_SYNC_NONE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int btrfs_wait_tree_block_writeback(struct extent_buffer *buf)
 | 
			
		||||
{
 | 
			
		||||
	return btrfs_wait_on_page_writeback_range(buf->first_page->mapping,
 | 
			
		||||
				  buf->start, buf->start + buf->len -1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
 | 
			
		||||
				      u32 blocksize, u64 parent_transid)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -732,15 +745,6 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int wait_on_tree_block_writeback(struct btrfs_root *root,
 | 
			
		||||
				 struct extent_buffer *buf)
 | 
			
		||||
{
 | 
			
		||||
	struct inode *btree_inode = root->fs_info->btree_inode;
 | 
			
		||||
	wait_on_extent_buffer_writeback(&BTRFS_I(btree_inode)->io_tree,
 | 
			
		||||
					buf);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
 | 
			
		||||
			u32 stripesize, struct btrfs_root *root,
 | 
			
		||||
			struct btrfs_fs_info *fs_info,
 | 
			
		||||
| 
						 | 
				
			
			@ -771,6 +775,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
 | 
			
		|||
	spin_lock_init(&root->node_lock);
 | 
			
		||||
	spin_lock_init(&root->list_lock);
 | 
			
		||||
	mutex_init(&root->objectid_mutex);
 | 
			
		||||
	mutex_init(&root->log_mutex);
 | 
			
		||||
 | 
			
		||||
	btrfs_leaf_ref_tree_init(&root->ref_tree_struct);
 | 
			
		||||
	root->ref_tree = &root->ref_tree_struct;
 | 
			
		||||
| 
						 | 
				
			
			@ -809,11 +814,74 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info,
 | 
			
		||||
					       struct btrfs_key *location)
 | 
			
		||||
int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
 | 
			
		||||
			     struct btrfs_fs_info *fs_info)
 | 
			
		||||
{
 | 
			
		||||
	struct extent_buffer *eb;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!fs_info->log_root_tree)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	eb = fs_info->log_root_tree->node;
 | 
			
		||||
 | 
			
		||||
	WARN_ON(btrfs_header_level(eb) != 0);
 | 
			
		||||
	WARN_ON(btrfs_header_nritems(eb) != 0);
 | 
			
		||||
 | 
			
		||||
	ret = btrfs_free_extent(trans, fs_info->tree_root,
 | 
			
		||||
				eb->start, eb->len,
 | 
			
		||||
				BTRFS_TREE_LOG_OBJECTID, 0, 0, 0, 1);
 | 
			
		||||
	BUG_ON(ret);
 | 
			
		||||
 | 
			
		||||
	free_extent_buffer(eb);
 | 
			
		||||
	kfree(fs_info->log_root_tree);
 | 
			
		||||
	fs_info->log_root_tree = NULL;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
 | 
			
		||||
			     struct btrfs_fs_info *fs_info)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_root *root;
 | 
			
		||||
	struct btrfs_root *tree_root = fs_info->tree_root;
 | 
			
		||||
 | 
			
		||||
	root = kzalloc(sizeof(*root), GFP_NOFS);
 | 
			
		||||
	if (!root)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	__setup_root(tree_root->nodesize, tree_root->leafsize,
 | 
			
		||||
		     tree_root->sectorsize, tree_root->stripesize,
 | 
			
		||||
		     root, fs_info, BTRFS_TREE_LOG_OBJECTID);
 | 
			
		||||
 | 
			
		||||
	root->root_key.objectid = BTRFS_TREE_LOG_OBJECTID;
 | 
			
		||||
	root->root_key.type = BTRFS_ROOT_ITEM_KEY;
 | 
			
		||||
	root->root_key.offset = BTRFS_TREE_LOG_OBJECTID;
 | 
			
		||||
	root->ref_cows = 0;
 | 
			
		||||
 | 
			
		||||
	root->node = btrfs_alloc_free_block(trans, root, root->leafsize,
 | 
			
		||||
					    BTRFS_TREE_LOG_OBJECTID,
 | 
			
		||||
					    0, 0, 0, 0, 0);
 | 
			
		||||
 | 
			
		||||
	btrfs_set_header_nritems(root->node, 0);
 | 
			
		||||
	btrfs_set_header_level(root->node, 0);
 | 
			
		||||
	btrfs_set_header_bytenr(root->node, root->node->start);
 | 
			
		||||
	btrfs_set_header_generation(root->node, trans->transid);
 | 
			
		||||
	btrfs_set_header_owner(root->node, BTRFS_TREE_LOG_OBJECTID);
 | 
			
		||||
 | 
			
		||||
	write_extent_buffer(root->node, root->fs_info->fsid,
 | 
			
		||||
			    (unsigned long)btrfs_header_fsid(root->node),
 | 
			
		||||
			    BTRFS_FSID_SIZE);
 | 
			
		||||
	btrfs_mark_buffer_dirty(root->node);
 | 
			
		||||
	btrfs_tree_unlock(root->node);
 | 
			
		||||
	fs_info->log_root_tree = root;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
 | 
			
		||||
					       struct btrfs_key *location)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_root *root;
 | 
			
		||||
	struct btrfs_fs_info *fs_info = tree_root->fs_info;
 | 
			
		||||
	struct btrfs_path *path;
 | 
			
		||||
	struct extent_buffer *l;
 | 
			
		||||
	u64 highest_inode;
 | 
			
		||||
| 
						 | 
				
			
			@ -863,12 +931,14 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info,
 | 
			
		|||
				     blocksize, 0);
 | 
			
		||||
	BUG_ON(!root->node);
 | 
			
		||||
insert:
 | 
			
		||||
	if (location->objectid != BTRFS_TREE_LOG_OBJECTID) {
 | 
			
		||||
		root->ref_cows = 1;
 | 
			
		||||
		ret = btrfs_find_highest_inode(root, &highest_inode);
 | 
			
		||||
		if (ret == 0) {
 | 
			
		||||
			root->highest_inode = highest_inode;
 | 
			
		||||
			root->last_inode_alloc = highest_inode;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return root;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -907,7 +977,7 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
 | 
			
		|||
	if (root)
 | 
			
		||||
		return root;
 | 
			
		||||
 | 
			
		||||
	root = btrfs_read_fs_root_no_radix(fs_info, location);
 | 
			
		||||
	root = btrfs_read_fs_root_no_radix(fs_info->tree_root, location);
 | 
			
		||||
	if (IS_ERR(root))
 | 
			
		||||
		return root;
 | 
			
		||||
	ret = radix_tree_insert(&fs_info->fs_roots_radix,
 | 
			
		||||
| 
						 | 
				
			
			@ -1250,16 +1320,18 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 | 
			
		|||
	u32 blocksize;
 | 
			
		||||
	u32 stripesize;
 | 
			
		||||
	struct buffer_head *bh;
 | 
			
		||||
	struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root),
 | 
			
		||||
	struct btrfs_root *extent_root = kzalloc(sizeof(struct btrfs_root),
 | 
			
		||||
						 GFP_NOFS);
 | 
			
		||||
	struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root),
 | 
			
		||||
	struct btrfs_root *tree_root = kzalloc(sizeof(struct btrfs_root),
 | 
			
		||||
					       GFP_NOFS);
 | 
			
		||||
	struct btrfs_fs_info *fs_info = kzalloc(sizeof(*fs_info),
 | 
			
		||||
						GFP_NOFS);
 | 
			
		||||
	struct btrfs_root *chunk_root = kmalloc(sizeof(struct btrfs_root),
 | 
			
		||||
	struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root),
 | 
			
		||||
						GFP_NOFS);
 | 
			
		||||
	struct btrfs_root *dev_root = kmalloc(sizeof(struct btrfs_root),
 | 
			
		||||
	struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root),
 | 
			
		||||
					      GFP_NOFS);
 | 
			
		||||
	struct btrfs_root *log_tree_root;
 | 
			
		||||
 | 
			
		||||
	int ret;
 | 
			
		||||
	int err = -EINVAL;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1343,6 +1415,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 | 
			
		|||
	mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS);
 | 
			
		||||
 | 
			
		||||
	mutex_init(&fs_info->trans_mutex);
 | 
			
		||||
	mutex_init(&fs_info->tree_log_mutex);
 | 
			
		||||
	mutex_init(&fs_info->drop_mutex);
 | 
			
		||||
	mutex_init(&fs_info->alloc_mutex);
 | 
			
		||||
	mutex_init(&fs_info->chunk_mutex);
 | 
			
		||||
| 
						 | 
				
			
			@ -1352,6 +1425,10 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 | 
			
		|||
	init_waitqueue_head(&fs_info->transaction_throttle);
 | 
			
		||||
	init_waitqueue_head(&fs_info->transaction_wait);
 | 
			
		||||
	init_waitqueue_head(&fs_info->async_submit_wait);
 | 
			
		||||
	init_waitqueue_head(&fs_info->tree_log_wait);
 | 
			
		||||
	atomic_set(&fs_info->tree_log_commit, 0);
 | 
			
		||||
	atomic_set(&fs_info->tree_log_writers, 0);
 | 
			
		||||
	fs_info->tree_log_transid = 0;
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
	ret = add_hasher(fs_info, "crc32c");
 | 
			
		||||
| 
						 | 
				
			
			@ -1532,7 +1609,26 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 | 
			
		|||
	if (!fs_info->transaction_kthread)
 | 
			
		||||
		goto fail_cleaner;
 | 
			
		||||
 | 
			
		||||
	if (btrfs_super_log_root(disk_super) != 0) {
 | 
			
		||||
		u32 blocksize;
 | 
			
		||||
		u64 bytenr = btrfs_super_log_root(disk_super);
 | 
			
		||||
 | 
			
		||||
		blocksize =
 | 
			
		||||
		     btrfs_level_size(tree_root,
 | 
			
		||||
				      btrfs_super_log_root_level(disk_super));
 | 
			
		||||
 | 
			
		||||
		log_tree_root = kzalloc(sizeof(struct btrfs_root),
 | 
			
		||||
						      GFP_NOFS);
 | 
			
		||||
 | 
			
		||||
		__setup_root(nodesize, leafsize, sectorsize, stripesize,
 | 
			
		||||
			     log_tree_root, fs_info, BTRFS_TREE_LOG_OBJECTID);
 | 
			
		||||
 | 
			
		||||
		log_tree_root->node = read_tree_block(tree_root, bytenr,
 | 
			
		||||
						      blocksize, 0);
 | 
			
		||||
		ret = btrfs_recover_log_trees(log_tree_root);
 | 
			
		||||
		BUG_ON(ret);
 | 
			
		||||
	}
 | 
			
		||||
	fs_info->last_trans_committed = btrfs_super_generation(disk_super);
 | 
			
		||||
	return tree_root;
 | 
			
		||||
 | 
			
		||||
fail_cleaner:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
 | 
			
		|||
struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
 | 
			
		||||
				      struct btrfs_key *location,
 | 
			
		||||
				      const char *name, int namelen);
 | 
			
		||||
struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info,
 | 
			
		||||
struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
 | 
			
		||||
					       struct btrfs_key *location);
 | 
			
		||||
struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
 | 
			
		||||
					      struct btrfs_key *location);
 | 
			
		||||
| 
						 | 
				
			
			@ -74,4 +74,10 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode,
 | 
			
		|||
			extent_submit_bio_hook_t *submit_bio_hook);
 | 
			
		||||
int btrfs_congested_async(struct btrfs_fs_info *info, int iodone);
 | 
			
		||||
unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info);
 | 
			
		||||
int btrfs_write_tree_block(struct extent_buffer *buf);
 | 
			
		||||
int btrfs_wait_tree_block_writeback(struct extent_buffer *buf);
 | 
			
		||||
int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
 | 
			
		||||
			     struct btrfs_fs_info *fs_info);
 | 
			
		||||
int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
 | 
			
		||||
			     struct btrfs_fs_info *fs_info);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -496,6 +496,23 @@ static int match_extent_ref(struct extent_buffer *leaf,
 | 
			
		|||
	return ret == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* simple helper to search for an existing extent at a given offset */
 | 
			
		||||
int btrfs_lookup_extent(struct btrfs_root *root, struct btrfs_path *path,
 | 
			
		||||
			u64 start, u64 len)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct btrfs_key key;
 | 
			
		||||
 | 
			
		||||
	maybe_lock_mutex(root);
 | 
			
		||||
	key.objectid = start;
 | 
			
		||||
	key.offset = len;
 | 
			
		||||
	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
 | 
			
		||||
	ret = btrfs_search_slot(NULL, root->fs_info->extent_root, &key, path,
 | 
			
		||||
				0, 0);
 | 
			
		||||
	maybe_unlock_mutex(root);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int noinline lookup_extent_backref(struct btrfs_trans_handle *trans,
 | 
			
		||||
					  struct btrfs_root *root,
 | 
			
		||||
					  struct btrfs_path *path, u64 bytenr,
 | 
			
		||||
| 
						 | 
				
			
			@ -1409,7 +1426,7 @@ static u64 first_logical_byte(struct btrfs_root *root, u64 search_start)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int update_pinned_extents(struct btrfs_root *root,
 | 
			
		||||
int btrfs_update_pinned_extents(struct btrfs_root *root,
 | 
			
		||||
				u64 bytenr, u64 num, int pin)
 | 
			
		||||
{
 | 
			
		||||
	u64 len;
 | 
			
		||||
| 
						 | 
				
			
			@ -1492,7 +1509,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
 | 
			
		|||
					    EXTENT_DIRTY);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			break;
 | 
			
		||||
		update_pinned_extents(root, start, end + 1 - start, 0);
 | 
			
		||||
		btrfs_update_pinned_extents(root, start, end + 1 - start, 0);
 | 
			
		||||
		clear_extent_dirty(unpin, start, end, GFP_NOFS);
 | 
			
		||||
		set_extent_dirty(free_space_cache, start, end, GFP_NOFS);
 | 
			
		||||
		if (need_resched()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1538,14 +1555,11 @@ static int finish_current_insert(struct btrfs_trans_handle *trans,
 | 
			
		|||
		clear_extent_bits(&info->extent_ins, start, end, EXTENT_LOCKED,
 | 
			
		||||
				  GFP_NOFS);
 | 
			
		||||
 | 
			
		||||
		eb = btrfs_find_tree_block(extent_root, ins.objectid,
 | 
			
		||||
		eb = btrfs_find_create_tree_block(extent_root, ins.objectid,
 | 
			
		||||
					   ins.offset);
 | 
			
		||||
 | 
			
		||||
		if (!btrfs_buffer_uptodate(eb, trans->transid)) {
 | 
			
		||||
			mutex_unlock(&extent_root->fs_info->alloc_mutex);
 | 
			
		||||
		if (!btrfs_buffer_uptodate(eb, trans->transid))
 | 
			
		||||
			btrfs_read_buffer(eb, trans->transid);
 | 
			
		||||
			mutex_lock(&extent_root->fs_info->alloc_mutex);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		btrfs_tree_lock(eb);
 | 
			
		||||
		level = btrfs_header_level(eb);
 | 
			
		||||
| 
						 | 
				
			
			@ -1585,13 +1599,20 @@ static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes,
 | 
			
		|||
		struct extent_buffer *buf;
 | 
			
		||||
		buf = btrfs_find_tree_block(root, bytenr, num_bytes);
 | 
			
		||||
		if (buf) {
 | 
			
		||||
			/* we can reuse a block if it hasn't been written
 | 
			
		||||
			 * and it is from this transaction.  We can't
 | 
			
		||||
			 * reuse anything from the tree log root because
 | 
			
		||||
			 * it has tiny sub-transactions.
 | 
			
		||||
			 */
 | 
			
		||||
			if (btrfs_buffer_uptodate(buf, 0) &&
 | 
			
		||||
			    btrfs_try_tree_lock(buf)) {
 | 
			
		||||
				u64 transid =
 | 
			
		||||
				    root->fs_info->running_transaction->transid;
 | 
			
		||||
				u64 header_transid =
 | 
			
		||||
					btrfs_header_generation(buf);
 | 
			
		||||
				if (header_transid == transid &&
 | 
			
		||||
				if (btrfs_header_owner(buf) !=
 | 
			
		||||
				    BTRFS_TREE_LOG_OBJECTID &&
 | 
			
		||||
				    header_transid == transid &&
 | 
			
		||||
				    !btrfs_header_flag(buf,
 | 
			
		||||
					       BTRFS_HEADER_FLAG_WRITTEN)) {
 | 
			
		||||
					clean_tree_block(NULL, root, buf);
 | 
			
		||||
| 
						 | 
				
			
			@ -1603,7 +1624,7 @@ static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes,
 | 
			
		|||
			}
 | 
			
		||||
			free_extent_buffer(buf);
 | 
			
		||||
		}
 | 
			
		||||
		update_pinned_extents(root, bytenr, num_bytes, 1);
 | 
			
		||||
		btrfs_update_pinned_extents(root, bytenr, num_bytes, 1);
 | 
			
		||||
	} else {
 | 
			
		||||
		set_extent_bits(&root->fs_info->pending_del,
 | 
			
		||||
				bytenr, bytenr + num_bytes - 1,
 | 
			
		||||
| 
						 | 
				
			
			@ -1801,7 +1822,7 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
 | 
			
		|||
				  GFP_NOFS);
 | 
			
		||||
		if (!test_range_bit(&extent_root->fs_info->extent_ins,
 | 
			
		||||
				    start, end, EXTENT_LOCKED, 0)) {
 | 
			
		||||
			update_pinned_extents(extent_root, start,
 | 
			
		||||
			btrfs_update_pinned_extents(extent_root, start,
 | 
			
		||||
					      end + 1 - start, 1);
 | 
			
		||||
			ret = __free_extent(trans, extent_root,
 | 
			
		||||
					     start, end + 1 - start,
 | 
			
		||||
| 
						 | 
				
			
			@ -1919,6 +1940,12 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
 | 
			
		|||
	if ((data & BTRFS_BLOCK_GROUP_DATA) && btrfs_test_opt(root, SSD)) {
 | 
			
		||||
		last_ptr = &root->fs_info->last_data_alloc;
 | 
			
		||||
	}
 | 
			
		||||
	if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
 | 
			
		||||
		last_ptr = &root->fs_info->last_log_alloc;
 | 
			
		||||
		if (!last_ptr == 0 && root->fs_info->last_alloc) {
 | 
			
		||||
			*last_ptr = root->fs_info->last_alloc + empty_cluster;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (last_ptr) {
 | 
			
		||||
		if (*last_ptr)
 | 
			
		||||
| 
						 | 
				
			
			@ -2268,6 +2295,35 @@ int btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
 | 
			
		|||
	maybe_unlock_mutex(root);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * this is used by the tree logging recovery code.  It records that
 | 
			
		||||
 * an extent has been allocated and makes sure to clear the free
 | 
			
		||||
 * space cache bits as well
 | 
			
		||||
 */
 | 
			
		||||
int btrfs_alloc_logged_extent(struct btrfs_trans_handle *trans,
 | 
			
		||||
				struct btrfs_root *root,
 | 
			
		||||
				u64 root_objectid, u64 ref_generation,
 | 
			
		||||
				u64 owner, u64 owner_offset,
 | 
			
		||||
				struct btrfs_key *ins)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct btrfs_block_group_cache *block_group;
 | 
			
		||||
 | 
			
		||||
	maybe_lock_mutex(root);
 | 
			
		||||
	block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid);
 | 
			
		||||
	cache_block_group(root, block_group);
 | 
			
		||||
 | 
			
		||||
	clear_extent_dirty(&root->fs_info->free_space_cache,
 | 
			
		||||
			   ins->objectid, ins->objectid + ins->offset - 1,
 | 
			
		||||
			   GFP_NOFS);
 | 
			
		||||
	ret = __btrfs_alloc_reserved_extent(trans, root, root_objectid,
 | 
			
		||||
					    ref_generation, owner,
 | 
			
		||||
					    owner_offset, ins);
 | 
			
		||||
	maybe_unlock_mutex(root);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * finds a free extent and does all the dirty work required for allocation
 | 
			
		||||
 * returns the key for the extent through ins, and a tree buffer for
 | 
			
		||||
| 
						 | 
				
			
			@ -2350,9 +2406,8 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
 | 
			
		|||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int noinline drop_leaf_ref_no_cache(struct btrfs_trans_handle *trans,
 | 
			
		||||
					   struct btrfs_root *root,
 | 
			
		||||
					   struct extent_buffer *leaf)
 | 
			
		||||
int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
 | 
			
		||||
			struct btrfs_root *root, struct extent_buffer *leaf)
 | 
			
		||||
{
 | 
			
		||||
	u64 leaf_owner;
 | 
			
		||||
	u64 leaf_generation;
 | 
			
		||||
| 
						 | 
				
			
			@ -2402,7 +2457,7 @@ static int noinline drop_leaf_ref_no_cache(struct btrfs_trans_handle *trans,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int noinline drop_leaf_ref(struct btrfs_trans_handle *trans,
 | 
			
		||||
static int noinline cache_drop_leaf_ref(struct btrfs_trans_handle *trans,
 | 
			
		||||
					struct btrfs_root *root,
 | 
			
		||||
					struct btrfs_leaf_ref *ref)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -2512,7 +2567,7 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
 | 
			
		|||
		    btrfs_header_nritems(cur))
 | 
			
		||||
			break;
 | 
			
		||||
		if (*level == 0) {
 | 
			
		||||
			ret = drop_leaf_ref_no_cache(trans, root, cur);
 | 
			
		||||
			ret = btrfs_drop_leaf_ref(trans, root, cur);
 | 
			
		||||
			BUG_ON(ret);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -2552,7 +2607,7 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
 | 
			
		|||
			btrfs_node_key_to_cpu(cur, &key, path->slots[*level]);
 | 
			
		||||
			ref = btrfs_lookup_leaf_ref(root, bytenr);
 | 
			
		||||
			if (ref) {
 | 
			
		||||
				ret = drop_leaf_ref(trans, root, ref);
 | 
			
		||||
				ret = cache_drop_leaf_ref(trans, root, ref);
 | 
			
		||||
				BUG_ON(ret);
 | 
			
		||||
				btrfs_remove_leaf_ref(root, ref);
 | 
			
		||||
				btrfs_free_leaf_ref(root, ref);
 | 
			
		||||
| 
						 | 
				
			
			@ -3628,6 +3683,8 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
 | 
			
		|||
	extent_root = root->fs_info->extent_root;
 | 
			
		||||
	block_group_cache = &root->fs_info->block_group_cache;
 | 
			
		||||
 | 
			
		||||
	root->fs_info->last_trans_new_blockgroup = trans->transid;
 | 
			
		||||
 | 
			
		||||
	cache = kzalloc(sizeof(*cache), GFP_NOFS);
 | 
			
		||||
	BUG_ON(!cache);
 | 
			
		||||
	cache->key.objectid = chunk_offset;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,8 @@
 | 
			
		|||
#include "btrfs_inode.h"
 | 
			
		||||
#include "ioctl.h"
 | 
			
		||||
#include "print-tree.h"
 | 
			
		||||
#include "tree-log.h"
 | 
			
		||||
#include "locking.h"
 | 
			
		||||
#include "compat.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -988,10 +990,27 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
 | 
			
		|||
	*ppos = pos;
 | 
			
		||||
 | 
			
		||||
	if (num_written > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
 | 
			
		||||
		err = sync_page_range(inode, inode->i_mapping,
 | 
			
		||||
				      start_pos, num_written);
 | 
			
		||||
		struct btrfs_trans_handle *trans;
 | 
			
		||||
 | 
			
		||||
		err = btrfs_fdatawrite_range(inode->i_mapping, start_pos,
 | 
			
		||||
					     start_pos + num_written -1,
 | 
			
		||||
					     WB_SYNC_NONE);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
			num_written = err;
 | 
			
		||||
 | 
			
		||||
		err = btrfs_wait_on_page_writeback_range(inode->i_mapping,
 | 
			
		||||
				 start_pos, start_pos + num_written - 1);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
			num_written = err;
 | 
			
		||||
 | 
			
		||||
		trans = btrfs_start_transaction(root, 1);
 | 
			
		||||
		ret = btrfs_log_dentry_safe(trans, root, file->f_dentry);
 | 
			
		||||
		if (ret == 0) {
 | 
			
		||||
			btrfs_sync_log(trans, root);
 | 
			
		||||
			btrfs_end_transaction(trans, root);
 | 
			
		||||
		} else {
 | 
			
		||||
			btrfs_commit_transaction(trans, root);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (num_written > 0 && (file->f_flags & O_DIRECT)) {
 | 
			
		||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
 | 
			
		||||
		do_sync_file_range(file, start_pos,
 | 
			
		||||
| 
						 | 
				
			
			@ -1019,8 +1038,7 @@ int btrfs_release_file(struct inode * inode, struct file * filp)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int btrfs_sync_file(struct file *file,
 | 
			
		||||
			   struct dentry *dentry, int datasync)
 | 
			
		||||
int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
 | 
			
		||||
{
 | 
			
		||||
	struct inode *inode = dentry->d_inode;
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(inode)->root;
 | 
			
		||||
| 
						 | 
				
			
			@ -1043,6 +1061,8 @@ static int btrfs_sync_file(struct file *file,
 | 
			
		|||
	}
 | 
			
		||||
	mutex_unlock(&root->fs_info->trans_mutex);
 | 
			
		||||
 | 
			
		||||
	filemap_fdatawait(inode->i_mapping);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * ok we haven't committed the transaction yet, lets do a commit
 | 
			
		||||
	 */
 | 
			
		||||
| 
						 | 
				
			
			@ -1054,7 +1074,16 @@ static int btrfs_sync_file(struct file *file,
 | 
			
		|||
		ret = -ENOMEM;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = btrfs_log_dentry_safe(trans, root, file->f_dentry);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		goto out;
 | 
			
		||||
	if (ret > 0) {
 | 
			
		||||
		ret = btrfs_commit_transaction(trans, root);
 | 
			
		||||
	} else {
 | 
			
		||||
		btrfs_sync_log(trans, root);
 | 
			
		||||
		ret = btrfs_end_transaction(trans, root);
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	return ret > 0 ? EIO : ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										239
									
								
								fs/btrfs/inode.c
									
									
									
									
									
								
							
							
						
						
									
										239
									
								
								fs/btrfs/inode.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -46,6 +46,8 @@
 | 
			
		|||
#include "volumes.h"
 | 
			
		||||
#include "ordered-data.h"
 | 
			
		||||
#include "xattr.h"
 | 
			
		||||
#include "compat.h"
 | 
			
		||||
#include "tree-log.h"
 | 
			
		||||
 | 
			
		||||
struct btrfs_iget_args {
 | 
			
		||||
	u64 ino;
 | 
			
		||||
| 
						 | 
				
			
			@ -586,6 +588,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
 | 
			
		|||
			  &ordered_extent->list);
 | 
			
		||||
 | 
			
		||||
	btrfs_ordered_update_i_size(inode, ordered_extent);
 | 
			
		||||
	btrfs_update_inode(trans, root, inode);
 | 
			
		||||
	btrfs_remove_ordered_extent(inode, ordered_extent);
 | 
			
		||||
 | 
			
		||||
	/* once for us */
 | 
			
		||||
| 
						 | 
				
			
			@ -593,7 +596,6 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
 | 
			
		|||
	/* once for the tree */
 | 
			
		||||
	btrfs_put_ordered_extent(ordered_extent);
 | 
			
		||||
 | 
			
		||||
	btrfs_update_inode(trans, root, inode);
 | 
			
		||||
	btrfs_end_transaction(trans, root);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1007,7 +1009,8 @@ void btrfs_read_locked_inode(struct inode *inode)
 | 
			
		|||
	inode->i_ctime.tv_nsec = btrfs_timespec_nsec(leaf, tspec);
 | 
			
		||||
 | 
			
		||||
	inode->i_blocks = btrfs_inode_nblocks(leaf, inode_item);
 | 
			
		||||
	inode->i_generation = btrfs_inode_generation(leaf, inode_item);
 | 
			
		||||
	BTRFS_I(inode)->generation = btrfs_inode_generation(leaf, inode_item);
 | 
			
		||||
	inode->i_generation = BTRFS_I(inode)->generation;
 | 
			
		||||
	inode->i_rdev = 0;
 | 
			
		||||
	rdev = btrfs_inode_rdev(leaf, inode_item);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1056,7 +1059,8 @@ void btrfs_read_locked_inode(struct inode *inode)
 | 
			
		|||
	make_bad_inode(inode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void fill_inode_item(struct extent_buffer *leaf,
 | 
			
		||||
static void fill_inode_item(struct btrfs_trans_handle *trans,
 | 
			
		||||
			    struct extent_buffer *leaf,
 | 
			
		||||
			    struct btrfs_inode_item *item,
 | 
			
		||||
			    struct inode *inode)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1082,7 +1086,8 @@ static void fill_inode_item(struct extent_buffer *leaf,
 | 
			
		|||
				inode->i_ctime.tv_nsec);
 | 
			
		||||
 | 
			
		||||
	btrfs_set_inode_nblocks(leaf, item, inode->i_blocks);
 | 
			
		||||
	btrfs_set_inode_generation(leaf, item, inode->i_generation);
 | 
			
		||||
	btrfs_set_inode_generation(leaf, item, BTRFS_I(inode)->generation);
 | 
			
		||||
	btrfs_set_inode_transid(leaf, item, trans->transid);
 | 
			
		||||
	btrfs_set_inode_rdev(leaf, item, inode->i_rdev);
 | 
			
		||||
	btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags);
 | 
			
		||||
	btrfs_set_inode_block_group(leaf, item,
 | 
			
		||||
| 
						 | 
				
			
			@ -1112,7 +1117,7 @@ int noinline btrfs_update_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
	inode_item = btrfs_item_ptr(leaf, path->slots[0],
 | 
			
		||||
				  struct btrfs_inode_item);
 | 
			
		||||
 | 
			
		||||
	fill_inode_item(leaf, inode_item, inode);
 | 
			
		||||
	fill_inode_item(trans, leaf, inode_item, inode);
 | 
			
		||||
	btrfs_mark_buffer_dirty(leaf);
 | 
			
		||||
	btrfs_set_inode_last_trans(trans, inode);
 | 
			
		||||
	ret = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1122,14 +1127,12 @@ int noinline btrfs_update_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int btrfs_unlink_trans(struct btrfs_trans_handle *trans,
 | 
			
		||||
int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
 | 
			
		||||
		       struct btrfs_root *root,
 | 
			
		||||
			      struct inode *dir,
 | 
			
		||||
			      struct dentry *dentry)
 | 
			
		||||
		       struct inode *dir, struct inode *inode,
 | 
			
		||||
		       const char *name, int name_len)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_path *path;
 | 
			
		||||
	const char *name = dentry->d_name.name;
 | 
			
		||||
	int name_len = dentry->d_name.len;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
	struct extent_buffer *leaf;
 | 
			
		||||
	struct btrfs_dir_item *di;
 | 
			
		||||
| 
						 | 
				
			
			@ -1160,13 +1163,12 @@ static int btrfs_unlink_trans(struct btrfs_trans_handle *trans,
 | 
			
		|||
	btrfs_release_path(root, path);
 | 
			
		||||
 | 
			
		||||
	ret = btrfs_del_inode_ref(trans, root, name, name_len,
 | 
			
		||||
				  dentry->d_inode->i_ino,
 | 
			
		||||
				  dentry->d_parent->d_inode->i_ino, &index);
 | 
			
		||||
				  inode->i_ino,
 | 
			
		||||
				  dir->i_ino, &index);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		printk("failed to delete reference to %.*s, "
 | 
			
		||||
		       "inode %lu parent %lu\n", name_len, name,
 | 
			
		||||
		       dentry->d_inode->i_ino,
 | 
			
		||||
		       dentry->d_parent->d_inode->i_ino);
 | 
			
		||||
		       inode->i_ino, dir->i_ino);
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1183,21 +1185,25 @@ static int btrfs_unlink_trans(struct btrfs_trans_handle *trans,
 | 
			
		|||
	ret = btrfs_delete_one_dir_name(trans, root, path, di);
 | 
			
		||||
	btrfs_release_path(root, path);
 | 
			
		||||
 | 
			
		||||
	dentry->d_inode->i_ctime = dir->i_ctime;
 | 
			
		||||
	ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len,
 | 
			
		||||
					 inode, dir->i_ino);
 | 
			
		||||
	BUG_ON(ret);
 | 
			
		||||
 | 
			
		||||
	ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len,
 | 
			
		||||
					   dir, index);
 | 
			
		||||
	BUG_ON(ret);
 | 
			
		||||
err:
 | 
			
		||||
	btrfs_free_path(path);
 | 
			
		||||
	if (!ret) {
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	btrfs_i_size_write(dir, dir->i_size - name_len * 2);
 | 
			
		||||
		dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 | 
			
		||||
	inode->i_ctime = dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 | 
			
		||||
	btrfs_update_inode(trans, root, dir);
 | 
			
		||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
 | 
			
		||||
		dentry->d_inode->i_nlink--;
 | 
			
		||||
#else
 | 
			
		||||
		drop_nlink(dentry->d_inode);
 | 
			
		||||
#endif
 | 
			
		||||
		ret = btrfs_update_inode(trans, root, dentry->d_inode);
 | 
			
		||||
	btrfs_drop_nlink(inode);
 | 
			
		||||
	ret = btrfs_update_inode(trans, root, inode);
 | 
			
		||||
	dir->i_sb->s_dirt = 1;
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1218,7 +1224,8 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
 | 
			
		|||
	trans = btrfs_start_transaction(root, 1);
 | 
			
		||||
 | 
			
		||||
	btrfs_set_trans_block_group(trans, dir);
 | 
			
		||||
	ret = btrfs_unlink_trans(trans, root, dir, dentry);
 | 
			
		||||
	ret = btrfs_unlink_inode(trans, root, dir, dentry->d_inode,
 | 
			
		||||
				 dentry->d_name.name, dentry->d_name.len);
 | 
			
		||||
 | 
			
		||||
	if (inode->i_nlink == 0)
 | 
			
		||||
		ret = btrfs_orphan_add(trans, inode);
 | 
			
		||||
| 
						 | 
				
			
			@ -1256,7 +1263,8 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
 | 
			
		|||
		goto fail_trans;
 | 
			
		||||
 | 
			
		||||
	/* now the directory is empty */
 | 
			
		||||
	err = btrfs_unlink_trans(trans, root, dir, dentry);
 | 
			
		||||
	err = btrfs_unlink_inode(trans, root, dir, dentry->d_inode,
 | 
			
		||||
				 dentry->d_name.name, dentry->d_name.len);
 | 
			
		||||
	if (!err) {
 | 
			
		||||
		btrfs_i_size_write(inode, 0);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1283,10 +1291,10 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
 | 
			
		|||
 * min_type is the minimum key type to truncate down to.  If set to 0, this
 | 
			
		||||
 * will kill all the items on this inode, including the INODE_ITEM_KEY.
 | 
			
		||||
 */
 | 
			
		||||
static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
 | 
			
		||||
noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
 | 
			
		||||
					struct btrfs_root *root,
 | 
			
		||||
					struct inode *inode,
 | 
			
		||||
				   u32 min_type)
 | 
			
		||||
					u64 new_size, u32 min_type)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct btrfs_path *path;
 | 
			
		||||
| 
						 | 
				
			
			@ -1307,7 +1315,9 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
 | 
			
		|||
	int extent_type = -1;
 | 
			
		||||
	u64 mask = root->sectorsize - 1;
 | 
			
		||||
 | 
			
		||||
	btrfs_drop_extent_cache(inode, inode->i_size & (~mask), (u64)-1);
 | 
			
		||||
	if (root->ref_cows)
 | 
			
		||||
		btrfs_drop_extent_cache(inode,
 | 
			
		||||
					new_size & (~mask), (u64)-1);
 | 
			
		||||
	path = btrfs_alloc_path();
 | 
			
		||||
	path->reada = -1;
 | 
			
		||||
	BUG_ON(!path);
 | 
			
		||||
| 
						 | 
				
			
			@ -1324,7 +1334,13 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
 | 
			
		|||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
	if (ret > 0) {
 | 
			
		||||
		BUG_ON(path->slots[0] == 0);
 | 
			
		||||
		/* there are no items in the tree for us to truncate, we're
 | 
			
		||||
		 * done
 | 
			
		||||
		 */
 | 
			
		||||
		if (path->slots[0] == 0) {
 | 
			
		||||
			ret = 0;
 | 
			
		||||
			goto error;
 | 
			
		||||
		}
 | 
			
		||||
		path->slots[0]--;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1358,10 +1374,10 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
 | 
			
		|||
		}
 | 
			
		||||
		if (found_type == BTRFS_CSUM_ITEM_KEY) {
 | 
			
		||||
			ret = btrfs_csum_truncate(trans, root, path,
 | 
			
		||||
						  inode->i_size);
 | 
			
		||||
						  new_size);
 | 
			
		||||
			BUG_ON(ret);
 | 
			
		||||
		}
 | 
			
		||||
		if (item_end < inode->i_size) {
 | 
			
		||||
		if (item_end < new_size) {
 | 
			
		||||
			if (found_type == BTRFS_DIR_ITEM_KEY) {
 | 
			
		||||
				found_type = BTRFS_INODE_ITEM_KEY;
 | 
			
		||||
			} else if (found_type == BTRFS_EXTENT_ITEM_KEY) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1378,7 +1394,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
 | 
			
		|||
			btrfs_set_key_type(&key, found_type);
 | 
			
		||||
			goto next;
 | 
			
		||||
		}
 | 
			
		||||
		if (found_key.offset >= inode->i_size)
 | 
			
		||||
		if (found_key.offset >= new_size)
 | 
			
		||||
			del_item = 1;
 | 
			
		||||
		else
 | 
			
		||||
			del_item = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -1394,7 +1410,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
 | 
			
		|||
			if (!del_item) {
 | 
			
		||||
				u64 orig_num_bytes =
 | 
			
		||||
					btrfs_file_extent_num_bytes(leaf, fi);
 | 
			
		||||
				extent_num_bytes = inode->i_size -
 | 
			
		||||
				extent_num_bytes = new_size -
 | 
			
		||||
					found_key.offset + root->sectorsize - 1;
 | 
			
		||||
				extent_num_bytes = extent_num_bytes &
 | 
			
		||||
					~((u64)root->sectorsize - 1);
 | 
			
		||||
| 
						 | 
				
			
			@ -1402,7 +1418,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
 | 
			
		|||
							 extent_num_bytes);
 | 
			
		||||
				num_dec = (orig_num_bytes -
 | 
			
		||||
					   extent_num_bytes);
 | 
			
		||||
				if (extent_start != 0)
 | 
			
		||||
				if (root->ref_cows && extent_start != 0)
 | 
			
		||||
					dec_i_blocks(inode, num_dec);
 | 
			
		||||
				btrfs_mark_buffer_dirty(leaf);
 | 
			
		||||
			} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1413,22 +1429,29 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
 | 
			
		|||
				num_dec = btrfs_file_extent_num_bytes(leaf, fi);
 | 
			
		||||
				if (extent_start != 0) {
 | 
			
		||||
					found_extent = 1;
 | 
			
		||||
					if (root->ref_cows)
 | 
			
		||||
						dec_i_blocks(inode, num_dec);
 | 
			
		||||
				}
 | 
			
		||||
				root_gen = btrfs_header_generation(leaf);
 | 
			
		||||
				if (root->ref_cows) {
 | 
			
		||||
					root_gen =
 | 
			
		||||
						btrfs_header_generation(leaf);
 | 
			
		||||
				}
 | 
			
		||||
				root_owner = btrfs_header_owner(leaf);
 | 
			
		||||
			}
 | 
			
		||||
		} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
 | 
			
		||||
			if (!del_item) {
 | 
			
		||||
				u32 newsize = inode->i_size - found_key.offset;
 | 
			
		||||
				u32 size = new_size - found_key.offset;
 | 
			
		||||
 | 
			
		||||
				if (root->ref_cows) {
 | 
			
		||||
					dec_i_blocks(inode, item_end + 1 -
 | 
			
		||||
					    found_key.offset - newsize);
 | 
			
		||||
				newsize =
 | 
			
		||||
				    btrfs_file_extent_calc_inline_size(newsize);
 | 
			
		||||
						    found_key.offset - size);
 | 
			
		||||
				}
 | 
			
		||||
				size =
 | 
			
		||||
				    btrfs_file_extent_calc_inline_size(size);
 | 
			
		||||
				ret = btrfs_truncate_item(trans, root, path,
 | 
			
		||||
							  newsize, 1);
 | 
			
		||||
							  size, 1);
 | 
			
		||||
				BUG_ON(ret);
 | 
			
		||||
			} else {
 | 
			
		||||
			} else if (root->ref_cows) {
 | 
			
		||||
				dec_i_blocks(inode, item_end + 1 -
 | 
			
		||||
					     found_key.offset);
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -1666,7 +1689,7 @@ void btrfs_delete_inode(struct inode *inode)
 | 
			
		|||
	trans = btrfs_start_transaction(root, 1);
 | 
			
		||||
 | 
			
		||||
	btrfs_set_trans_block_group(trans, inode);
 | 
			
		||||
	ret = btrfs_truncate_in_trans(trans, root, inode, 0);
 | 
			
		||||
	ret = btrfs_truncate_inode_items(trans, root, inode, inode->i_size, 0);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		btrfs_orphan_del(NULL, inode);
 | 
			
		||||
		goto no_delete_lock;
 | 
			
		||||
| 
						 | 
				
			
			@ -1753,15 +1776,20 @@ static int fixup_tree_root_location(struct btrfs_root *root,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int btrfs_init_locked_inode(struct inode *inode, void *p)
 | 
			
		||||
static noinline void init_btrfs_i(struct inode *inode)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_iget_args *args = p;
 | 
			
		||||
	inode->i_ino = args->ino;
 | 
			
		||||
	BTRFS_I(inode)->root = args->root;
 | 
			
		||||
	BTRFS_I(inode)->delalloc_bytes = 0;
 | 
			
		||||
	inode->i_mapping->writeback_index = 0;
 | 
			
		||||
	BTRFS_I(inode)->disk_i_size = 0;
 | 
			
		||||
	BTRFS_I(inode)->index_cnt = (u64)-1;
 | 
			
		||||
	struct btrfs_inode *bi = BTRFS_I(inode);
 | 
			
		||||
 | 
			
		||||
	bi->i_acl = NULL;
 | 
			
		||||
	bi->i_default_acl = NULL;
 | 
			
		||||
 | 
			
		||||
	bi->generation = 0;
 | 
			
		||||
	bi->last_trans = 0;
 | 
			
		||||
	bi->logged_trans = 0;
 | 
			
		||||
	bi->delalloc_bytes = 0;
 | 
			
		||||
	bi->disk_i_size = 0;
 | 
			
		||||
	bi->flags = 0;
 | 
			
		||||
	bi->index_cnt = (u64)-1;
 | 
			
		||||
	extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
 | 
			
		||||
	extent_io_tree_init(&BTRFS_I(inode)->io_tree,
 | 
			
		||||
			     inode->i_mapping, GFP_NOFS);
 | 
			
		||||
| 
						 | 
				
			
			@ -1771,6 +1799,15 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p)
 | 
			
		|||
	btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
 | 
			
		||||
	mutex_init(&BTRFS_I(inode)->csum_mutex);
 | 
			
		||||
	mutex_init(&BTRFS_I(inode)->extent_mutex);
 | 
			
		||||
	mutex_init(&BTRFS_I(inode)->log_mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int btrfs_init_locked_inode(struct inode *inode, void *p)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_iget_args *args = p;
 | 
			
		||||
	inode->i_ino = args->ino;
 | 
			
		||||
	init_btrfs_i(inode);
 | 
			
		||||
	BTRFS_I(inode)->root = args->root;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2263,21 +2300,10 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
	 * btrfs_get_inode_index_count has an explanation for the magic
 | 
			
		||||
	 * number
 | 
			
		||||
	 */
 | 
			
		||||
	init_btrfs_i(inode);
 | 
			
		||||
	BTRFS_I(inode)->index_cnt = 2;
 | 
			
		||||
 | 
			
		||||
	extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
 | 
			
		||||
	extent_io_tree_init(&BTRFS_I(inode)->io_tree,
 | 
			
		||||
			     inode->i_mapping, GFP_NOFS);
 | 
			
		||||
	extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree,
 | 
			
		||||
			     inode->i_mapping, GFP_NOFS);
 | 
			
		||||
	btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
 | 
			
		||||
	INIT_LIST_HEAD(&BTRFS_I(inode)->delalloc_inodes);
 | 
			
		||||
	mutex_init(&BTRFS_I(inode)->csum_mutex);
 | 
			
		||||
	mutex_init(&BTRFS_I(inode)->extent_mutex);
 | 
			
		||||
	BTRFS_I(inode)->delalloc_bytes = 0;
 | 
			
		||||
	inode->i_mapping->writeback_index = 0;
 | 
			
		||||
	BTRFS_I(inode)->disk_i_size = 0;
 | 
			
		||||
	BTRFS_I(inode)->root = root;
 | 
			
		||||
	BTRFS_I(inode)->generation = trans->transid;
 | 
			
		||||
 | 
			
		||||
	if (mode & S_IFDIR)
 | 
			
		||||
		owner = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -2290,7 +2316,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
		new_inode_group = group;
 | 
			
		||||
	}
 | 
			
		||||
	BTRFS_I(inode)->block_group = new_inode_group;
 | 
			
		||||
	BTRFS_I(inode)->flags = 0;
 | 
			
		||||
 | 
			
		||||
	key[0].objectid = objectid;
 | 
			
		||||
	btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY);
 | 
			
		||||
| 
						 | 
				
			
			@ -2318,7 +2343,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 | 
			
		||||
	inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
 | 
			
		||||
				  struct btrfs_inode_item);
 | 
			
		||||
	fill_inode_item(path->nodes[0], inode_item, inode);
 | 
			
		||||
	fill_inode_item(trans, path->nodes[0], inode_item, inode);
 | 
			
		||||
 | 
			
		||||
	ref = btrfs_item_ptr(path->nodes[0], path->slots[0] + 1,
 | 
			
		||||
			     struct btrfs_inode_ref);
 | 
			
		||||
| 
						 | 
				
			
			@ -2349,38 +2374,34 @@ static inline u8 btrfs_inode_type(struct inode *inode)
 | 
			
		|||
	return btrfs_type_by_mode[(inode->i_mode & S_IFMT) >> S_SHIFT];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int btrfs_add_link(struct btrfs_trans_handle *trans,
 | 
			
		||||
			    struct dentry *dentry, struct inode *inode,
 | 
			
		||||
			    int add_backref, u64 index)
 | 
			
		||||
int btrfs_add_link(struct btrfs_trans_handle *trans,
 | 
			
		||||
		   struct inode *parent_inode, struct inode *inode,
 | 
			
		||||
		   const char *name, int name_len, int add_backref, u64 index)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct btrfs_key key;
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(dentry->d_parent->d_inode)->root;
 | 
			
		||||
	struct inode *parent_inode = dentry->d_parent->d_inode;
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(parent_inode)->root;
 | 
			
		||||
 | 
			
		||||
	key.objectid = inode->i_ino;
 | 
			
		||||
	btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
 | 
			
		||||
	key.offset = 0;
 | 
			
		||||
 | 
			
		||||
	ret = btrfs_insert_dir_item(trans, root,
 | 
			
		||||
				    dentry->d_name.name, dentry->d_name.len,
 | 
			
		||||
				    dentry->d_parent->d_inode->i_ino,
 | 
			
		||||
	ret = btrfs_insert_dir_item(trans, root, name, name_len,
 | 
			
		||||
				    parent_inode->i_ino,
 | 
			
		||||
				    &key, btrfs_inode_type(inode),
 | 
			
		||||
				    index);
 | 
			
		||||
	if (ret == 0) {
 | 
			
		||||
		if (add_backref) {
 | 
			
		||||
			ret = btrfs_insert_inode_ref(trans, root,
 | 
			
		||||
					     dentry->d_name.name,
 | 
			
		||||
					     dentry->d_name.len,
 | 
			
		||||
						     name, name_len,
 | 
			
		||||
						     inode->i_ino,
 | 
			
		||||
						     parent_inode->i_ino,
 | 
			
		||||
						     index);
 | 
			
		||||
		}
 | 
			
		||||
		btrfs_i_size_write(parent_inode, parent_inode->i_size +
 | 
			
		||||
				   dentry->d_name.len * 2);
 | 
			
		||||
				   name_len * 2);
 | 
			
		||||
		parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
 | 
			
		||||
		ret = btrfs_update_inode(trans, root,
 | 
			
		||||
					 dentry->d_parent->d_inode);
 | 
			
		||||
		ret = btrfs_update_inode(trans, root, parent_inode);
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2389,7 +2410,9 @@ static int btrfs_add_nondir(struct btrfs_trans_handle *trans,
 | 
			
		|||
			    struct dentry *dentry, struct inode *inode,
 | 
			
		||||
			    int backref, u64 index)
 | 
			
		||||
{
 | 
			
		||||
	int err = btrfs_add_link(trans, dentry, inode, backref, index);
 | 
			
		||||
	int err = btrfs_add_link(trans, dentry->d_parent->d_inode,
 | 
			
		||||
				 inode, dentry->d_name.name,
 | 
			
		||||
				 dentry->d_name.len, backref, index);
 | 
			
		||||
	if (!err) {
 | 
			
		||||
		d_instantiate(dentry, inode);
 | 
			
		||||
		return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -2513,19 +2536,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
 | 
			
		|||
		inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
 | 
			
		||||
		inode->i_fop = &btrfs_file_operations;
 | 
			
		||||
		inode->i_op = &btrfs_file_inode_operations;
 | 
			
		||||
		extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
 | 
			
		||||
		extent_io_tree_init(&BTRFS_I(inode)->io_tree,
 | 
			
		||||
				     inode->i_mapping, GFP_NOFS);
 | 
			
		||||
		extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree,
 | 
			
		||||
				     inode->i_mapping, GFP_NOFS);
 | 
			
		||||
		INIT_LIST_HEAD(&BTRFS_I(inode)->delalloc_inodes);
 | 
			
		||||
		mutex_init(&BTRFS_I(inode)->csum_mutex);
 | 
			
		||||
		mutex_init(&BTRFS_I(inode)->extent_mutex);
 | 
			
		||||
		BTRFS_I(inode)->delalloc_bytes = 0;
 | 
			
		||||
		BTRFS_I(inode)->disk_i_size = 0;
 | 
			
		||||
		inode->i_mapping->writeback_index = 0;
 | 
			
		||||
		BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
 | 
			
		||||
		btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
 | 
			
		||||
	}
 | 
			
		||||
	dir->i_sb->s_dirt = 1;
 | 
			
		||||
	btrfs_update_inode_block_group(trans, inode);
 | 
			
		||||
| 
						 | 
				
			
			@ -2556,11 +2567,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
 | 
			
		|||
	if (inode->i_nlink == 0)
 | 
			
		||||
		return -ENOENT;
 | 
			
		||||
 | 
			
		||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
 | 
			
		||||
	inode->i_nlink++;
 | 
			
		||||
#else
 | 
			
		||||
	inc_nlink(inode);
 | 
			
		||||
#endif
 | 
			
		||||
	btrfs_inc_nlink(inode);
 | 
			
		||||
	err = btrfs_check_free_space(root, 1, 0);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto fail;
 | 
			
		||||
| 
						 | 
				
			
			@ -2650,7 +2657,9 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 | 
			
		|||
	if (err)
 | 
			
		||||
		goto out_fail;
 | 
			
		||||
 | 
			
		||||
	err = btrfs_add_link(trans, dentry, inode, 0, index);
 | 
			
		||||
	err = btrfs_add_link(trans, dentry->d_parent->d_inode,
 | 
			
		||||
				 inode, dentry->d_name.name,
 | 
			
		||||
				 dentry->d_name.len, 0, index);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto out_fail;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3221,7 +3230,7 @@ static void btrfs_truncate(struct inode *inode)
 | 
			
		|||
	if (ret)
 | 
			
		||||
		goto out;
 | 
			
		||||
	/* FIXME, add redo link to tree so we don't leak on crash */
 | 
			
		||||
	ret = btrfs_truncate_in_trans(trans, root, inode,
 | 
			
		||||
	ret = btrfs_truncate_inode_items(trans, root, inode, inode->i_size,
 | 
			
		||||
				      BTRFS_EXTENT_DATA_KEY);
 | 
			
		||||
	btrfs_update_inode(trans, root, inode);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3304,6 +3313,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
 | 
			
		|||
	if (!ei)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	ei->last_trans = 0;
 | 
			
		||||
	ei->logged_trans = 0;
 | 
			
		||||
	btrfs_ordered_inode_tree_init(&ei->ordered_tree);
 | 
			
		||||
	ei->i_acl = BTRFS_ACL_NOT_CACHED;
 | 
			
		||||
	ei->i_default_acl = BTRFS_ACL_NOT_CACHED;
 | 
			
		||||
| 
						 | 
				
			
			@ -3463,31 +3473,39 @@ static int btrfs_rename(struct inode * old_dir, struct dentry *old_dentry,
 | 
			
		|||
 | 
			
		||||
	btrfs_set_trans_block_group(trans, new_dir);
 | 
			
		||||
 | 
			
		||||
	old_dentry->d_inode->i_nlink++;
 | 
			
		||||
	btrfs_inc_nlink(old_dentry->d_inode);
 | 
			
		||||
	old_dir->i_ctime = old_dir->i_mtime = ctime;
 | 
			
		||||
	new_dir->i_ctime = new_dir->i_mtime = ctime;
 | 
			
		||||
	old_inode->i_ctime = ctime;
 | 
			
		||||
 | 
			
		||||
	ret = btrfs_unlink_trans(trans, root, old_dir, old_dentry);
 | 
			
		||||
	ret = btrfs_unlink_inode(trans, root, old_dir, old_dentry->d_inode,
 | 
			
		||||
				 old_dentry->d_name.name,
 | 
			
		||||
				 old_dentry->d_name.len);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto out_fail;
 | 
			
		||||
 | 
			
		||||
	if (new_inode) {
 | 
			
		||||
		new_inode->i_ctime = CURRENT_TIME;
 | 
			
		||||
		ret = btrfs_unlink_trans(trans, root, new_dir, new_dentry);
 | 
			
		||||
		ret = btrfs_unlink_inode(trans, root, new_dir,
 | 
			
		||||
					 new_dentry->d_inode,
 | 
			
		||||
					 new_dentry->d_name.name,
 | 
			
		||||
					 new_dentry->d_name.len);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			goto out_fail;
 | 
			
		||||
		if (new_inode->i_nlink == 0) {
 | 
			
		||||
			ret = btrfs_orphan_add(trans, new_inode);
 | 
			
		||||
			ret = btrfs_orphan_add(trans, new_dentry->d_inode);
 | 
			
		||||
			if (ret)
 | 
			
		||||
				goto out_fail;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	ret = btrfs_set_inode_index(new_dir, old_inode, &index);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto out_fail;
 | 
			
		||||
 | 
			
		||||
	ret = btrfs_add_link(trans, new_dentry, old_inode, 1, index);
 | 
			
		||||
	ret = btrfs_add_link(trans, new_dentry->d_parent->d_inode,
 | 
			
		||||
			     old_inode, new_dentry->d_name.name,
 | 
			
		||||
			     new_dentry->d_name.len, 1, index);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto out_fail;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3577,19 +3595,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
 | 
			
		|||
		inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
 | 
			
		||||
		inode->i_fop = &btrfs_file_operations;
 | 
			
		||||
		inode->i_op = &btrfs_file_inode_operations;
 | 
			
		||||
		extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
 | 
			
		||||
		extent_io_tree_init(&BTRFS_I(inode)->io_tree,
 | 
			
		||||
				     inode->i_mapping, GFP_NOFS);
 | 
			
		||||
		extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree,
 | 
			
		||||
				     inode->i_mapping, GFP_NOFS);
 | 
			
		||||
		INIT_LIST_HEAD(&BTRFS_I(inode)->delalloc_inodes);
 | 
			
		||||
		mutex_init(&BTRFS_I(inode)->csum_mutex);
 | 
			
		||||
		mutex_init(&BTRFS_I(inode)->extent_mutex);
 | 
			
		||||
		BTRFS_I(inode)->delalloc_bytes = 0;
 | 
			
		||||
		BTRFS_I(inode)->disk_i_size = 0;
 | 
			
		||||
		inode->i_mapping->writeback_index = 0;
 | 
			
		||||
		BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
 | 
			
		||||
		btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
 | 
			
		||||
	}
 | 
			
		||||
	dir->i_sb->s_dirt = 1;
 | 
			
		||||
	btrfs_update_inode_block_group(trans, inode);
 | 
			
		||||
| 
						 | 
				
			
			@ -3691,6 +3697,7 @@ static struct file_operations btrfs_dir_file_operations = {
 | 
			
		|||
	.compat_ioctl	= btrfs_ioctl,
 | 
			
		||||
#endif
 | 
			
		||||
	.release        = btrfs_release_file,
 | 
			
		||||
	.fsync		= btrfs_sync_file,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct extent_io_ops btrfs_extent_io_ops = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -202,7 +202,8 @@ int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid,
 | 
			
		|||
		memcpy(&found_key, &key, sizeof(key));
 | 
			
		||||
		key.offset++;
 | 
			
		||||
		btrfs_release_path(root, path);
 | 
			
		||||
		dead_root = btrfs_read_fs_root_no_radix(root->fs_info,
 | 
			
		||||
		dead_root =
 | 
			
		||||
			btrfs_read_fs_root_no_radix(root->fs_info->tree_root,
 | 
			
		||||
						    &found_key);
 | 
			
		||||
		if (IS_ERR(dead_root)) {
 | 
			
		||||
			ret = PTR_ERR(dead_root);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,7 @@
 | 
			
		|||
#include "transaction.h"
 | 
			
		||||
#include "locking.h"
 | 
			
		||||
#include "ref-cache.h"
 | 
			
		||||
#include "tree-log.h"
 | 
			
		||||
 | 
			
		||||
static int total_trans = 0;
 | 
			
		||||
extern struct kmem_cache *btrfs_trans_handle_cachep;
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +58,7 @@ static noinline int join_transaction(struct btrfs_root *root)
 | 
			
		|||
		root->fs_info->generation++;
 | 
			
		||||
		root->fs_info->last_alloc = 0;
 | 
			
		||||
		root->fs_info->last_data_alloc = 0;
 | 
			
		||||
		root->fs_info->last_log_alloc = 0;
 | 
			
		||||
		cur_trans->num_writers = 1;
 | 
			
		||||
		cur_trans->num_joined = 0;
 | 
			
		||||
		cur_trans->transid = root->fs_info->generation;
 | 
			
		||||
| 
						 | 
				
			
			@ -83,7 +85,7 @@ static noinline int join_transaction(struct btrfs_root *root)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static noinline int record_root_in_trans(struct btrfs_root *root)
 | 
			
		||||
noinline int btrfs_record_root_in_trans(struct btrfs_root *root)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_dirty_root *dirty;
 | 
			
		||||
	u64 running_trans_id = root->fs_info->running_transaction->transid;
 | 
			
		||||
| 
						 | 
				
			
			@ -151,7 +153,7 @@ static void wait_current_trans(struct btrfs_root *root)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
 | 
			
		||||
static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
 | 
			
		||||
					     int num_blocks, int wait)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_trans_handle *h =
 | 
			
		||||
| 
						 | 
				
			
			@ -164,7 +166,7 @@ struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
 | 
			
		|||
	ret = join_transaction(root);
 | 
			
		||||
	BUG_ON(ret);
 | 
			
		||||
 | 
			
		||||
	record_root_in_trans(root);
 | 
			
		||||
	btrfs_record_root_in_trans(root);
 | 
			
		||||
	h->transid = root->fs_info->running_transaction->transid;
 | 
			
		||||
	h->transaction = root->fs_info->running_transaction;
 | 
			
		||||
	h->blocks_reserved = num_blocks;
 | 
			
		||||
| 
						 | 
				
			
			@ -456,6 +458,8 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans,
 | 
			
		|||
			BUG_ON(!root->ref_tree);
 | 
			
		||||
			dirty = root->dirty_root;
 | 
			
		||||
 | 
			
		||||
			btrfs_free_log(trans, root);
 | 
			
		||||
 | 
			
		||||
			if (root->commit_root == root->node) {
 | 
			
		||||
				WARN_ON(root->node->start !=
 | 
			
		||||
					btrfs_root_bytenr(&root->root_item));
 | 
			
		||||
| 
						 | 
				
			
			@ -600,7 +604,7 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root,
 | 
			
		|||
		num_bytes -= btrfs_root_used(&dirty->root->root_item);
 | 
			
		||||
		bytes_used = btrfs_root_used(&root->root_item);
 | 
			
		||||
		if (num_bytes) {
 | 
			
		||||
			record_root_in_trans(root);
 | 
			
		||||
			btrfs_record_root_in_trans(root);
 | 
			
		||||
			btrfs_set_root_used(&root->root_item,
 | 
			
		||||
					    bytes_used - num_bytes);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -745,7 +749,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 | 
			
		|||
	int ret;
 | 
			
		||||
 | 
			
		||||
	INIT_LIST_HEAD(&dirty_fs_roots);
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&root->fs_info->trans_mutex);
 | 
			
		||||
	if (trans->transaction->in_commit) {
 | 
			
		||||
		cur_trans = trans->transaction;
 | 
			
		||||
| 
						 | 
				
			
			@ -821,10 +824,30 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 | 
			
		|||
 | 
			
		||||
	WARN_ON(cur_trans != trans->transaction);
 | 
			
		||||
 | 
			
		||||
	/* btrfs_commit_tree_roots is responsible for getting the
 | 
			
		||||
	 * various roots consistent with each other.  Every pointer
 | 
			
		||||
	 * in the tree of tree roots has to point to the most up to date
 | 
			
		||||
	 * root for every subvolume and other tree.  So, we have to keep
 | 
			
		||||
	 * the tree logging code from jumping in and changing any
 | 
			
		||||
	 * of the trees.
 | 
			
		||||
	 *
 | 
			
		||||
	 * At this point in the commit, there can't be any tree-log
 | 
			
		||||
	 * writers, but a little lower down we drop the trans mutex
 | 
			
		||||
	 * and let new people in.  By holding the tree_log_mutex
 | 
			
		||||
	 * from now until after the super is written, we avoid races
 | 
			
		||||
	 * with the tree-log code.
 | 
			
		||||
	 */
 | 
			
		||||
	mutex_lock(&root->fs_info->tree_log_mutex);
 | 
			
		||||
 | 
			
		||||
	ret = add_dirty_roots(trans, &root->fs_info->fs_roots_radix,
 | 
			
		||||
			      &dirty_fs_roots);
 | 
			
		||||
	BUG_ON(ret);
 | 
			
		||||
 | 
			
		||||
	/* add_dirty_roots gets rid of all the tree log roots, it is now
 | 
			
		||||
	 * safe to free the root of tree log roots
 | 
			
		||||
	 */
 | 
			
		||||
	btrfs_free_log_root_tree(trans, root->fs_info);
 | 
			
		||||
 | 
			
		||||
	ret = btrfs_commit_tree_roots(trans, root);
 | 
			
		||||
	BUG_ON(ret);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -843,6 +866,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 | 
			
		|||
				   chunk_root->node->start);
 | 
			
		||||
	btrfs_set_super_chunk_root_level(&root->fs_info->super_copy,
 | 
			
		||||
					 btrfs_header_level(chunk_root->node));
 | 
			
		||||
 | 
			
		||||
	if (!root->fs_info->log_root_recovering) {
 | 
			
		||||
		btrfs_set_super_log_root(&root->fs_info->super_copy, 0);
 | 
			
		||||
		btrfs_set_super_log_root_level(&root->fs_info->super_copy, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memcpy(&root->fs_info->super_for_commit, &root->fs_info->super_copy,
 | 
			
		||||
	       sizeof(root->fs_info->super_copy));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -857,6 +886,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 | 
			
		|||
	BUG_ON(ret);
 | 
			
		||||
	write_ctree_super(trans, root);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * the super is written, we can safely allow the tree-loggers
 | 
			
		||||
	 * to go about their business
 | 
			
		||||
	 */
 | 
			
		||||
	mutex_unlock(&root->fs_info->tree_log_mutex);
 | 
			
		||||
 | 
			
		||||
	btrfs_finish_extent_commit(trans, root, pinned_copy);
 | 
			
		||||
	mutex_lock(&root->fs_info->trans_mutex);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -98,4 +98,5 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 | 
			
		|||
int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
 | 
			
		||||
				   struct btrfs_root *root);
 | 
			
		||||
void btrfs_throttle(struct btrfs_root *root);
 | 
			
		||||
int btrfs_record_root_in_trans(struct btrfs_root *root);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,12 +81,12 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
 | 
			
		|||
		memcpy(&key, &root->defrag_progress, sizeof(key));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	path->lowest_level = 1;
 | 
			
		||||
	path->keep_locks = 1;
 | 
			
		||||
	if (cache_only)
 | 
			
		||||
		min_trans = root->defrag_trans_start;
 | 
			
		||||
 | 
			
		||||
	ret = btrfs_search_forward(root, &key, path, cache_only, min_trans);
 | 
			
		||||
	ret = btrfs_search_forward(root, &key, NULL, path,
 | 
			
		||||
				   cache_only, min_trans);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		goto out;
 | 
			
		||||
	if (ret > 0) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2804
									
								
								fs/btrfs/tree-log.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2804
									
								
								fs/btrfs/tree-log.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										41
									
								
								fs/btrfs/tree-log.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								fs/btrfs/tree-log.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (C) 2008 Oracle.  All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 __TREE_LOG_
 | 
			
		||||
#define __TREE_LOG_
 | 
			
		||||
 | 
			
		||||
int btrfs_sync_log(struct btrfs_trans_handle *trans,
 | 
			
		||||
		   struct btrfs_root *root);
 | 
			
		||||
int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root);
 | 
			
		||||
int btrfs_log_dentry(struct btrfs_trans_handle *trans,
 | 
			
		||||
		    struct btrfs_root *root, struct dentry *dentry);
 | 
			
		||||
int btrfs_recover_log_trees(struct btrfs_root *tree_root);
 | 
			
		||||
int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
 | 
			
		||||
			  struct btrfs_root *root, struct dentry *dentry);
 | 
			
		||||
int btrfs_log_inode(struct btrfs_trans_handle *trans,
 | 
			
		||||
		    struct btrfs_root *root, struct inode *inode,
 | 
			
		||||
		    int inode_only);
 | 
			
		||||
int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
 | 
			
		||||
				 struct btrfs_root *root,
 | 
			
		||||
				 const char *name, int name_len,
 | 
			
		||||
				 struct inode *dir, u64 index);
 | 
			
		||||
int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
 | 
			
		||||
			       struct btrfs_root *root,
 | 
			
		||||
			       const char *name, int name_len,
 | 
			
		||||
			       struct inode *inode, u64 dirid);
 | 
			
		||||
#endif
 | 
			
		||||
		Loading…
	
		Reference in a new issue