Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: (58 commits) Btrfs: use the device_list_mutex during write_dev_supers Btrfs: setup free ino caching in a more asynchronous way btrfs scrub: don't coalesce pages that are logically discontiguous Btrfs: return -ENOMEM in clear_extent_bit Btrfs: add mount -o auto_defrag Btrfs: using rcu lock in the reader side of devices list Btrfs: drop unnecessary device lock Btrfs: fix the race between remove dev and alloc chunk Btrfs: fix the race between reading and updating devices Btrfs: fix bh leak on __btrfs_open_devices path Btrfs: fix unsafe usage of merge_state Btrfs: allocate extent state and check the result properly fs/btrfs: Add missing btrfs_free_path Btrfs: check return value of btrfs_inc_extent_ref() Btrfs: return error to caller if read_one_inode() fails Btrfs: BUG_ON is deleted from the caller of btrfs_truncate_item & btrfs_extend_item Btrfs: return error code to caller when btrfs_del_item fails Btrfs: return error code to caller when btrfs_previous_item fails btrfs: fix typo 'testeing' -> 'testing' btrfs: typo: 'btrfS' -> 'btrfs' ...
This commit is contained in:
		
						commit
						a0c3061093
					
				| @ -7,4 +7,4 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ | ||||
| 	   extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
 | ||||
| 	   extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
 | ||||
| 	   export.o tree-log.o acl.o free-space-cache.o zlib.o lzo.o \
 | ||||
| 	   compression.o delayed-ref.o relocation.o | ||||
| 	   compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o | ||||
|  | ||||
| @ -288,7 +288,7 @@ int btrfs_acl_chmod(struct inode *inode) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); | ||||
| 	if (IS_ERR(acl) || !acl) | ||||
| 	if (IS_ERR_OR_NULL(acl)) | ||||
| 		return PTR_ERR(acl); | ||||
| 
 | ||||
| 	clone = posix_acl_clone(acl, GFP_KERNEL); | ||||
|  | ||||
| @ -22,6 +22,7 @@ | ||||
| #include "extent_map.h" | ||||
| #include "extent_io.h" | ||||
| #include "ordered-data.h" | ||||
| #include "delayed-inode.h" | ||||
| 
 | ||||
| /* in memory btrfs inode */ | ||||
| struct btrfs_inode { | ||||
| @ -152,20 +153,34 @@ struct btrfs_inode { | ||||
| 	unsigned ordered_data_close:1; | ||||
| 	unsigned orphan_meta_reserved:1; | ||||
| 	unsigned dummy_inode:1; | ||||
| 	unsigned in_defrag:1; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * always compress this one file | ||||
| 	 */ | ||||
| 	unsigned force_compress:4; | ||||
| 
 | ||||
| 	struct btrfs_delayed_node *delayed_node; | ||||
| 
 | ||||
| 	struct inode vfs_inode; | ||||
| }; | ||||
| 
 | ||||
| extern unsigned char btrfs_filetype_table[]; | ||||
| 
 | ||||
| static inline struct btrfs_inode *BTRFS_I(struct inode *inode) | ||||
| { | ||||
| 	return container_of(inode, struct btrfs_inode, vfs_inode); | ||||
| } | ||||
| 
 | ||||
| static inline u64 btrfs_ino(struct inode *inode) | ||||
| { | ||||
| 	u64 ino = BTRFS_I(inode)->location.objectid; | ||||
| 
 | ||||
| 	if (ino <= BTRFS_FIRST_FREE_OBJECTID) | ||||
| 		ino = inode->i_ino; | ||||
| 	return ino; | ||||
| } | ||||
| 
 | ||||
| static inline void btrfs_i_size_write(struct inode *inode, u64 size) | ||||
| { | ||||
| 	i_size_write(inode, size); | ||||
|  | ||||
| @ -125,9 +125,10 @@ static int check_compressed_csum(struct inode *inode, | ||||
| 		kunmap_atomic(kaddr, KM_USER0); | ||||
| 
 | ||||
| 		if (csum != *cb_sum) { | ||||
| 			printk(KERN_INFO "btrfs csum failed ino %lu " | ||||
| 			printk(KERN_INFO "btrfs csum failed ino %llu " | ||||
| 			       "extent %llu csum %u " | ||||
| 			       "wanted %u mirror %d\n", inode->i_ino, | ||||
| 			       "wanted %u mirror %d\n", | ||||
| 			       (unsigned long long)btrfs_ino(inode), | ||||
| 			       (unsigned long long)disk_start, | ||||
| 			       csum, *cb_sum, cb->mirror_num); | ||||
| 			ret = -EIO; | ||||
| @ -332,7 +333,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, | ||||
| 	struct compressed_bio *cb; | ||||
| 	unsigned long bytes_left; | ||||
| 	struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | ||||
| 	int page_index = 0; | ||||
| 	int pg_index = 0; | ||||
| 	struct page *page; | ||||
| 	u64 first_byte = disk_start; | ||||
| 	struct block_device *bdev; | ||||
| @ -366,8 +367,8 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, | ||||
| 
 | ||||
| 	/* create and submit bios for the compressed pages */ | ||||
| 	bytes_left = compressed_len; | ||||
| 	for (page_index = 0; page_index < cb->nr_pages; page_index++) { | ||||
| 		page = compressed_pages[page_index]; | ||||
| 	for (pg_index = 0; pg_index < cb->nr_pages; pg_index++) { | ||||
| 		page = compressed_pages[pg_index]; | ||||
| 		page->mapping = inode->i_mapping; | ||||
| 		if (bio->bi_size) | ||||
| 			ret = io_tree->ops->merge_bio_hook(page, 0, | ||||
| @ -432,7 +433,7 @@ static noinline int add_ra_bio_pages(struct inode *inode, | ||||
| 				     struct compressed_bio *cb) | ||||
| { | ||||
| 	unsigned long end_index; | ||||
| 	unsigned long page_index; | ||||
| 	unsigned long pg_index; | ||||
| 	u64 last_offset; | ||||
| 	u64 isize = i_size_read(inode); | ||||
| 	int ret; | ||||
| @ -456,13 +457,13 @@ static noinline int add_ra_bio_pages(struct inode *inode, | ||||
| 	end_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT; | ||||
| 
 | ||||
| 	while (last_offset < compressed_end) { | ||||
| 		page_index = last_offset >> PAGE_CACHE_SHIFT; | ||||
| 		pg_index = last_offset >> PAGE_CACHE_SHIFT; | ||||
| 
 | ||||
| 		if (page_index > end_index) | ||||
| 		if (pg_index > end_index) | ||||
| 			break; | ||||
| 
 | ||||
| 		rcu_read_lock(); | ||||
| 		page = radix_tree_lookup(&mapping->page_tree, page_index); | ||||
| 		page = radix_tree_lookup(&mapping->page_tree, pg_index); | ||||
| 		rcu_read_unlock(); | ||||
| 		if (page) { | ||||
| 			misses++; | ||||
| @ -476,7 +477,7 @@ static noinline int add_ra_bio_pages(struct inode *inode, | ||||
| 		if (!page) | ||||
| 			break; | ||||
| 
 | ||||
| 		if (add_to_page_cache_lru(page, mapping, page_index, | ||||
| 		if (add_to_page_cache_lru(page, mapping, pg_index, | ||||
| 								GFP_NOFS)) { | ||||
| 			page_cache_release(page); | ||||
| 			goto next; | ||||
| @ -560,7 +561,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, | ||||
| 	unsigned long uncompressed_len = bio->bi_vcnt * PAGE_CACHE_SIZE; | ||||
| 	unsigned long compressed_len; | ||||
| 	unsigned long nr_pages; | ||||
| 	unsigned long page_index; | ||||
| 	unsigned long pg_index; | ||||
| 	struct page *page; | ||||
| 	struct block_device *bdev; | ||||
| 	struct bio *comp_bio; | ||||
| @ -613,10 +614,10 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, | ||||
| 
 | ||||
| 	bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; | ||||
| 
 | ||||
| 	for (page_index = 0; page_index < nr_pages; page_index++) { | ||||
| 		cb->compressed_pages[page_index] = alloc_page(GFP_NOFS | | ||||
| 	for (pg_index = 0; pg_index < nr_pages; pg_index++) { | ||||
| 		cb->compressed_pages[pg_index] = alloc_page(GFP_NOFS | | ||||
| 							      __GFP_HIGHMEM); | ||||
| 		if (!cb->compressed_pages[page_index]) | ||||
| 		if (!cb->compressed_pages[pg_index]) | ||||
| 			goto fail2; | ||||
| 	} | ||||
| 	cb->nr_pages = nr_pages; | ||||
| @ -634,8 +635,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, | ||||
| 	comp_bio->bi_end_io = end_compressed_bio_read; | ||||
| 	atomic_inc(&cb->pending_bios); | ||||
| 
 | ||||
| 	for (page_index = 0; page_index < nr_pages; page_index++) { | ||||
| 		page = cb->compressed_pages[page_index]; | ||||
| 	for (pg_index = 0; pg_index < nr_pages; pg_index++) { | ||||
| 		page = cb->compressed_pages[pg_index]; | ||||
| 		page->mapping = inode->i_mapping; | ||||
| 		page->index = em_start >> PAGE_CACHE_SHIFT; | ||||
| 
 | ||||
| @ -702,8 +703,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, | ||||
| 	return 0; | ||||
| 
 | ||||
| fail2: | ||||
| 	for (page_index = 0; page_index < nr_pages; page_index++) | ||||
| 		free_page((unsigned long)cb->compressed_pages[page_index]); | ||||
| 	for (pg_index = 0; pg_index < nr_pages; pg_index++) | ||||
| 		free_page((unsigned long)cb->compressed_pages[pg_index]); | ||||
| 
 | ||||
| 	kfree(cb->compressed_pages); | ||||
| fail1: | ||||
| @ -945,7 +946,7 @@ void btrfs_exit_compress(void) | ||||
| int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, | ||||
| 			      unsigned long total_out, u64 disk_start, | ||||
| 			      struct bio_vec *bvec, int vcnt, | ||||
| 			      unsigned long *page_index, | ||||
| 			      unsigned long *pg_index, | ||||
| 			      unsigned long *pg_offset) | ||||
| { | ||||
| 	unsigned long buf_offset; | ||||
| @ -954,7 +955,7 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, | ||||
| 	unsigned long working_bytes = total_out - buf_start; | ||||
| 	unsigned long bytes; | ||||
| 	char *kaddr; | ||||
| 	struct page *page_out = bvec[*page_index].bv_page; | ||||
| 	struct page *page_out = bvec[*pg_index].bv_page; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * start byte is the first byte of the page we're currently | ||||
| @ -995,11 +996,11 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, | ||||
| 
 | ||||
| 		/* check if we need to pick another page */ | ||||
| 		if (*pg_offset == PAGE_CACHE_SIZE) { | ||||
| 			(*page_index)++; | ||||
| 			if (*page_index >= vcnt) | ||||
| 			(*pg_index)++; | ||||
| 			if (*pg_index >= vcnt) | ||||
| 				return 0; | ||||
| 
 | ||||
| 			page_out = bvec[*page_index].bv_page; | ||||
| 			page_out = bvec[*pg_index].bv_page; | ||||
| 			*pg_offset = 0; | ||||
| 			start_byte = page_offset(page_out) - disk_start; | ||||
| 
 | ||||
|  | ||||
| @ -37,7 +37,7 @@ int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page, | ||||
| int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, | ||||
| 			      unsigned long total_out, u64 disk_start, | ||||
| 			      struct bio_vec *bvec, int vcnt, | ||||
| 			      unsigned long *page_index, | ||||
| 			      unsigned long *pg_index, | ||||
| 			      unsigned long *pg_offset); | ||||
| 
 | ||||
| int btrfs_submit_compressed_write(struct inode *inode, u64 start, | ||||
|  | ||||
| @ -38,11 +38,6 @@ static int balance_node_right(struct btrfs_trans_handle *trans, | ||||
| 			      struct extent_buffer *src_buf); | ||||
| static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||||
| 		   struct btrfs_path *path, int level, int slot); | ||||
| static int setup_items_for_insert(struct btrfs_trans_handle *trans, | ||||
| 			struct btrfs_root *root, struct btrfs_path *path, | ||||
| 			struct btrfs_key *cpu_key, u32 *data_size, | ||||
| 			u32 total_data, u32 total_size, int nr); | ||||
| 
 | ||||
| 
 | ||||
| struct btrfs_path *btrfs_alloc_path(void) | ||||
| { | ||||
| @ -107,7 +102,7 @@ void btrfs_free_path(struct btrfs_path *p) | ||||
| { | ||||
| 	if (!p) | ||||
| 		return; | ||||
| 	btrfs_release_path(NULL, p); | ||||
| 	btrfs_release_path(p); | ||||
| 	kmem_cache_free(btrfs_path_cachep, p); | ||||
| } | ||||
| 
 | ||||
| @ -117,7 +112,7 @@ void btrfs_free_path(struct btrfs_path *p) | ||||
|  * | ||||
|  * It is safe to call this on paths that no locks or extent buffers held. | ||||
|  */ | ||||
| noinline void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p) | ||||
| noinline void btrfs_release_path(struct btrfs_path *p) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| @ -1328,7 +1323,7 @@ static noinline int reada_for_balance(struct btrfs_root *root, | ||||
| 		ret = -EAGAIN; | ||||
| 
 | ||||
| 		/* release the whole path */ | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 
 | ||||
| 		/* read the blocks */ | ||||
| 		if (block1) | ||||
| @ -1475,7 +1470,7 @@ read_block_for_search(struct btrfs_trans_handle *trans, | ||||
| 				return 0; | ||||
| 			} | ||||
| 			free_extent_buffer(tmp); | ||||
| 			btrfs_release_path(NULL, p); | ||||
| 			btrfs_release_path(p); | ||||
| 			return -EIO; | ||||
| 		} | ||||
| 	} | ||||
| @ -1494,7 +1489,7 @@ read_block_for_search(struct btrfs_trans_handle *trans, | ||||
| 	if (p->reada) | ||||
| 		reada_for_search(root, p, level, slot, key->objectid); | ||||
| 
 | ||||
| 	btrfs_release_path(NULL, p); | ||||
| 	btrfs_release_path(p); | ||||
| 
 | ||||
| 	ret = -EAGAIN; | ||||
| 	tmp = read_tree_block(root, blocknr, blocksize, 0); | ||||
| @ -1563,7 +1558,7 @@ setup_nodes_for_search(struct btrfs_trans_handle *trans, | ||||
| 		} | ||||
| 		b = p->nodes[level]; | ||||
| 		if (!b) { | ||||
| 			btrfs_release_path(NULL, p); | ||||
| 			btrfs_release_path(p); | ||||
| 			goto again; | ||||
| 		} | ||||
| 		BUG_ON(btrfs_header_nritems(b) == 1); | ||||
| @ -1753,7 +1748,7 @@ done: | ||||
| 	if (!p->leave_spinning) | ||||
| 		btrfs_set_path_blocking(p); | ||||
| 	if (ret < 0) | ||||
| 		btrfs_release_path(root, p); | ||||
| 		btrfs_release_path(p); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| @ -3026,7 +3021,7 @@ static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans, | ||||
| 				    struct btrfs_file_extent_item); | ||||
| 		extent_len = btrfs_file_extent_num_bytes(leaf, fi); | ||||
| 	} | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 
 | ||||
| 	path->keep_locks = 1; | ||||
| 	path->search_for_split = 1; | ||||
| @ -3216,7 +3211,6 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans, | ||||
| 			struct btrfs_path *path, | ||||
| 			u32 new_size, int from_end) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	int slot; | ||||
| 	struct extent_buffer *leaf; | ||||
| 	struct btrfs_item *item; | ||||
| @ -3314,12 +3308,11 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans, | ||||
| 	btrfs_set_item_size(leaf, item, new_size); | ||||
| 	btrfs_mark_buffer_dirty(leaf); | ||||
| 
 | ||||
| 	ret = 0; | ||||
| 	if (btrfs_leaf_free_space(root, leaf) < 0) { | ||||
| 		btrfs_print_leaf(root, leaf); | ||||
| 		BUG(); | ||||
| 	} | ||||
| 	return ret; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -3329,7 +3322,6 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans, | ||||
| 		      struct btrfs_root *root, struct btrfs_path *path, | ||||
| 		      u32 data_size) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	int slot; | ||||
| 	struct extent_buffer *leaf; | ||||
| 	struct btrfs_item *item; | ||||
| @ -3394,12 +3386,11 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans, | ||||
| 	btrfs_set_item_size(leaf, item, old_size + data_size); | ||||
| 	btrfs_mark_buffer_dirty(leaf); | ||||
| 
 | ||||
| 	ret = 0; | ||||
| 	if (btrfs_leaf_free_space(root, leaf) < 0) { | ||||
| 		btrfs_print_leaf(root, leaf); | ||||
| 		BUG(); | ||||
| 	} | ||||
| 	return ret; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -3559,11 +3550,10 @@ out: | ||||
|  * to save stack depth by doing the bulk of the work in a function | ||||
|  * that doesn't call btrfs_search_slot | ||||
|  */ | ||||
| static noinline_for_stack int | ||||
| setup_items_for_insert(struct btrfs_trans_handle *trans, | ||||
| 		      struct btrfs_root *root, struct btrfs_path *path, | ||||
| 		      struct btrfs_key *cpu_key, u32 *data_size, | ||||
| 		      u32 total_data, u32 total_size, int nr) | ||||
| int setup_items_for_insert(struct btrfs_trans_handle *trans, | ||||
| 			   struct btrfs_root *root, struct btrfs_path *path, | ||||
| 			   struct btrfs_key *cpu_key, u32 *data_size, | ||||
| 			   u32 total_data, u32 total_size, int nr) | ||||
| { | ||||
| 	struct btrfs_item *item; | ||||
| 	int i; | ||||
| @ -3647,7 +3637,6 @@ setup_items_for_insert(struct btrfs_trans_handle *trans, | ||||
| 
 | ||||
| 	ret = 0; | ||||
| 	if (slot == 0) { | ||||
| 		struct btrfs_disk_key disk_key; | ||||
| 		btrfs_cpu_key_to_disk(&disk_key, cpu_key); | ||||
| 		ret = fixup_low_keys(trans, root, path, &disk_key, 1); | ||||
| 	} | ||||
| @ -3949,7 +3938,7 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) | ||||
| 	else | ||||
| 		return 1; | ||||
| 
 | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| @ -4073,7 +4062,7 @@ find_next_key: | ||||
| 			sret = btrfs_find_next_key(root, path, min_key, level, | ||||
| 						  cache_only, min_trans); | ||||
| 			if (sret == 0) { | ||||
| 				btrfs_release_path(root, path); | ||||
| 				btrfs_release_path(path); | ||||
| 				goto again; | ||||
| 			} else { | ||||
| 				goto out; | ||||
| @ -4152,7 +4141,7 @@ next: | ||||
| 				btrfs_node_key_to_cpu(c, &cur_key, slot); | ||||
| 
 | ||||
| 			orig_lowest = path->lowest_level; | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			path->lowest_level = level; | ||||
| 			ret = btrfs_search_slot(NULL, root, &cur_key, path, | ||||
| 						0, 0); | ||||
| @ -4229,7 +4218,7 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) | ||||
| again: | ||||
| 	level = 1; | ||||
| 	next = NULL; | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 
 | ||||
| 	path->keep_locks = 1; | ||||
| 
 | ||||
| @ -4285,7 +4274,7 @@ again: | ||||
| 			goto again; | ||||
| 
 | ||||
| 		if (ret < 0) { | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			goto done; | ||||
| 		} | ||||
| 
 | ||||
| @ -4324,7 +4313,7 @@ again: | ||||
| 			goto again; | ||||
| 
 | ||||
| 		if (ret < 0) { | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			goto done; | ||||
| 		} | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										244
									
								
								fs/btrfs/ctree.h
									
									
									
									
									
								
							
							
						
						
									
										244
									
								
								fs/btrfs/ctree.h
									
									
									
									
									
								
							| @ -23,6 +23,7 @@ | ||||
| #include <linux/mm.h> | ||||
| #include <linux/highmem.h> | ||||
| #include <linux/fs.h> | ||||
| #include <linux/rwsem.h> | ||||
| #include <linux/completion.h> | ||||
| #include <linux/backing-dev.h> | ||||
| #include <linux/wait.h> | ||||
| @ -33,6 +34,7 @@ | ||||
| #include "extent_io.h" | ||||
| #include "extent_map.h" | ||||
| #include "async-thread.h" | ||||
| #include "ioctl.h" | ||||
| 
 | ||||
| struct btrfs_trans_handle; | ||||
| struct btrfs_transaction; | ||||
| @ -105,6 +107,12 @@ struct btrfs_ordered_sum; | ||||
| /* For storing free space cache */ | ||||
| #define BTRFS_FREE_SPACE_OBJECTID -11ULL | ||||
| 
 | ||||
| /*
 | ||||
|  * The inode number assigned to the special inode for sotring | ||||
|  * free ino cache | ||||
|  */ | ||||
| #define BTRFS_FREE_INO_OBJECTID -12ULL | ||||
| 
 | ||||
| /* dummy objectid represents multiple objectids */ | ||||
| #define BTRFS_MULTIPLE_OBJECTIDS -255ULL | ||||
| 
 | ||||
| @ -187,7 +195,6 @@ struct btrfs_mapping_tree { | ||||
| 	struct extent_map_tree map_tree; | ||||
| }; | ||||
| 
 | ||||
| #define BTRFS_UUID_SIZE 16 | ||||
| struct btrfs_dev_item { | ||||
| 	/* the internal btrfs device id */ | ||||
| 	__le64 devid; | ||||
| @ -294,7 +301,6 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes) | ||||
| 		sizeof(struct btrfs_stripe) * (num_stripes - 1); | ||||
| } | ||||
| 
 | ||||
| #define BTRFS_FSID_SIZE 16 | ||||
| #define BTRFS_HEADER_FLAG_WRITTEN	(1ULL << 0) | ||||
| #define BTRFS_HEADER_FLAG_RELOC		(1ULL << 1) | ||||
| 
 | ||||
| @ -510,6 +516,12 @@ struct btrfs_extent_item_v0 { | ||||
| /* use full backrefs for extent pointers in the block */ | ||||
| #define BTRFS_BLOCK_FLAG_FULL_BACKREF	(1ULL << 8) | ||||
| 
 | ||||
| /*
 | ||||
|  * this flag is only used internally by scrub and may be changed at any time | ||||
|  * it is only declared here to avoid collisions | ||||
|  */ | ||||
| #define BTRFS_EXTENT_FLAG_SUPER		(1ULL << 48) | ||||
| 
 | ||||
| struct btrfs_tree_block_info { | ||||
| 	struct btrfs_disk_key key; | ||||
| 	u8 level; | ||||
| @ -740,12 +752,12 @@ struct btrfs_space_info { | ||||
| 	 */ | ||||
| 	unsigned long reservation_progress; | ||||
| 
 | ||||
| 	int full:1;		/* indicates that we cannot allocate any more
 | ||||
| 	unsigned int full:1;	/* indicates that we cannot allocate any more
 | ||||
| 				   chunks for this space */ | ||||
| 	int chunk_alloc:1;	/* set if we are allocating a chunk */ | ||||
| 	unsigned int chunk_alloc:1;	/* set if we are allocating a chunk */ | ||||
| 
 | ||||
| 	int force_alloc;	/* set if we need to force a chunk alloc for
 | ||||
| 				   this space */ | ||||
| 	unsigned int force_alloc;	/* set if we need to force a chunk
 | ||||
| 					   alloc for this space */ | ||||
| 
 | ||||
| 	struct list_head list; | ||||
| 
 | ||||
| @ -830,9 +842,6 @@ struct btrfs_block_group_cache { | ||||
| 	u64 bytes_super; | ||||
| 	u64 flags; | ||||
| 	u64 sectorsize; | ||||
| 	int extents_thresh; | ||||
| 	int free_extents; | ||||
| 	int total_bitmaps; | ||||
| 	unsigned int ro:1; | ||||
| 	unsigned int dirty:1; | ||||
| 	unsigned int iref:1; | ||||
| @ -847,9 +856,7 @@ struct btrfs_block_group_cache { | ||||
| 	struct btrfs_space_info *space_info; | ||||
| 
 | ||||
| 	/* free space cache stuff */ | ||||
| 	spinlock_t tree_lock; | ||||
| 	struct rb_root free_space_offset; | ||||
| 	u64 free_space; | ||||
| 	struct btrfs_free_space_ctl *free_space_ctl; | ||||
| 
 | ||||
| 	/* block group cache stuff */ | ||||
| 	struct rb_node cache_node; | ||||
| @ -869,6 +876,7 @@ struct btrfs_block_group_cache { | ||||
| struct reloc_control; | ||||
| struct btrfs_device; | ||||
| struct btrfs_fs_devices; | ||||
| struct btrfs_delayed_root; | ||||
| struct btrfs_fs_info { | ||||
| 	u8 fsid[BTRFS_FSID_SIZE]; | ||||
| 	u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; | ||||
| @ -895,7 +903,10 @@ struct btrfs_fs_info { | ||||
| 	/* logical->physical extent mapping */ | ||||
| 	struct btrfs_mapping_tree mapping_tree; | ||||
| 
 | ||||
| 	/* block reservation for extent, checksum and root tree */ | ||||
| 	/*
 | ||||
| 	 * block reservation for extent, checksum, root tree and | ||||
| 	 * delayed dir index item | ||||
| 	 */ | ||||
| 	struct btrfs_block_rsv global_block_rsv; | ||||
| 	/* block reservation for delay allocation */ | ||||
| 	struct btrfs_block_rsv delalloc_block_rsv; | ||||
| @ -1022,6 +1033,7 @@ struct btrfs_fs_info { | ||||
| 	 * for the sys_munmap function call path | ||||
| 	 */ | ||||
| 	struct btrfs_workers fixup_workers; | ||||
| 	struct btrfs_workers delayed_workers; | ||||
| 	struct task_struct *transaction_kthread; | ||||
| 	struct task_struct *cleaner_kthread; | ||||
| 	int thread_pool_size; | ||||
| @ -1062,6 +1074,11 @@ struct btrfs_fs_info { | ||||
| 	/* all metadata allocations go through this cluster */ | ||||
| 	struct btrfs_free_cluster meta_alloc_cluster; | ||||
| 
 | ||||
| 	/* auto defrag inodes go here */ | ||||
| 	spinlock_t defrag_inodes_lock; | ||||
| 	struct rb_root defrag_inodes; | ||||
| 	atomic_t defrag_running; | ||||
| 
 | ||||
| 	spinlock_t ref_cache_lock; | ||||
| 	u64 total_ref_cache_size; | ||||
| 
 | ||||
| @ -1077,8 +1094,21 @@ struct btrfs_fs_info { | ||||
| 
 | ||||
| 	void *bdev_holder; | ||||
| 
 | ||||
| 	/* private scrub information */ | ||||
| 	struct mutex scrub_lock; | ||||
| 	atomic_t scrubs_running; | ||||
| 	atomic_t scrub_pause_req; | ||||
| 	atomic_t scrubs_paused; | ||||
| 	atomic_t scrub_cancel_req; | ||||
| 	wait_queue_head_t scrub_pause_wait; | ||||
| 	struct rw_semaphore scrub_super_lock; | ||||
| 	int scrub_workers_refcnt; | ||||
| 	struct btrfs_workers scrub_workers; | ||||
| 
 | ||||
| 	/* filesystem state */ | ||||
| 	u64 fs_state; | ||||
| 
 | ||||
| 	struct btrfs_delayed_root *delayed_root; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
| @ -1088,9 +1118,6 @@ struct btrfs_fs_info { | ||||
| struct btrfs_root { | ||||
| 	struct extent_buffer *node; | ||||
| 
 | ||||
| 	/* the node lock is held while changing the node pointer */ | ||||
| 	spinlock_t node_lock; | ||||
| 
 | ||||
| 	struct extent_buffer *commit_root; | ||||
| 	struct btrfs_root *log_root; | ||||
| 	struct btrfs_root *reloc_root; | ||||
| @ -1107,6 +1134,16 @@ struct btrfs_root { | ||||
| 	spinlock_t accounting_lock; | ||||
| 	struct btrfs_block_rsv *block_rsv; | ||||
| 
 | ||||
| 	/* free ino cache stuff */ | ||||
| 	struct mutex fs_commit_mutex; | ||||
| 	struct btrfs_free_space_ctl *free_ino_ctl; | ||||
| 	enum btrfs_caching_type cached; | ||||
| 	spinlock_t cache_lock; | ||||
| 	wait_queue_head_t cache_wait; | ||||
| 	struct btrfs_free_space_ctl *free_ino_pinned; | ||||
| 	u64 cache_progress; | ||||
| 	struct inode *cache_inode; | ||||
| 
 | ||||
| 	struct mutex log_mutex; | ||||
| 	wait_queue_head_t log_writer_wait; | ||||
| 	wait_queue_head_t log_commit_wait[2]; | ||||
| @ -1161,6 +1198,11 @@ struct btrfs_root { | ||||
| 	/* red-black tree that keeps track of in-memory inodes */ | ||||
| 	struct rb_root inode_tree; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * radix tree that keeps track of delayed nodes of every inode, | ||||
| 	 * protected by inode_lock | ||||
| 	 */ | ||||
| 	struct radix_tree_root delayed_nodes_tree; | ||||
| 	/*
 | ||||
| 	 * right now this just gets used so that a root has its own devid | ||||
| 	 * for stat.  It may be used for more later | ||||
| @ -1168,6 +1210,38 @@ struct btrfs_root { | ||||
| 	struct super_block anon_super; | ||||
| }; | ||||
| 
 | ||||
| struct btrfs_ioctl_defrag_range_args { | ||||
| 	/* start of the defrag operation */ | ||||
| 	__u64 start; | ||||
| 
 | ||||
| 	/* number of bytes to defrag, use (u64)-1 to say all */ | ||||
| 	__u64 len; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * flags for the operation, which can include turning | ||||
| 	 * on compression for this one defrag | ||||
| 	 */ | ||||
| 	__u64 flags; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * any extent bigger than this will be considered | ||||
| 	 * already defragged.  Use 0 to take the kernel default | ||||
| 	 * Use 1 to say every single extent must be rewritten | ||||
| 	 */ | ||||
| 	__u32 extent_thresh; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * which compression method to use if turning on compression | ||||
| 	 * for this defrag operation.  If unspecified, zlib will | ||||
| 	 * be used | ||||
| 	 */ | ||||
| 	__u32 compress_type; | ||||
| 
 | ||||
| 	/* spare for later */ | ||||
| 	__u32 unused[4]; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * inode items have the data typically returned from stat and store other | ||||
|  * info about object characteristics.  There is one for every file and dir in | ||||
| @ -1265,6 +1339,7 @@ struct btrfs_root { | ||||
| #define BTRFS_MOUNT_CLEAR_CACHE		(1 << 13) | ||||
| #define BTRFS_MOUNT_USER_SUBVOL_RM_ALLOWED (1 << 14) | ||||
| #define BTRFS_MOUNT_ENOSPC_DEBUG	 (1 << 15) | ||||
| #define BTRFS_MOUNT_AUTO_DEFRAG		(1 << 16) | ||||
| 
 | ||||
| #define btrfs_clear_opt(o, opt)		((o) &= ~BTRFS_MOUNT_##opt) | ||||
| #define btrfs_set_opt(o, opt)		((o) |= BTRFS_MOUNT_##opt) | ||||
| @ -1440,26 +1515,12 @@ static inline u64 btrfs_stripe_offset_nr(struct extent_buffer *eb, | ||||
| 	return btrfs_stripe_offset(eb, btrfs_stripe_nr(c, nr)); | ||||
| } | ||||
| 
 | ||||
| static inline void btrfs_set_stripe_offset_nr(struct extent_buffer *eb, | ||||
| 					     struct btrfs_chunk *c, int nr, | ||||
| 					     u64 val) | ||||
| { | ||||
| 	btrfs_set_stripe_offset(eb, btrfs_stripe_nr(c, nr), val); | ||||
| } | ||||
| 
 | ||||
| static inline u64 btrfs_stripe_devid_nr(struct extent_buffer *eb, | ||||
| 					 struct btrfs_chunk *c, int nr) | ||||
| { | ||||
| 	return btrfs_stripe_devid(eb, btrfs_stripe_nr(c, nr)); | ||||
| } | ||||
| 
 | ||||
| static inline void btrfs_set_stripe_devid_nr(struct extent_buffer *eb, | ||||
| 					     struct btrfs_chunk *c, int nr, | ||||
| 					     u64 val) | ||||
| { | ||||
| 	btrfs_set_stripe_devid(eb, btrfs_stripe_nr(c, nr), val); | ||||
| } | ||||
| 
 | ||||
| /* struct btrfs_block_group_item */ | ||||
| BTRFS_SETGET_STACK_FUNCS(block_group_used, struct btrfs_block_group_item, | ||||
| 			 used, 64); | ||||
| @ -1517,14 +1578,6 @@ btrfs_inode_ctime(struct btrfs_inode_item *inode_item) | ||||
| 	return (struct btrfs_timespec *)ptr; | ||||
| } | ||||
| 
 | ||||
| static inline struct btrfs_timespec * | ||||
| btrfs_inode_otime(struct btrfs_inode_item *inode_item) | ||||
| { | ||||
| 	unsigned long ptr = (unsigned long)inode_item; | ||||
| 	ptr += offsetof(struct btrfs_inode_item, otime); | ||||
| 	return (struct btrfs_timespec *)ptr; | ||||
| } | ||||
| 
 | ||||
| BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64); | ||||
| BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32); | ||||
| 
 | ||||
| @ -1875,33 +1928,6 @@ static inline u8 *btrfs_header_chunk_tree_uuid(struct extent_buffer *eb) | ||||
| 	return (u8 *)ptr; | ||||
| } | ||||
| 
 | ||||
| static inline u8 *btrfs_super_fsid(struct extent_buffer *eb) | ||||
| { | ||||
| 	unsigned long ptr = offsetof(struct btrfs_super_block, fsid); | ||||
| 	return (u8 *)ptr; | ||||
| } | ||||
| 
 | ||||
| static inline u8 *btrfs_header_csum(struct extent_buffer *eb) | ||||
| { | ||||
| 	unsigned long ptr = offsetof(struct btrfs_header, csum); | ||||
| 	return (u8 *)ptr; | ||||
| } | ||||
| 
 | ||||
| static inline struct btrfs_node *btrfs_buffer_node(struct extent_buffer *eb) | ||||
| { | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static inline struct btrfs_leaf *btrfs_buffer_leaf(struct extent_buffer *eb) | ||||
| { | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static inline struct btrfs_header *btrfs_buffer_header(struct extent_buffer *eb) | ||||
| { | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static inline int btrfs_is_leaf(struct extent_buffer *eb) | ||||
| { | ||||
| 	return btrfs_header_level(eb) == 0; | ||||
| @ -2055,22 +2081,6 @@ static inline struct btrfs_root *btrfs_sb(struct super_block *sb) | ||||
| 	return sb->s_fs_info; | ||||
| } | ||||
| 
 | ||||
| static inline int btrfs_set_root_name(struct btrfs_root *root, | ||||
| 				      const char *name, int len) | ||||
| { | ||||
| 	/* if we already have a name just free it */ | ||||
| 	kfree(root->name); | ||||
| 
 | ||||
| 	root->name = kmalloc(len+1, GFP_KERNEL); | ||||
| 	if (!root->name) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	memcpy(root->name, name, len); | ||||
| 	root->name[len] = '\0'; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static inline u32 btrfs_level_size(struct btrfs_root *root, int level) | ||||
| { | ||||
| 	if (level == 0) | ||||
| @ -2099,6 +2109,13 @@ static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info) | ||||
| } | ||||
| 
 | ||||
| /* extent-tree.c */ | ||||
| static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root, | ||||
| 						 int num_items) | ||||
| { | ||||
| 	return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) * | ||||
| 		3 * num_items; | ||||
| } | ||||
| 
 | ||||
| void btrfs_put_block_group(struct btrfs_block_group_cache *cache); | ||||
| int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, | ||||
| 			   struct btrfs_root *root, unsigned long count); | ||||
| @ -2108,12 +2125,9 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, | ||||
| 			     u64 num_bytes, u64 *refs, u64 *flags); | ||||
| int btrfs_pin_extent(struct btrfs_root *root, | ||||
| 		     u64 bytenr, u64 num, int reserved); | ||||
| int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans, | ||||
| 			struct btrfs_root *root, struct extent_buffer *leaf); | ||||
| int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans, | ||||
| 			  struct btrfs_root *root, | ||||
| 			  u64 objectid, u64 offset, u64 bytenr); | ||||
| int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy); | ||||
| struct btrfs_block_group_cache *btrfs_lookup_block_group( | ||||
| 						 struct btrfs_fs_info *info, | ||||
| 						 u64 bytenr); | ||||
| @ -2290,10 +2304,12 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, | ||||
| 		       struct btrfs_root *root, struct extent_buffer *parent, | ||||
| 		       int start_slot, int cache_only, u64 *last_ret, | ||||
| 		       struct btrfs_key *progress); | ||||
| void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p); | ||||
| void btrfs_release_path(struct btrfs_path *p); | ||||
| struct btrfs_path *btrfs_alloc_path(void); | ||||
| void btrfs_free_path(struct btrfs_path *p); | ||||
| void btrfs_set_path_blocking(struct btrfs_path *p); | ||||
| void btrfs_clear_path_blocking(struct btrfs_path *p, | ||||
| 			       struct extent_buffer *held); | ||||
| void btrfs_unlock_up_safe(struct btrfs_path *p, int level); | ||||
| 
 | ||||
| int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||||
| @ -2305,13 +2321,12 @@ static inline int btrfs_del_item(struct btrfs_trans_handle *trans, | ||||
| 	return btrfs_del_items(trans, root, path, path->slots[0], 1); | ||||
| } | ||||
| 
 | ||||
| int setup_items_for_insert(struct btrfs_trans_handle *trans, | ||||
| 			   struct btrfs_root *root, struct btrfs_path *path, | ||||
| 			   struct btrfs_key *cpu_key, u32 *data_size, | ||||
| 			   u32 total_data, u32 total_size, int nr); | ||||
| int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root | ||||
| 		      *root, struct btrfs_key *key, void *data, u32 data_size); | ||||
| int btrfs_insert_some_items(struct btrfs_trans_handle *trans, | ||||
| 			    struct btrfs_root *root, | ||||
| 			    struct btrfs_path *path, | ||||
| 			    struct btrfs_key *cpu_key, u32 *data_size, | ||||
| 			    int nr); | ||||
| int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, | ||||
| 			     struct btrfs_root *root, | ||||
| 			     struct btrfs_path *path, | ||||
| @ -2357,8 +2372,6 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root | ||||
| 		      *item); | ||||
| int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct | ||||
| 			 btrfs_root_item *item, struct btrfs_key *key); | ||||
| int btrfs_search_root(struct btrfs_root *root, u64 search_start, | ||||
| 		      u64 *found_objectid); | ||||
| int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid); | ||||
| int btrfs_find_orphan_roots(struct btrfs_root *tree_root); | ||||
| int btrfs_set_root_node(struct btrfs_root_item *item, | ||||
| @ -2368,7 +2381,7 @@ void btrfs_check_and_init_root_item(struct btrfs_root_item *item); | ||||
| /* dir-item.c */ | ||||
| int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, | ||||
| 			  struct btrfs_root *root, const char *name, | ||||
| 			  int name_len, u64 dir, | ||||
| 			  int name_len, struct inode *dir, | ||||
| 			  struct btrfs_key *location, u8 type, u64 index); | ||||
| struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, | ||||
| 					     struct btrfs_root *root, | ||||
| @ -2413,12 +2426,6 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle *trans, | ||||
| 			  struct btrfs_root *root, u64 offset); | ||||
| int btrfs_find_orphan_item(struct btrfs_root *root, u64 offset); | ||||
| 
 | ||||
| /* inode-map.c */ | ||||
| int btrfs_find_free_objectid(struct btrfs_trans_handle *trans, | ||||
| 			     struct btrfs_root *fs_root, | ||||
| 			     u64 dirid, u64 *objectid); | ||||
| int btrfs_find_highest_inode(struct btrfs_root *fs_root, u64 *objectid); | ||||
| 
 | ||||
| /* inode-item.c */ | ||||
| int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, | ||||
| 			   struct btrfs_root *root, | ||||
| @ -2463,8 +2470,6 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, | ||||
| 			   struct btrfs_ordered_sum *sums); | ||||
| int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | ||||
| 		       struct bio *bio, u64 file_start, int contig); | ||||
| int btrfs_csum_file_bytes(struct btrfs_root *root, struct inode *inode, | ||||
| 			  u64 start, unsigned long len); | ||||
| struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, | ||||
| 					  struct btrfs_root *root, | ||||
| 					  struct btrfs_path *path, | ||||
| @ -2472,8 +2477,8 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, | ||||
| int btrfs_csum_truncate(struct btrfs_trans_handle *trans, | ||||
| 			struct btrfs_root *root, struct btrfs_path *path, | ||||
| 			u64 isize); | ||||
| int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, | ||||
| 			     u64 end, struct list_head *list); | ||||
| int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, | ||||
| 			     struct list_head *list, int search_commit); | ||||
| /* inode.c */ | ||||
| 
 | ||||
| /* RHEL and EL kernels have a patch that renames PG_checked to FsMisc */ | ||||
| @ -2502,8 +2507,6 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, | ||||
| 			       u32 min_type); | ||||
| 
 | ||||
| int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput); | ||||
| int btrfs_start_one_delalloc_inode(struct btrfs_root *root, int delay_iput, | ||||
| 				   int sync); | ||||
| int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end, | ||||
| 			      struct extent_state **cached_state); | ||||
| int btrfs_writepages(struct address_space *mapping, | ||||
| @ -2520,7 +2523,6 @@ unsigned long btrfs_force_ra(struct address_space *mapping, | ||||
| int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); | ||||
| int btrfs_readpage(struct file *file, struct page *page); | ||||
| void btrfs_evict_inode(struct inode *inode); | ||||
| void btrfs_put_inode(struct inode *inode); | ||||
| int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc); | ||||
| void btrfs_dirty_inode(struct inode *inode); | ||||
| struct inode *btrfs_alloc_inode(struct super_block *sb); | ||||
| @ -2531,10 +2533,8 @@ void btrfs_destroy_cachep(void); | ||||
| long btrfs_ioctl_trans_end(struct file *file); | ||||
| struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, | ||||
| 			 struct btrfs_root *root, int *was_new); | ||||
| int btrfs_commit_write(struct file *file, struct page *page, | ||||
| 		       unsigned from, unsigned to); | ||||
| struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, | ||||
| 				    size_t page_offset, u64 start, u64 end, | ||||
| 				    size_t pg_offset, u64 start, u64 end, | ||||
| 				    int create); | ||||
| int btrfs_update_inode(struct btrfs_trans_handle *trans, | ||||
| 			      struct btrfs_root *root, | ||||
| @ -2566,12 +2566,16 @@ extern const struct dentry_operations btrfs_dentry_operations; | ||||
| long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); | ||||
| void btrfs_update_iflags(struct inode *inode); | ||||
| void btrfs_inherit_iflags(struct inode *inode, struct inode *dir); | ||||
| 
 | ||||
| int btrfs_defrag_file(struct inode *inode, struct file *file, | ||||
| 		      struct btrfs_ioctl_defrag_range_args *range, | ||||
| 		      u64 newer_than, unsigned long max_pages); | ||||
| /* file.c */ | ||||
| int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, | ||||
| 			   struct inode *inode); | ||||
| int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info); | ||||
| int btrfs_sync_file(struct file *file, int datasync); | ||||
| int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, | ||||
| 			    int skip_pinned); | ||||
| int btrfs_check_file(struct btrfs_root *root, struct inode *inode); | ||||
| extern const struct file_operations btrfs_file_operations; | ||||
| int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode, | ||||
| 		       u64 start, u64 end, u64 *hint_byte, int drop_cache); | ||||
| @ -2591,10 +2595,6 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | ||||
| /* sysfs.c */ | ||||
| int btrfs_init_sysfs(void); | ||||
| void btrfs_exit_sysfs(void); | ||||
| int btrfs_sysfs_add_super(struct btrfs_fs_info *fs); | ||||
| int btrfs_sysfs_add_root(struct btrfs_root *root); | ||||
| void btrfs_sysfs_del_root(struct btrfs_root *root); | ||||
| void btrfs_sysfs_del_super(struct btrfs_fs_info *root); | ||||
| 
 | ||||
| /* xattr.c */ | ||||
| ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size); | ||||
| @ -2637,4 +2637,18 @@ void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans, | ||||
| 			      u64 *bytes_to_reserve); | ||||
| void btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans, | ||||
| 			      struct btrfs_pending_snapshot *pending); | ||||
| 
 | ||||
| /* scrub.c */ | ||||
| int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end, | ||||
| 		    struct btrfs_scrub_progress *progress, int readonly); | ||||
| int btrfs_scrub_pause(struct btrfs_root *root); | ||||
| int btrfs_scrub_pause_super(struct btrfs_root *root); | ||||
| int btrfs_scrub_continue(struct btrfs_root *root); | ||||
| int btrfs_scrub_continue_super(struct btrfs_root *root); | ||||
| int btrfs_scrub_cancel(struct btrfs_root *root); | ||||
| int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev); | ||||
| int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid); | ||||
| int btrfs_scrub_progress(struct btrfs_root *root, u64 devid, | ||||
| 			 struct btrfs_scrub_progress *progress); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										1695
									
								
								fs/btrfs/delayed-inode.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1695
									
								
								fs/btrfs/delayed-inode.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										141
									
								
								fs/btrfs/delayed-inode.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								fs/btrfs/delayed-inode.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,141 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2011 Fujitsu.  All rights reserved. | ||||
|  * Written by Miao Xie <miaox@cn.fujitsu.com> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public | ||||
|  * License v2 as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public | ||||
|  * License along with this program; if not, write to the | ||||
|  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||||
|  * Boston, MA 021110-1307, USA. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __DELAYED_TREE_OPERATION_H | ||||
| #define __DELAYED_TREE_OPERATION_H | ||||
| 
 | ||||
| #include <linux/rbtree.h> | ||||
| #include <linux/spinlock.h> | ||||
| #include <linux/mutex.h> | ||||
| #include <linux/list.h> | ||||
| #include <linux/wait.h> | ||||
| #include <asm/atomic.h> | ||||
| 
 | ||||
| #include "ctree.h" | ||||
| 
 | ||||
| /* types of the delayed item */ | ||||
| #define BTRFS_DELAYED_INSERTION_ITEM	1 | ||||
| #define BTRFS_DELAYED_DELETION_ITEM	2 | ||||
| 
 | ||||
| struct btrfs_delayed_root { | ||||
| 	spinlock_t lock; | ||||
| 	struct list_head node_list; | ||||
| 	/*
 | ||||
| 	 * Used for delayed nodes which is waiting to be dealt with by the | ||||
| 	 * worker. If the delayed node is inserted into the work queue, we | ||||
| 	 * drop it from this list. | ||||
| 	 */ | ||||
| 	struct list_head prepare_list; | ||||
| 	atomic_t items;		/* for delayed items */ | ||||
| 	int nodes;		/* for delayed nodes */ | ||||
| 	wait_queue_head_t wait; | ||||
| }; | ||||
| 
 | ||||
| struct btrfs_delayed_node { | ||||
| 	u64 inode_id; | ||||
| 	u64 bytes_reserved; | ||||
| 	struct btrfs_root *root; | ||||
| 	/* Used to add the node into the delayed root's node list. */ | ||||
| 	struct list_head n_list; | ||||
| 	/*
 | ||||
| 	 * Used to add the node into the prepare list, the nodes in this list | ||||
| 	 * is waiting to be dealt with by the async worker. | ||||
| 	 */ | ||||
| 	struct list_head p_list; | ||||
| 	struct rb_root ins_root; | ||||
| 	struct rb_root del_root; | ||||
| 	struct mutex mutex; | ||||
| 	struct btrfs_inode_item inode_item; | ||||
| 	atomic_t refs; | ||||
| 	u64 index_cnt; | ||||
| 	bool in_list; | ||||
| 	bool inode_dirty; | ||||
| 	int count; | ||||
| }; | ||||
| 
 | ||||
| struct btrfs_delayed_item { | ||||
| 	struct rb_node rb_node; | ||||
| 	struct btrfs_key key; | ||||
| 	struct list_head tree_list;	/* used for batch insert/delete items */ | ||||
| 	struct list_head readdir_list;	/* used for readdir items */ | ||||
| 	u64 bytes_reserved; | ||||
| 	struct btrfs_block_rsv *block_rsv; | ||||
| 	struct btrfs_delayed_node *delayed_node; | ||||
| 	atomic_t refs; | ||||
| 	int ins_or_del; | ||||
| 	u32 data_len; | ||||
| 	char data[0]; | ||||
| }; | ||||
| 
 | ||||
| static inline void btrfs_init_delayed_root( | ||||
| 				struct btrfs_delayed_root *delayed_root) | ||||
| { | ||||
| 	atomic_set(&delayed_root->items, 0); | ||||
| 	delayed_root->nodes = 0; | ||||
| 	spin_lock_init(&delayed_root->lock); | ||||
| 	init_waitqueue_head(&delayed_root->wait); | ||||
| 	INIT_LIST_HEAD(&delayed_root->node_list); | ||||
| 	INIT_LIST_HEAD(&delayed_root->prepare_list); | ||||
| } | ||||
| 
 | ||||
| int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, | ||||
| 				   struct btrfs_root *root, const char *name, | ||||
| 				   int name_len, struct inode *dir, | ||||
| 				   struct btrfs_disk_key *disk_key, u8 type, | ||||
| 				   u64 index); | ||||
| 
 | ||||
| int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans, | ||||
| 				   struct btrfs_root *root, struct inode *dir, | ||||
| 				   u64 index); | ||||
| 
 | ||||
| int btrfs_inode_delayed_dir_index_count(struct inode *inode); | ||||
| 
 | ||||
| int btrfs_run_delayed_items(struct btrfs_trans_handle *trans, | ||||
| 			    struct btrfs_root *root); | ||||
| 
 | ||||
| void btrfs_balance_delayed_items(struct btrfs_root *root); | ||||
| 
 | ||||
| int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, | ||||
| 				     struct inode *inode); | ||||
| /* Used for evicting the inode. */ | ||||
| void btrfs_remove_delayed_node(struct inode *inode); | ||||
| void btrfs_kill_delayed_inode_items(struct inode *inode); | ||||
| 
 | ||||
| 
 | ||||
| int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans, | ||||
| 			       struct btrfs_root *root, struct inode *inode); | ||||
| 
 | ||||
| /* Used for drop dead root */ | ||||
| void btrfs_kill_all_delayed_nodes(struct btrfs_root *root); | ||||
| 
 | ||||
| /* Used for readdir() */ | ||||
| void btrfs_get_delayed_items(struct inode *inode, struct list_head *ins_list, | ||||
| 			     struct list_head *del_list); | ||||
| void btrfs_put_delayed_items(struct list_head *ins_list, | ||||
| 			     struct list_head *del_list); | ||||
| int btrfs_should_delete_dir_index(struct list_head *del_list, | ||||
| 				  u64 index); | ||||
| int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent, | ||||
| 				    filldir_t filldir, | ||||
| 				    struct list_head *ins_list); | ||||
| 
 | ||||
| /* for init */ | ||||
| int __init btrfs_delayed_inode_init(void); | ||||
| void btrfs_delayed_inode_exit(void); | ||||
| #endif | ||||
| @ -280,44 +280,6 @@ again: | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * This checks to see if there are any delayed refs in the | ||||
|  * btree for a given bytenr.  It returns one if it finds any | ||||
|  * and zero otherwise. | ||||
|  * | ||||
|  * If it only finds a head node, it returns 0. | ||||
|  * | ||||
|  * The idea is to use this when deciding if you can safely delete an | ||||
|  * extent from the extent allocation tree.  There may be a pending | ||||
|  * ref in the rbtree that adds or removes references, so as long as this | ||||
|  * returns one you need to leave the BTRFS_EXTENT_ITEM in the extent | ||||
|  * allocation tree. | ||||
|  */ | ||||
| int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr) | ||||
| { | ||||
| 	struct btrfs_delayed_ref_node *ref; | ||||
| 	struct btrfs_delayed_ref_root *delayed_refs; | ||||
| 	struct rb_node *prev_node; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	delayed_refs = &trans->transaction->delayed_refs; | ||||
| 	spin_lock(&delayed_refs->lock); | ||||
| 
 | ||||
| 	ref = find_ref_head(&delayed_refs->root, bytenr, NULL); | ||||
| 	if (ref) { | ||||
| 		prev_node = rb_prev(&ref->rb_node); | ||||
| 		if (!prev_node) | ||||
| 			goto out; | ||||
| 		ref = rb_entry(prev_node, struct btrfs_delayed_ref_node, | ||||
| 			       rb_node); | ||||
| 		if (ref->bytenr == bytenr) | ||||
| 			ret = 1; | ||||
| 	} | ||||
| out: | ||||
| 	spin_unlock(&delayed_refs->lock); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * helper function to update an extent delayed ref in the | ||||
|  * rbtree.  existing and update must both have the same | ||||
| @ -747,79 +709,3 @@ btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr) | ||||
| 		return btrfs_delayed_node_to_head(ref); | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * add a delayed ref to the tree.  This does all of the accounting required | ||||
|  * to make sure the delayed ref is eventually processed before this | ||||
|  * transaction commits. | ||||
|  * | ||||
|  * The main point of this call is to add and remove a backreference in a single | ||||
|  * shot, taking the lock only once, and only searching for the head node once. | ||||
|  * | ||||
|  * It is the same as doing a ref add and delete in two separate calls. | ||||
|  */ | ||||
| #if 0 | ||||
| int btrfs_update_delayed_ref(struct btrfs_trans_handle *trans, | ||||
| 			  u64 bytenr, u64 num_bytes, u64 orig_parent, | ||||
| 			  u64 parent, u64 orig_ref_root, u64 ref_root, | ||||
| 			  u64 orig_ref_generation, u64 ref_generation, | ||||
| 			  u64 owner_objectid, int pin) | ||||
| { | ||||
| 	struct btrfs_delayed_ref *ref; | ||||
| 	struct btrfs_delayed_ref *old_ref; | ||||
| 	struct btrfs_delayed_ref_head *head_ref; | ||||
| 	struct btrfs_delayed_ref_root *delayed_refs; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ref = kmalloc(sizeof(*ref), GFP_NOFS); | ||||
| 	if (!ref) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	old_ref = kmalloc(sizeof(*old_ref), GFP_NOFS); | ||||
| 	if (!old_ref) { | ||||
| 		kfree(ref); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * the parent = 0 case comes from cases where we don't actually | ||||
| 	 * know the parent yet.  It will get updated later via a add/drop | ||||
| 	 * pair. | ||||
| 	 */ | ||||
| 	if (parent == 0) | ||||
| 		parent = bytenr; | ||||
| 	if (orig_parent == 0) | ||||
| 		orig_parent = bytenr; | ||||
| 
 | ||||
| 	head_ref = kmalloc(sizeof(*head_ref), GFP_NOFS); | ||||
| 	if (!head_ref) { | ||||
| 		kfree(ref); | ||||
| 		kfree(old_ref); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 	delayed_refs = &trans->transaction->delayed_refs; | ||||
| 	spin_lock(&delayed_refs->lock); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * insert both the head node and the new ref without dropping | ||||
| 	 * the spin lock | ||||
| 	 */ | ||||
| 	ret = __btrfs_add_delayed_ref(trans, &head_ref->node, bytenr, num_bytes, | ||||
| 				      (u64)-1, 0, 0, 0, | ||||
| 				      BTRFS_UPDATE_DELAYED_HEAD, 0); | ||||
| 	BUG_ON(ret); | ||||
| 
 | ||||
| 	ret = __btrfs_add_delayed_ref(trans, &ref->node, bytenr, num_bytes, | ||||
| 				      parent, ref_root, ref_generation, | ||||
| 				      owner_objectid, BTRFS_ADD_DELAYED_REF, 0); | ||||
| 	BUG_ON(ret); | ||||
| 
 | ||||
| 	ret = __btrfs_add_delayed_ref(trans, &old_ref->node, bytenr, num_bytes, | ||||
| 				      orig_parent, orig_ref_root, | ||||
| 				      orig_ref_generation, owner_objectid, | ||||
| 				      BTRFS_DROP_DELAYED_REF, pin); | ||||
| 	BUG_ON(ret); | ||||
| 	spin_unlock(&delayed_refs->lock); | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -166,12 +166,6 @@ int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans, | ||||
| 
 | ||||
| struct btrfs_delayed_ref_head * | ||||
| btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr); | ||||
| int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr); | ||||
| int btrfs_update_delayed_ref(struct btrfs_trans_handle *trans, | ||||
| 			  u64 bytenr, u64 num_bytes, u64 orig_parent, | ||||
| 			  u64 parent, u64 orig_ref_root, u64 ref_root, | ||||
| 			  u64 orig_ref_generation, u64 ref_generation, | ||||
| 			  u64 owner_objectid, int pin); | ||||
| int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans, | ||||
| 			   struct btrfs_delayed_ref_head *head); | ||||
| int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans, | ||||
|  | ||||
| @ -50,7 +50,6 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle | ||||
| 		if (di) | ||||
| 			return ERR_PTR(-EEXIST); | ||||
| 		ret = btrfs_extend_item(trans, root, path, data_size); | ||||
| 		WARN_ON(ret > 0); | ||||
| 	} | ||||
| 	if (ret < 0) | ||||
| 		return ERR_PTR(ret); | ||||
| @ -124,8 +123,9 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, | ||||
|  * to use for the second index (if one is created). | ||||
|  */ | ||||
| int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root | ||||
| 			  *root, const char *name, int name_len, u64 dir, | ||||
| 			  struct btrfs_key *location, u8 type, u64 index) | ||||
| 			  *root, const char *name, int name_len, | ||||
| 			  struct inode *dir, struct btrfs_key *location, | ||||
| 			  u8 type, u64 index) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	int ret2 = 0; | ||||
| @ -137,13 +137,17 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root | ||||
| 	struct btrfs_disk_key disk_key; | ||||
| 	u32 data_size; | ||||
| 
 | ||||
| 	key.objectid = dir; | ||||
| 	key.objectid = btrfs_ino(dir); | ||||
| 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); | ||||
| 	key.offset = btrfs_name_hash(name, name_len); | ||||
| 
 | ||||
| 	path = btrfs_alloc_path(); | ||||
| 	if (!path) | ||||
| 		return -ENOMEM; | ||||
| 	path->leave_spinning = 1; | ||||
| 
 | ||||
| 	btrfs_cpu_key_to_disk(&disk_key, location); | ||||
| 
 | ||||
| 	data_size = sizeof(*dir_item) + name_len; | ||||
| 	dir_item = insert_with_overflow(trans, root, path, &key, data_size, | ||||
| 					name, name_len); | ||||
| @ -155,7 +159,6 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root | ||||
| 	} | ||||
| 
 | ||||
| 	leaf = path->nodes[0]; | ||||
| 	btrfs_cpu_key_to_disk(&disk_key, location); | ||||
| 	btrfs_set_dir_item_key(leaf, dir_item, &disk_key); | ||||
| 	btrfs_set_dir_type(leaf, dir_item, type); | ||||
| 	btrfs_set_dir_data_len(leaf, dir_item, 0); | ||||
| @ -172,29 +175,11 @@ second_insert: | ||||
| 		ret = 0; | ||||
| 		goto out_free; | ||||
| 	} | ||||
| 	btrfs_release_path(root, path); | ||||
| 
 | ||||
| 	btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY); | ||||
| 	key.offset = index; | ||||
| 	dir_item = insert_with_overflow(trans, root, path, &key, data_size, | ||||
| 					name, name_len); | ||||
| 	if (IS_ERR(dir_item)) { | ||||
| 		ret2 = PTR_ERR(dir_item); | ||||
| 		goto out_free; | ||||
| 	} | ||||
| 	leaf = path->nodes[0]; | ||||
| 	btrfs_cpu_key_to_disk(&disk_key, location); | ||||
| 	btrfs_set_dir_item_key(leaf, dir_item, &disk_key); | ||||
| 	btrfs_set_dir_type(leaf, dir_item, type); | ||||
| 	btrfs_set_dir_data_len(leaf, dir_item, 0); | ||||
| 	btrfs_set_dir_name_len(leaf, dir_item, name_len); | ||||
| 	btrfs_set_dir_transid(leaf, dir_item, trans->transid); | ||||
| 	name_ptr = (unsigned long)(dir_item + 1); | ||||
| 	write_extent_buffer(leaf, name, name_ptr, name_len); | ||||
| 	btrfs_mark_buffer_dirty(leaf); | ||||
| 	btrfs_release_path(path); | ||||
| 
 | ||||
| 	ret2 = btrfs_insert_delayed_dir_index(trans, root, name, name_len, dir, | ||||
| 					      &disk_key, type, index); | ||||
| out_free: | ||||
| 
 | ||||
| 	btrfs_free_path(path); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| @ -452,7 +437,7 @@ int verify_dir_item(struct btrfs_root *root, | ||||
| 		namelen = XATTR_NAME_MAX; | ||||
| 
 | ||||
| 	if (btrfs_dir_name_len(leaf, dir_item) > namelen) { | ||||
| 		printk(KERN_CRIT "btrfS: invalid dir item name len: %u\n", | ||||
| 		printk(KERN_CRIT "btrfs: invalid dir item name len: %u\n", | ||||
| 		       (unsigned)btrfs_dir_data_len(leaf, dir_item)); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| @ -29,6 +29,7 @@ | ||||
| #include <linux/crc32c.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/migrate.h> | ||||
| #include <linux/ratelimit.h> | ||||
| #include <asm/unaligned.h> | ||||
| #include "compat.h" | ||||
| #include "ctree.h" | ||||
| @ -41,6 +42,7 @@ | ||||
| #include "locking.h" | ||||
| #include "tree-log.h" | ||||
| #include "free-space-cache.h" | ||||
| #include "inode-map.h" | ||||
| 
 | ||||
| static struct extent_io_ops btree_extent_io_ops; | ||||
| static void end_workqueue_fn(struct btrfs_work *work); | ||||
| @ -137,7 +139,7 @@ static const char *btrfs_eb_name[BTRFS_MAX_LEVEL + 1] = { | ||||
|  * that covers the entire device | ||||
|  */ | ||||
| static struct extent_map *btree_get_extent(struct inode *inode, | ||||
| 		struct page *page, size_t page_offset, u64 start, u64 len, | ||||
| 		struct page *page, size_t pg_offset, u64 start, u64 len, | ||||
| 		int create) | ||||
| { | ||||
| 	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | ||||
| @ -154,7 +156,7 @@ static struct extent_map *btree_get_extent(struct inode *inode, | ||||
| 	} | ||||
| 	read_unlock(&em_tree->lock); | ||||
| 
 | ||||
| 	em = alloc_extent_map(GFP_NOFS); | ||||
| 	em = alloc_extent_map(); | ||||
| 	if (!em) { | ||||
| 		em = ERR_PTR(-ENOMEM); | ||||
| 		goto out; | ||||
| @ -254,14 +256,12 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, | ||||
| 			memcpy(&found, result, csum_size); | ||||
| 
 | ||||
| 			read_extent_buffer(buf, &val, 0, csum_size); | ||||
| 			if (printk_ratelimit()) { | ||||
| 				printk(KERN_INFO "btrfs: %s checksum verify " | ||||
| 			printk_ratelimited(KERN_INFO "btrfs: %s checksum verify " | ||||
| 				       "failed on %llu wanted %X found %X " | ||||
| 				       "level %d\n", | ||||
| 				       root->fs_info->sb->s_id, | ||||
| 				       (unsigned long long)buf->start, val, found, | ||||
| 				       btrfs_header_level(buf)); | ||||
| 			} | ||||
| 			if (result != (char *)&inline_result) | ||||
| 				kfree(result); | ||||
| 			return 1; | ||||
| @ -296,13 +296,11 @@ static int verify_parent_transid(struct extent_io_tree *io_tree, | ||||
| 		ret = 0; | ||||
| 		goto out; | ||||
| 	} | ||||
| 	if (printk_ratelimit()) { | ||||
| 		printk("parent transid verify failed on %llu wanted %llu " | ||||
| 	printk_ratelimited("parent transid verify failed on %llu wanted %llu " | ||||
| 		       "found %llu\n", | ||||
| 		       (unsigned long long)eb->start, | ||||
| 		       (unsigned long long)parent_transid, | ||||
| 		       (unsigned long long)btrfs_header_generation(eb)); | ||||
| 	} | ||||
| 	ret = 1; | ||||
| 	clear_extent_buffer_uptodate(io_tree, eb, &cached_state); | ||||
| out: | ||||
| @ -380,7 +378,7 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page) | ||||
| 	len = page->private >> 2; | ||||
| 	WARN_ON(len == 0); | ||||
| 
 | ||||
| 	eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS); | ||||
| 	eb = alloc_extent_buffer(tree, start, len, page); | ||||
| 	if (eb == NULL) { | ||||
| 		WARN_ON(1); | ||||
| 		goto out; | ||||
| @ -525,7 +523,7 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, | ||||
| 	len = page->private >> 2; | ||||
| 	WARN_ON(len == 0); | ||||
| 
 | ||||
| 	eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS); | ||||
| 	eb = alloc_extent_buffer(tree, start, len, page); | ||||
| 	if (eb == NULL) { | ||||
| 		ret = -EIO; | ||||
| 		goto out; | ||||
| @ -533,12 +531,10 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, | ||||
| 
 | ||||
| 	found_start = btrfs_header_bytenr(eb); | ||||
| 	if (found_start != start) { | ||||
| 		if (printk_ratelimit()) { | ||||
| 			printk(KERN_INFO "btrfs bad tree block start " | ||||
| 		printk_ratelimited(KERN_INFO "btrfs bad tree block start " | ||||
| 			       "%llu %llu\n", | ||||
| 			       (unsigned long long)found_start, | ||||
| 			       (unsigned long long)eb->start); | ||||
| 		} | ||||
| 		ret = -EIO; | ||||
| 		goto err; | ||||
| 	} | ||||
| @ -550,10 +546,8 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, | ||||
| 		goto err; | ||||
| 	} | ||||
| 	if (check_tree_block_fsid(root, eb)) { | ||||
| 		if (printk_ratelimit()) { | ||||
| 			printk(KERN_INFO "btrfs bad fsid on block %llu\n", | ||||
| 		printk_ratelimited(KERN_INFO "btrfs bad fsid on block %llu\n", | ||||
| 			       (unsigned long long)eb->start); | ||||
| 		} | ||||
| 		ret = -EIO; | ||||
| 		goto err; | ||||
| 	} | ||||
| @ -650,12 +644,6 @@ unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info) | ||||
| 	return 256 * limit; | ||||
| } | ||||
| 
 | ||||
| int btrfs_congested_async(struct btrfs_fs_info *info, int iodone) | ||||
| { | ||||
| 	return atomic_read(&info->nr_async_bios) > | ||||
| 		btrfs_async_submit_limit(info); | ||||
| } | ||||
| 
 | ||||
| static void run_one_async_start(struct btrfs_work *work) | ||||
| { | ||||
| 	struct async_submit_bio *async; | ||||
| @ -963,7 +951,7 @@ struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, | ||||
| 	struct inode *btree_inode = root->fs_info->btree_inode; | ||||
| 	struct extent_buffer *eb; | ||||
| 	eb = find_extent_buffer(&BTRFS_I(btree_inode)->io_tree, | ||||
| 				bytenr, blocksize, GFP_NOFS); | ||||
| 				bytenr, blocksize); | ||||
| 	return eb; | ||||
| } | ||||
| 
 | ||||
| @ -974,7 +962,7 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, | ||||
| 	struct extent_buffer *eb; | ||||
| 
 | ||||
| 	eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->io_tree, | ||||
| 				 bytenr, blocksize, NULL, GFP_NOFS); | ||||
| 				 bytenr, blocksize, NULL); | ||||
| 	return eb; | ||||
| } | ||||
| 
 | ||||
| @ -1058,13 +1046,13 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, | ||||
| 	root->name = NULL; | ||||
| 	root->in_sysfs = 0; | ||||
| 	root->inode_tree = RB_ROOT; | ||||
| 	INIT_RADIX_TREE(&root->delayed_nodes_tree, GFP_ATOMIC); | ||||
| 	root->block_rsv = NULL; | ||||
| 	root->orphan_block_rsv = NULL; | ||||
| 
 | ||||
| 	INIT_LIST_HEAD(&root->dirty_list); | ||||
| 	INIT_LIST_HEAD(&root->orphan_list); | ||||
| 	INIT_LIST_HEAD(&root->root_list); | ||||
| 	spin_lock_init(&root->node_lock); | ||||
| 	spin_lock_init(&root->orphan_lock); | ||||
| 	spin_lock_init(&root->inode_lock); | ||||
| 	spin_lock_init(&root->accounting_lock); | ||||
| @ -1080,7 +1068,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, | ||||
| 	root->log_transid = 0; | ||||
| 	root->last_log_commit = 0; | ||||
| 	extent_io_tree_init(&root->dirty_log_pages, | ||||
| 			     fs_info->btree_inode->i_mapping, GFP_NOFS); | ||||
| 			     fs_info->btree_inode->i_mapping); | ||||
| 
 | ||||
| 	memset(&root->root_key, 0, sizeof(root->root_key)); | ||||
| 	memset(&root->root_item, 0, sizeof(root->root_item)); | ||||
| @ -1283,21 +1271,6 @@ out: | ||||
| 	return root; | ||||
| } | ||||
| 
 | ||||
| struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, | ||||
| 					u64 root_objectid) | ||||
| { | ||||
| 	struct btrfs_root *root; | ||||
| 
 | ||||
| 	if (root_objectid == BTRFS_ROOT_TREE_OBJECTID) | ||||
| 		return fs_info->tree_root; | ||||
| 	if (root_objectid == BTRFS_EXTENT_TREE_OBJECTID) | ||||
| 		return fs_info->extent_root; | ||||
| 
 | ||||
| 	root = radix_tree_lookup(&fs_info->fs_roots_radix, | ||||
| 				 (unsigned long)root_objectid); | ||||
| 	return root; | ||||
| } | ||||
| 
 | ||||
| struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, | ||||
| 					      struct btrfs_key *location) | ||||
| { | ||||
| @ -1326,6 +1299,19 @@ again: | ||||
| 	if (IS_ERR(root)) | ||||
| 		return root; | ||||
| 
 | ||||
| 	root->free_ino_ctl = kzalloc(sizeof(*root->free_ino_ctl), GFP_NOFS); | ||||
| 	if (!root->free_ino_ctl) | ||||
| 		goto fail; | ||||
| 	root->free_ino_pinned = kzalloc(sizeof(*root->free_ino_pinned), | ||||
| 					GFP_NOFS); | ||||
| 	if (!root->free_ino_pinned) | ||||
| 		goto fail; | ||||
| 
 | ||||
| 	btrfs_init_free_ino_ctl(root); | ||||
| 	mutex_init(&root->fs_commit_mutex); | ||||
| 	spin_lock_init(&root->cache_lock); | ||||
| 	init_waitqueue_head(&root->cache_wait); | ||||
| 
 | ||||
| 	set_anon_super(&root->anon_super, NULL); | ||||
| 
 | ||||
| 	if (btrfs_root_refs(&root->root_item) == 0) { | ||||
| @ -1369,41 +1355,6 @@ fail: | ||||
| 	return ERR_PTR(ret); | ||||
| } | ||||
| 
 | ||||
| struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | ||||
| 				      struct btrfs_key *location, | ||||
| 				      const char *name, int namelen) | ||||
| { | ||||
| 	return btrfs_read_fs_root_no_name(fs_info, location); | ||||
| #if 0 | ||||
| 	struct btrfs_root *root; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	root = btrfs_read_fs_root_no_name(fs_info, location); | ||||
| 	if (!root) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	if (root->in_sysfs) | ||||
| 		return root; | ||||
| 
 | ||||
| 	ret = btrfs_set_root_name(root, name, namelen); | ||||
| 	if (ret) { | ||||
| 		free_extent_buffer(root->node); | ||||
| 		kfree(root); | ||||
| 		return ERR_PTR(ret); | ||||
| 	} | ||||
| 
 | ||||
| 	ret = btrfs_sysfs_add_root(root); | ||||
| 	if (ret) { | ||||
| 		free_extent_buffer(root->node); | ||||
| 		kfree(root->name); | ||||
| 		kfree(root); | ||||
| 		return ERR_PTR(ret); | ||||
| 	} | ||||
| 	root->in_sysfs = 1; | ||||
| 	return root; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static int btrfs_congested_fn(void *congested_data, int bdi_bits) | ||||
| { | ||||
| 	struct btrfs_fs_info *info = (struct btrfs_fs_info *)congested_data; | ||||
| @ -1411,7 +1362,8 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits) | ||||
| 	struct btrfs_device *device; | ||||
| 	struct backing_dev_info *bdi; | ||||
| 
 | ||||
| 	list_for_each_entry(device, &info->fs_devices->devices, dev_list) { | ||||
| 	rcu_read_lock(); | ||||
| 	list_for_each_entry_rcu(device, &info->fs_devices->devices, dev_list) { | ||||
| 		if (!device->bdev) | ||||
| 			continue; | ||||
| 		bdi = blk_get_backing_dev_info(device->bdev); | ||||
| @ -1420,6 +1372,7 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits) | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	rcu_read_unlock(); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| @ -1522,6 +1475,7 @@ static int cleaner_kthread(void *arg) | ||||
| 			btrfs_run_delayed_iputs(root); | ||||
| 			btrfs_clean_old_snapshots(root); | ||||
| 			mutex_unlock(&root->fs_info->cleaner_mutex); | ||||
| 			btrfs_run_defrag_inodes(root->fs_info); | ||||
| 		} | ||||
| 
 | ||||
| 		if (freezing(current)) { | ||||
| @ -1611,7 +1565,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | ||||
| 	struct btrfs_root *csum_root = kzalloc(sizeof(struct btrfs_root), | ||||
| 						 GFP_NOFS); | ||||
| 	struct btrfs_root *tree_root = btrfs_sb(sb); | ||||
| 	struct btrfs_fs_info *fs_info = tree_root->fs_info; | ||||
| 	struct btrfs_fs_info *fs_info = NULL; | ||||
| 	struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root), | ||||
| 						GFP_NOFS); | ||||
| 	struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root), | ||||
| @ -1623,11 +1577,12 @@ struct btrfs_root *open_ctree(struct super_block *sb, | ||||
| 
 | ||||
| 	struct btrfs_super_block *disk_super; | ||||
| 
 | ||||
| 	if (!extent_root || !tree_root || !fs_info || | ||||
| 	if (!extent_root || !tree_root || !tree_root->fs_info || | ||||
| 	    !chunk_root || !dev_root || !csum_root) { | ||||
| 		err = -ENOMEM; | ||||
| 		goto fail; | ||||
| 	} | ||||
| 	fs_info = tree_root->fs_info; | ||||
| 
 | ||||
| 	ret = init_srcu_struct(&fs_info->subvol_srcu); | ||||
| 	if (ret) { | ||||
| @ -1662,6 +1617,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | ||||
| 	spin_lock_init(&fs_info->ref_cache_lock); | ||||
| 	spin_lock_init(&fs_info->fs_roots_radix_lock); | ||||
| 	spin_lock_init(&fs_info->delayed_iput_lock); | ||||
| 	spin_lock_init(&fs_info->defrag_inodes_lock); | ||||
| 
 | ||||
| 	init_completion(&fs_info->kobj_unregister); | ||||
| 	fs_info->tree_root = tree_root; | ||||
| @ -1684,15 +1640,35 @@ struct btrfs_root *open_ctree(struct super_block *sb, | ||||
| 	atomic_set(&fs_info->async_delalloc_pages, 0); | ||||
| 	atomic_set(&fs_info->async_submit_draining, 0); | ||||
| 	atomic_set(&fs_info->nr_async_bios, 0); | ||||
| 	atomic_set(&fs_info->defrag_running, 0); | ||||
| 	fs_info->sb = sb; | ||||
| 	fs_info->max_inline = 8192 * 1024; | ||||
| 	fs_info->metadata_ratio = 0; | ||||
| 	fs_info->defrag_inodes = RB_ROOT; | ||||
| 
 | ||||
| 	fs_info->thread_pool_size = min_t(unsigned long, | ||||
| 					  num_online_cpus() + 2, 8); | ||||
| 
 | ||||
| 	INIT_LIST_HEAD(&fs_info->ordered_extents); | ||||
| 	spin_lock_init(&fs_info->ordered_extent_lock); | ||||
| 	fs_info->delayed_root = kmalloc(sizeof(struct btrfs_delayed_root), | ||||
| 					GFP_NOFS); | ||||
| 	if (!fs_info->delayed_root) { | ||||
| 		err = -ENOMEM; | ||||
| 		goto fail_iput; | ||||
| 	} | ||||
| 	btrfs_init_delayed_root(fs_info->delayed_root); | ||||
| 
 | ||||
| 	mutex_init(&fs_info->scrub_lock); | ||||
| 	atomic_set(&fs_info->scrubs_running, 0); | ||||
| 	atomic_set(&fs_info->scrub_pause_req, 0); | ||||
| 	atomic_set(&fs_info->scrubs_paused, 0); | ||||
| 	atomic_set(&fs_info->scrub_cancel_req, 0); | ||||
| 	init_waitqueue_head(&fs_info->scrub_pause_wait); | ||||
| 	init_rwsem(&fs_info->scrub_super_lock); | ||||
| 	fs_info->scrub_workers_refcnt = 0; | ||||
| 	btrfs_init_workers(&fs_info->scrub_workers, "scrub", | ||||
| 			   fs_info->thread_pool_size, &fs_info->generic_worker); | ||||
| 
 | ||||
| 	sb->s_blocksize = 4096; | ||||
| 	sb->s_blocksize_bits = blksize_bits(4096); | ||||
| @ -1711,10 +1687,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, | ||||
| 
 | ||||
| 	RB_CLEAR_NODE(&BTRFS_I(fs_info->btree_inode)->rb_node); | ||||
| 	extent_io_tree_init(&BTRFS_I(fs_info->btree_inode)->io_tree, | ||||
| 			     fs_info->btree_inode->i_mapping, | ||||
| 			     GFP_NOFS); | ||||
| 	extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree, | ||||
| 			     GFP_NOFS); | ||||
| 			     fs_info->btree_inode->i_mapping); | ||||
| 	extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree); | ||||
| 
 | ||||
| 	BTRFS_I(fs_info->btree_inode)->io_tree.ops = &btree_extent_io_ops; | ||||
| 
 | ||||
| @ -1728,9 +1702,9 @@ struct btrfs_root *open_ctree(struct super_block *sb, | ||||
| 	fs_info->block_group_cache_tree = RB_ROOT; | ||||
| 
 | ||||
| 	extent_io_tree_init(&fs_info->freed_extents[0], | ||||
| 			     fs_info->btree_inode->i_mapping, GFP_NOFS); | ||||
| 			     fs_info->btree_inode->i_mapping); | ||||
| 	extent_io_tree_init(&fs_info->freed_extents[1], | ||||
| 			     fs_info->btree_inode->i_mapping, GFP_NOFS); | ||||
| 			     fs_info->btree_inode->i_mapping); | ||||
| 	fs_info->pinned_extents = &fs_info->freed_extents[0]; | ||||
| 	fs_info->do_barriers = 1; | ||||
| 
 | ||||
| @ -1760,7 +1734,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | ||||
| 	bh = btrfs_read_dev_super(fs_devices->latest_bdev); | ||||
| 	if (!bh) { | ||||
| 		err = -EINVAL; | ||||
| 		goto fail_iput; | ||||
| 		goto fail_alloc; | ||||
| 	} | ||||
| 
 | ||||
| 	memcpy(&fs_info->super_copy, bh->b_data, sizeof(fs_info->super_copy)); | ||||
| @ -1772,7 +1746,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | ||||
| 
 | ||||
| 	disk_super = &fs_info->super_copy; | ||||
| 	if (!btrfs_super_root(disk_super)) | ||||
| 		goto fail_iput; | ||||
| 		goto fail_alloc; | ||||
| 
 | ||||
| 	/* check FS state, whether FS is broken. */ | ||||
| 	fs_info->fs_state |= btrfs_super_flags(disk_super); | ||||
| @ -1788,7 +1762,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | ||||
| 	ret = btrfs_parse_options(tree_root, options); | ||||
| 	if (ret) { | ||||
| 		err = ret; | ||||
| 		goto fail_iput; | ||||
| 		goto fail_alloc; | ||||
| 	} | ||||
| 
 | ||||
| 	features = btrfs_super_incompat_flags(disk_super) & | ||||
| @ -1798,7 +1772,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | ||||
| 		       "unsupported optional features (%Lx).\n", | ||||
| 		       (unsigned long long)features); | ||||
| 		err = -EINVAL; | ||||
| 		goto fail_iput; | ||||
| 		goto fail_alloc; | ||||
| 	} | ||||
| 
 | ||||
| 	features = btrfs_super_incompat_flags(disk_super); | ||||
| @ -1814,7 +1788,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | ||||
| 		       "unsupported option features (%Lx).\n", | ||||
| 		       (unsigned long long)features); | ||||
| 		err = -EINVAL; | ||||
| 		goto fail_iput; | ||||
| 		goto fail_alloc; | ||||
| 	} | ||||
| 
 | ||||
| 	btrfs_init_workers(&fs_info->generic_worker, | ||||
| @ -1861,6 +1835,9 @@ struct btrfs_root *open_ctree(struct super_block *sb, | ||||
| 			   &fs_info->generic_worker); | ||||
| 	btrfs_init_workers(&fs_info->endio_freespace_worker, "freespace-write", | ||||
| 			   1, &fs_info->generic_worker); | ||||
| 	btrfs_init_workers(&fs_info->delayed_workers, "delayed-meta", | ||||
| 			   fs_info->thread_pool_size, | ||||
| 			   &fs_info->generic_worker); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * endios are largely parallel and should have a very | ||||
| @ -1882,6 +1859,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | ||||
| 	btrfs_start_workers(&fs_info->endio_meta_write_workers, 1); | ||||
| 	btrfs_start_workers(&fs_info->endio_write_workers, 1); | ||||
| 	btrfs_start_workers(&fs_info->endio_freespace_worker, 1); | ||||
| 	btrfs_start_workers(&fs_info->delayed_workers, 1); | ||||
| 
 | ||||
| 	fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super); | ||||
| 	fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages, | ||||
| @ -2138,6 +2116,9 @@ fail_sb_buffer: | ||||
| 	btrfs_stop_workers(&fs_info->endio_write_workers); | ||||
| 	btrfs_stop_workers(&fs_info->endio_freespace_worker); | ||||
| 	btrfs_stop_workers(&fs_info->submit_workers); | ||||
| 	btrfs_stop_workers(&fs_info->delayed_workers); | ||||
| fail_alloc: | ||||
| 	kfree(fs_info->delayed_root); | ||||
| fail_iput: | ||||
| 	invalidate_inode_pages2(fs_info->btree_inode->i_mapping); | ||||
| 	iput(fs_info->btree_inode); | ||||
| @ -2165,11 +2146,9 @@ static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate) | ||||
| 	if (uptodate) { | ||||
| 		set_buffer_uptodate(bh); | ||||
| 	} else { | ||||
| 		if (printk_ratelimit()) { | ||||
| 			printk(KERN_WARNING "lost page write due to " | ||||
| 		printk_ratelimited(KERN_WARNING "lost page write due to " | ||||
| 					"I/O error on %s\n", | ||||
| 				       bdevname(bh->b_bdev, b)); | ||||
| 		} | ||||
| 		/* note, we dont' set_buffer_write_io_error because we have
 | ||||
| 		 * our own ways of dealing with the IO errors | ||||
| 		 */ | ||||
| @ -2333,7 +2312,7 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors) | ||||
| 
 | ||||
| 	mutex_lock(&root->fs_info->fs_devices->device_list_mutex); | ||||
| 	head = &root->fs_info->fs_devices->devices; | ||||
| 	list_for_each_entry(dev, head, dev_list) { | ||||
| 	list_for_each_entry_rcu(dev, head, dev_list) { | ||||
| 		if (!dev->bdev) { | ||||
| 			total_errors++; | ||||
| 			continue; | ||||
| @ -2366,7 +2345,7 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors) | ||||
| 	} | ||||
| 
 | ||||
| 	total_errors = 0; | ||||
| 	list_for_each_entry(dev, head, dev_list) { | ||||
| 	list_for_each_entry_rcu(dev, head, dev_list) { | ||||
| 		if (!dev->bdev) | ||||
| 			continue; | ||||
| 		if (!dev->in_fs_metadata || !dev->writeable) | ||||
| @ -2404,12 +2383,15 @@ int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) | ||||
| 	if (btrfs_root_refs(&root->root_item) == 0) | ||||
| 		synchronize_srcu(&fs_info->subvol_srcu); | ||||
| 
 | ||||
| 	__btrfs_remove_free_space_cache(root->free_ino_pinned); | ||||
| 	__btrfs_remove_free_space_cache(root->free_ino_ctl); | ||||
| 	free_fs_root(root); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void free_fs_root(struct btrfs_root *root) | ||||
| { | ||||
| 	iput(root->cache_inode); | ||||
| 	WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree)); | ||||
| 	if (root->anon_super.s_dev) { | ||||
| 		down_write(&root->anon_super.s_umount); | ||||
| @ -2417,6 +2399,8 @@ static void free_fs_root(struct btrfs_root *root) | ||||
| 	} | ||||
| 	free_extent_buffer(root->node); | ||||
| 	free_extent_buffer(root->commit_root); | ||||
| 	kfree(root->free_ino_ctl); | ||||
| 	kfree(root->free_ino_pinned); | ||||
| 	kfree(root->name); | ||||
| 	kfree(root); | ||||
| } | ||||
| @ -2520,6 +2504,15 @@ int close_ctree(struct btrfs_root *root) | ||||
| 	fs_info->closing = 1; | ||||
| 	smp_mb(); | ||||
| 
 | ||||
| 	btrfs_scrub_cancel(root); | ||||
| 
 | ||||
| 	/* wait for any defraggers to finish */ | ||||
| 	wait_event(fs_info->transaction_wait, | ||||
| 		   (atomic_read(&fs_info->defrag_running) == 0)); | ||||
| 
 | ||||
| 	/* clear out the rbtree of defraggable inodes */ | ||||
| 	btrfs_run_defrag_inodes(root->fs_info); | ||||
| 
 | ||||
| 	btrfs_put_block_group_cache(fs_info); | ||||
| 
 | ||||
| 	/*
 | ||||
| @ -2578,6 +2571,7 @@ int close_ctree(struct btrfs_root *root) | ||||
| 	del_fs_roots(fs_info); | ||||
| 
 | ||||
| 	iput(fs_info->btree_inode); | ||||
| 	kfree(fs_info->delayed_root); | ||||
| 
 | ||||
| 	btrfs_stop_workers(&fs_info->generic_worker); | ||||
| 	btrfs_stop_workers(&fs_info->fixup_workers); | ||||
| @ -2589,6 +2583,7 @@ int close_ctree(struct btrfs_root *root) | ||||
| 	btrfs_stop_workers(&fs_info->endio_write_workers); | ||||
| 	btrfs_stop_workers(&fs_info->endio_freespace_worker); | ||||
| 	btrfs_stop_workers(&fs_info->submit_workers); | ||||
| 	btrfs_stop_workers(&fs_info->delayed_workers); | ||||
| 
 | ||||
| 	btrfs_close_devices(fs_info->fs_devices); | ||||
| 	btrfs_mapping_tree_free(&fs_info->mapping_tree); | ||||
| @ -2662,6 +2657,29 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) | ||||
| 	u64 num_dirty; | ||||
| 	unsigned long thresh = 32 * 1024 * 1024; | ||||
| 
 | ||||
| 	if (current->flags & PF_MEMALLOC) | ||||
| 		return; | ||||
| 
 | ||||
| 	btrfs_balance_delayed_items(root); | ||||
| 
 | ||||
| 	num_dirty = root->fs_info->dirty_metadata_bytes; | ||||
| 
 | ||||
| 	if (num_dirty > thresh) { | ||||
| 		balance_dirty_pages_ratelimited_nr( | ||||
| 				   root->fs_info->btree_inode->i_mapping, 1); | ||||
| 	} | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * looks as though older kernels can get into trouble with | ||||
| 	 * this code, they end up stuck in balance_dirty_pages forever | ||||
| 	 */ | ||||
| 	u64 num_dirty; | ||||
| 	unsigned long thresh = 32 * 1024 * 1024; | ||||
| 
 | ||||
| 	if (current->flags & PF_MEMALLOC) | ||||
| 		return; | ||||
| 
 | ||||
| @ -2697,7 +2715,7 @@ int btree_lock_page_hook(struct page *page) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	len = page->private >> 2; | ||||
| 	eb = find_extent_buffer(io_tree, bytenr, len, GFP_NOFS); | ||||
| 	eb = find_extent_buffer(io_tree, bytenr, len); | ||||
| 	if (!eb) | ||||
| 		goto out; | ||||
| 
 | ||||
|  | ||||
| @ -55,35 +55,20 @@ int btrfs_commit_super(struct btrfs_root *root); | ||||
| int btrfs_error_commit_super(struct btrfs_root *root); | ||||
| struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, | ||||
| 					    u64 bytenr, u32 blocksize); | ||||
| struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, | ||||
| 					u64 root_objectid); | ||||
| 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_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); | ||||
| int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info); | ||||
| int btrfs_insert_dev_radix(struct btrfs_root *root, | ||||
| 			   struct block_device *bdev, | ||||
| 			   u64 device_id, | ||||
| 			   u64 block_start, | ||||
| 			   u64 num_blocks); | ||||
| void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr); | ||||
| void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr); | ||||
| int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root); | ||||
| void btrfs_mark_buffer_dirty(struct extent_buffer *buf); | ||||
| void btrfs_mark_buffer_dirty_nonblocking(struct extent_buffer *buf); | ||||
| int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid); | ||||
| int btrfs_set_buffer_uptodate(struct extent_buffer *buf); | ||||
| int wait_on_tree_block_writeback(struct btrfs_root *root, | ||||
| 				 struct extent_buffer *buf); | ||||
| int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid); | ||||
| u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len); | ||||
| void btrfs_csum_final(u32 crc, char *result); | ||||
| int btrfs_open_device(struct btrfs_device *dev); | ||||
| int btrfs_verify_block_csum(struct btrfs_root *root, | ||||
| 			    struct extent_buffer *buf); | ||||
| int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio, | ||||
| 			int metadata); | ||||
| int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, | ||||
| @ -91,8 +76,6 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, | ||||
| 			unsigned long bio_flags, u64 bio_offset, | ||||
| 			extent_submit_bio_hook_t *submit_bio_start, | ||||
| 			extent_submit_bio_hook_t *submit_bio_done); | ||||
| 
 | ||||
| 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); | ||||
|  | ||||
| @ -32,7 +32,7 @@ static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len, | ||||
| 	len  = BTRFS_FID_SIZE_NON_CONNECTABLE; | ||||
| 	type = FILEID_BTRFS_WITHOUT_PARENT; | ||||
| 
 | ||||
| 	fid->objectid = inode->i_ino; | ||||
| 	fid->objectid = btrfs_ino(inode); | ||||
| 	fid->root_objectid = BTRFS_I(inode)->root->objectid; | ||||
| 	fid->gen = inode->i_generation; | ||||
| 
 | ||||
| @ -178,13 +178,13 @@ static struct dentry *btrfs_get_parent(struct dentry *child) | ||||
| 	if (!path) | ||||
| 		return ERR_PTR(-ENOMEM); | ||||
| 
 | ||||
| 	if (dir->i_ino == BTRFS_FIRST_FREE_OBJECTID) { | ||||
| 	if (btrfs_ino(dir) == BTRFS_FIRST_FREE_OBJECTID) { | ||||
| 		key.objectid = root->root_key.objectid; | ||||
| 		key.type = BTRFS_ROOT_BACKREF_KEY; | ||||
| 		key.offset = (u64)-1; | ||||
| 		root = root->fs_info->tree_root; | ||||
| 	} else { | ||||
| 		key.objectid = dir->i_ino; | ||||
| 		key.objectid = btrfs_ino(dir); | ||||
| 		key.type = BTRFS_INODE_REF_KEY; | ||||
| 		key.offset = (u64)-1; | ||||
| 	} | ||||
| @ -244,6 +244,7 @@ static int btrfs_get_name(struct dentry *parent, char *name, | ||||
| 	struct btrfs_key key; | ||||
| 	int name_len; | ||||
| 	int ret; | ||||
| 	u64 ino; | ||||
| 
 | ||||
| 	if (!dir || !inode) | ||||
| 		return -EINVAL; | ||||
| @ -251,19 +252,21 @@ static int btrfs_get_name(struct dentry *parent, char *name, | ||||
| 	if (!S_ISDIR(dir->i_mode)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	ino = btrfs_ino(inode); | ||||
| 
 | ||||
| 	path = btrfs_alloc_path(); | ||||
| 	if (!path) | ||||
| 		return -ENOMEM; | ||||
| 	path->leave_spinning = 1; | ||||
| 
 | ||||
| 	if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) { | ||||
| 	if (ino == BTRFS_FIRST_FREE_OBJECTID) { | ||||
| 		key.objectid = BTRFS_I(inode)->root->root_key.objectid; | ||||
| 		key.type = BTRFS_ROOT_BACKREF_KEY; | ||||
| 		key.offset = (u64)-1; | ||||
| 		root = root->fs_info->tree_root; | ||||
| 	} else { | ||||
| 		key.objectid = inode->i_ino; | ||||
| 		key.offset = dir->i_ino; | ||||
| 		key.objectid = ino; | ||||
| 		key.offset = btrfs_ino(dir); | ||||
| 		key.type = BTRFS_INODE_REF_KEY; | ||||
| 	} | ||||
| 
 | ||||
| @ -272,7 +275,7 @@ static int btrfs_get_name(struct dentry *parent, char *name, | ||||
| 		btrfs_free_path(path); | ||||
| 		return ret; | ||||
| 	} else if (ret > 0) { | ||||
| 		if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) { | ||||
| 		if (ino == BTRFS_FIRST_FREE_OBJECTID) { | ||||
| 			path->slots[0]--; | ||||
| 		} else { | ||||
| 			btrfs_free_path(path); | ||||
| @ -281,11 +284,11 @@ static int btrfs_get_name(struct dentry *parent, char *name, | ||||
| 	} | ||||
| 	leaf = path->nodes[0]; | ||||
| 
 | ||||
| 	if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) { | ||||
| 	       rref = btrfs_item_ptr(leaf, path->slots[0], | ||||
| 	if (ino == BTRFS_FIRST_FREE_OBJECTID) { | ||||
| 		rref = btrfs_item_ptr(leaf, path->slots[0], | ||||
| 				     struct btrfs_root_ref); | ||||
| 	       name_ptr = (unsigned long)(rref + 1); | ||||
| 	       name_len = btrfs_root_ref_name_len(leaf, rref); | ||||
| 		name_ptr = (unsigned long)(rref + 1); | ||||
| 		name_len = btrfs_root_ref_name_len(leaf, rref); | ||||
| 	} else { | ||||
| 		iref = btrfs_item_ptr(leaf, path->slots[0], | ||||
| 				      struct btrfs_inode_ref); | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -103,7 +103,7 @@ void extent_io_exit(void) | ||||
| } | ||||
| 
 | ||||
| void extent_io_tree_init(struct extent_io_tree *tree, | ||||
| 			  struct address_space *mapping, gfp_t mask) | ||||
| 			 struct address_space *mapping) | ||||
| { | ||||
| 	tree->state = RB_ROOT; | ||||
| 	INIT_RADIX_TREE(&tree->buffer, GFP_ATOMIC); | ||||
| @ -441,6 +441,15 @@ static int clear_state_bit(struct extent_io_tree *tree, | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static struct extent_state * | ||||
| alloc_extent_state_atomic(struct extent_state *prealloc) | ||||
| { | ||||
| 	if (!prealloc) | ||||
| 		prealloc = alloc_extent_state(GFP_ATOMIC); | ||||
| 
 | ||||
| 	return prealloc; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * clear some bits on a range in the tree.  This may require splitting | ||||
|  * or inserting elements in the tree, so the gfp mask is used to | ||||
| @ -531,8 +540,8 @@ hit_next: | ||||
| 	 */ | ||||
| 
 | ||||
| 	if (state->start < start) { | ||||
| 		if (!prealloc) | ||||
| 			prealloc = alloc_extent_state(GFP_ATOMIC); | ||||
| 		prealloc = alloc_extent_state_atomic(prealloc); | ||||
| 		BUG_ON(!prealloc); | ||||
| 		err = split_state(tree, state, prealloc, start); | ||||
| 		BUG_ON(err == -EEXIST); | ||||
| 		prealloc = NULL; | ||||
| @ -553,8 +562,8 @@ hit_next: | ||||
| 	 * on the first half | ||||
| 	 */ | ||||
| 	if (state->start <= end && state->end > end) { | ||||
| 		if (!prealloc) | ||||
| 			prealloc = alloc_extent_state(GFP_ATOMIC); | ||||
| 		prealloc = alloc_extent_state_atomic(prealloc); | ||||
| 		BUG_ON(!prealloc); | ||||
| 		err = split_state(tree, state, prealloc, end + 1); | ||||
| 		BUG_ON(err == -EEXIST); | ||||
| 		if (wake) | ||||
| @ -727,8 +736,7 @@ int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, | ||||
| again: | ||||
| 	if (!prealloc && (mask & __GFP_WAIT)) { | ||||
| 		prealloc = alloc_extent_state(mask); | ||||
| 		if (!prealloc) | ||||
| 			return -ENOMEM; | ||||
| 		BUG_ON(!prealloc); | ||||
| 	} | ||||
| 
 | ||||
| 	spin_lock(&tree->lock); | ||||
| @ -745,6 +753,8 @@ again: | ||||
| 	 */ | ||||
| 	node = tree_search(tree, start); | ||||
| 	if (!node) { | ||||
| 		prealloc = alloc_extent_state_atomic(prealloc); | ||||
| 		BUG_ON(!prealloc); | ||||
| 		err = insert_state(tree, prealloc, start, end, &bits); | ||||
| 		prealloc = NULL; | ||||
| 		BUG_ON(err == -EEXIST); | ||||
| @ -773,20 +783,18 @@ hit_next: | ||||
| 		if (err) | ||||
| 			goto out; | ||||
| 
 | ||||
| 		next_node = rb_next(node); | ||||
| 		cache_state(state, cached_state); | ||||
| 		merge_state(tree, state); | ||||
| 		if (last_end == (u64)-1) | ||||
| 			goto out; | ||||
| 
 | ||||
| 		start = last_end + 1; | ||||
| 		if (start < end && prealloc && !need_resched()) { | ||||
| 			next_node = rb_next(node); | ||||
| 			if (next_node) { | ||||
| 				state = rb_entry(next_node, struct extent_state, | ||||
| 						 rb_node); | ||||
| 				if (state->start == start) | ||||
| 					goto hit_next; | ||||
| 			} | ||||
| 		if (next_node && start < end && prealloc && !need_resched()) { | ||||
| 			state = rb_entry(next_node, struct extent_state, | ||||
| 					 rb_node); | ||||
| 			if (state->start == start) | ||||
| 				goto hit_next; | ||||
| 		} | ||||
| 		goto search_again; | ||||
| 	} | ||||
| @ -813,6 +821,9 @@ hit_next: | ||||
| 			err = -EEXIST; | ||||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| 		prealloc = alloc_extent_state_atomic(prealloc); | ||||
| 		BUG_ON(!prealloc); | ||||
| 		err = split_state(tree, state, prealloc, start); | ||||
| 		BUG_ON(err == -EEXIST); | ||||
| 		prealloc = NULL; | ||||
| @ -843,14 +854,25 @@ hit_next: | ||||
| 			this_end = end; | ||||
| 		else | ||||
| 			this_end = last_start - 1; | ||||
| 
 | ||||
| 		prealloc = alloc_extent_state_atomic(prealloc); | ||||
| 		BUG_ON(!prealloc); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Avoid to free 'prealloc' if it can be merged with | ||||
| 		 * the later extent. | ||||
| 		 */ | ||||
| 		atomic_inc(&prealloc->refs); | ||||
| 		err = insert_state(tree, prealloc, start, this_end, | ||||
| 				   &bits); | ||||
| 		BUG_ON(err == -EEXIST); | ||||
| 		if (err) { | ||||
| 			free_extent_state(prealloc); | ||||
| 			prealloc = NULL; | ||||
| 			goto out; | ||||
| 		} | ||||
| 		cache_state(prealloc, cached_state); | ||||
| 		free_extent_state(prealloc); | ||||
| 		prealloc = NULL; | ||||
| 		start = this_end + 1; | ||||
| 		goto search_again; | ||||
| @ -867,6 +889,9 @@ hit_next: | ||||
| 			err = -EEXIST; | ||||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| 		prealloc = alloc_extent_state_atomic(prealloc); | ||||
| 		BUG_ON(!prealloc); | ||||
| 		err = split_state(tree, state, prealloc, end + 1); | ||||
| 		BUG_ON(err == -EEXIST); | ||||
| 
 | ||||
| @ -943,13 +968,6 @@ int set_extent_new(struct extent_io_tree *tree, u64 start, u64 end, | ||||
| 			      NULL, mask); | ||||
| } | ||||
| 
 | ||||
| static int clear_extent_new(struct extent_io_tree *tree, u64 start, u64 end, | ||||
| 		       gfp_t mask) | ||||
| { | ||||
| 	return clear_extent_bit(tree, start, end, EXTENT_NEW, 0, 0, | ||||
| 				NULL, mask); | ||||
| } | ||||
| 
 | ||||
| int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end, | ||||
| 			struct extent_state **cached_state, gfp_t mask) | ||||
| { | ||||
| @ -965,11 +983,6 @@ static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start, | ||||
| 				cached_state, mask); | ||||
| } | ||||
| 
 | ||||
| int wait_on_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end) | ||||
| { | ||||
| 	return wait_extent_bit(tree, start, end, EXTENT_WRITEBACK); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * either insert or lock state struct between start and end use mask to tell | ||||
|  * us if waiting is desired. | ||||
| @ -1029,25 +1042,6 @@ int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask) | ||||
| 				mask); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * helper function to set pages and extents in the tree dirty | ||||
|  */ | ||||
| int set_range_dirty(struct extent_io_tree *tree, u64 start, u64 end) | ||||
| { | ||||
| 	unsigned long index = start >> PAGE_CACHE_SHIFT; | ||||
| 	unsigned long end_index = end >> PAGE_CACHE_SHIFT; | ||||
| 	struct page *page; | ||||
| 
 | ||||
| 	while (index <= end_index) { | ||||
| 		page = find_get_page(tree->mapping, index); | ||||
| 		BUG_ON(!page); | ||||
| 		__set_page_dirty_nobuffers(page); | ||||
| 		page_cache_release(page); | ||||
| 		index++; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * helper function to set both pages and extents in the tree writeback | ||||
|  */ | ||||
| @ -1821,46 +1815,6 @@ static void end_bio_extent_readpage(struct bio *bio, int err) | ||||
| 	bio_put(bio); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * IO done from prepare_write is pretty simple, we just unlock | ||||
|  * the structs in the extent tree when done, and set the uptodate bits | ||||
|  * as appropriate. | ||||
|  */ | ||||
| static void end_bio_extent_preparewrite(struct bio *bio, int err) | ||||
| { | ||||
| 	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); | ||||
| 	struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; | ||||
| 	struct extent_io_tree *tree; | ||||
| 	u64 start; | ||||
| 	u64 end; | ||||
| 
 | ||||
| 	do { | ||||
| 		struct page *page = bvec->bv_page; | ||||
| 		struct extent_state *cached = NULL; | ||||
| 		tree = &BTRFS_I(page->mapping->host)->io_tree; | ||||
| 
 | ||||
| 		start = ((u64)page->index << PAGE_CACHE_SHIFT) + | ||||
| 			bvec->bv_offset; | ||||
| 		end = start + bvec->bv_len - 1; | ||||
| 
 | ||||
| 		if (--bvec >= bio->bi_io_vec) | ||||
| 			prefetchw(&bvec->bv_page->flags); | ||||
| 
 | ||||
| 		if (uptodate) { | ||||
| 			set_extent_uptodate(tree, start, end, &cached, | ||||
| 					    GFP_ATOMIC); | ||||
| 		} else { | ||||
| 			ClearPageUptodate(page); | ||||
| 			SetPageError(page); | ||||
| 		} | ||||
| 
 | ||||
| 		unlock_extent_cached(tree, start, end, &cached, GFP_ATOMIC); | ||||
| 
 | ||||
| 	} while (bvec >= bio->bi_io_vec); | ||||
| 
 | ||||
| 	bio_put(bio); | ||||
| } | ||||
| 
 | ||||
| struct bio * | ||||
| btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, | ||||
| 		gfp_t gfp_flags) | ||||
| @ -2009,7 +1963,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree, | ||||
| 	struct btrfs_ordered_extent *ordered; | ||||
| 	int ret; | ||||
| 	int nr = 0; | ||||
| 	size_t page_offset = 0; | ||||
| 	size_t pg_offset = 0; | ||||
| 	size_t iosize; | ||||
| 	size_t disk_io_size; | ||||
| 	size_t blocksize = inode->i_sb->s_blocksize; | ||||
| @ -2052,9 +2006,9 @@ static int __extent_read_full_page(struct extent_io_tree *tree, | ||||
| 			char *userpage; | ||||
| 			struct extent_state *cached = NULL; | ||||
| 
 | ||||
| 			iosize = PAGE_CACHE_SIZE - page_offset; | ||||
| 			iosize = PAGE_CACHE_SIZE - pg_offset; | ||||
| 			userpage = kmap_atomic(page, KM_USER0); | ||||
| 			memset(userpage + page_offset, 0, iosize); | ||||
| 			memset(userpage + pg_offset, 0, iosize); | ||||
| 			flush_dcache_page(page); | ||||
| 			kunmap_atomic(userpage, KM_USER0); | ||||
| 			set_extent_uptodate(tree, cur, cur + iosize - 1, | ||||
| @ -2063,9 +2017,9 @@ static int __extent_read_full_page(struct extent_io_tree *tree, | ||||
| 					     &cached, GFP_NOFS); | ||||
| 			break; | ||||
| 		} | ||||
| 		em = get_extent(inode, page, page_offset, cur, | ||||
| 		em = get_extent(inode, page, pg_offset, cur, | ||||
| 				end - cur + 1, 0); | ||||
| 		if (IS_ERR(em) || !em) { | ||||
| 		if (IS_ERR_OR_NULL(em)) { | ||||
| 			SetPageError(page); | ||||
| 			unlock_extent(tree, cur, end, GFP_NOFS); | ||||
| 			break; | ||||
| @ -2103,7 +2057,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree, | ||||
| 			struct extent_state *cached = NULL; | ||||
| 
 | ||||
| 			userpage = kmap_atomic(page, KM_USER0); | ||||
| 			memset(userpage + page_offset, 0, iosize); | ||||
| 			memset(userpage + pg_offset, 0, iosize); | ||||
| 			flush_dcache_page(page); | ||||
| 			kunmap_atomic(userpage, KM_USER0); | ||||
| 
 | ||||
| @ -2112,7 +2066,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree, | ||||
| 			unlock_extent_cached(tree, cur, cur + iosize - 1, | ||||
| 			                     &cached, GFP_NOFS); | ||||
| 			cur = cur + iosize; | ||||
| 			page_offset += iosize; | ||||
| 			pg_offset += iosize; | ||||
| 			continue; | ||||
| 		} | ||||
| 		/* the get_extent function already copied into the page */ | ||||
| @ -2121,7 +2075,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree, | ||||
| 			check_page_uptodate(tree, page); | ||||
| 			unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS); | ||||
| 			cur = cur + iosize; | ||||
| 			page_offset += iosize; | ||||
| 			pg_offset += iosize; | ||||
| 			continue; | ||||
| 		} | ||||
| 		/* we have an inline extent but it didn't get marked up
 | ||||
| @ -2131,7 +2085,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree, | ||||
| 			SetPageError(page); | ||||
| 			unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS); | ||||
| 			cur = cur + iosize; | ||||
| 			page_offset += iosize; | ||||
| 			pg_offset += iosize; | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| @ -2144,7 +2098,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree, | ||||
| 			unsigned long pnr = (last_byte >> PAGE_CACHE_SHIFT) + 1; | ||||
| 			pnr -= page->index; | ||||
| 			ret = submit_extent_page(READ, tree, page, | ||||
| 					 sector, disk_io_size, page_offset, | ||||
| 					 sector, disk_io_size, pg_offset, | ||||
| 					 bdev, bio, pnr, | ||||
| 					 end_bio_extent_readpage, mirror_num, | ||||
| 					 *bio_flags, | ||||
| @ -2155,7 +2109,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree, | ||||
| 		if (ret) | ||||
| 			SetPageError(page); | ||||
| 		cur = cur + iosize; | ||||
| 		page_offset += iosize; | ||||
| 		pg_offset += iosize; | ||||
| 	} | ||||
| out: | ||||
| 	if (!nr) { | ||||
| @ -2351,7 +2305,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | ||||
| 		} | ||||
| 		em = epd->get_extent(inode, page, pg_offset, cur, | ||||
| 				     end - cur + 1, 1); | ||||
| 		if (IS_ERR(em) || !em) { | ||||
| 		if (IS_ERR_OR_NULL(em)) { | ||||
| 			SetPageError(page); | ||||
| 			break; | ||||
| 		} | ||||
| @ -2729,128 +2683,6 @@ int extent_invalidatepage(struct extent_io_tree *tree, | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * simple commit_write call, set_range_dirty is used to mark both | ||||
|  * the pages and the extent records as dirty | ||||
|  */ | ||||
| int extent_commit_write(struct extent_io_tree *tree, | ||||
| 			struct inode *inode, struct page *page, | ||||
| 			unsigned from, unsigned to) | ||||
| { | ||||
| 	loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | ||||
| 
 | ||||
| 	set_page_extent_mapped(page); | ||||
| 	set_page_dirty(page); | ||||
| 
 | ||||
| 	if (pos > inode->i_size) { | ||||
| 		i_size_write(inode, pos); | ||||
| 		mark_inode_dirty(inode); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int extent_prepare_write(struct extent_io_tree *tree, | ||||
| 			 struct inode *inode, struct page *page, | ||||
| 			 unsigned from, unsigned to, get_extent_t *get_extent) | ||||
| { | ||||
| 	u64 page_start = (u64)page->index << PAGE_CACHE_SHIFT; | ||||
| 	u64 page_end = page_start + PAGE_CACHE_SIZE - 1; | ||||
| 	u64 block_start; | ||||
| 	u64 orig_block_start; | ||||
| 	u64 block_end; | ||||
| 	u64 cur_end; | ||||
| 	struct extent_map *em; | ||||
| 	unsigned blocksize = 1 << inode->i_blkbits; | ||||
| 	size_t page_offset = 0; | ||||
| 	size_t block_off_start; | ||||
| 	size_t block_off_end; | ||||
| 	int err = 0; | ||||
| 	int iocount = 0; | ||||
| 	int ret = 0; | ||||
| 	int isnew; | ||||
| 
 | ||||
| 	set_page_extent_mapped(page); | ||||
| 
 | ||||
| 	block_start = (page_start + from) & ~((u64)blocksize - 1); | ||||
| 	block_end = (page_start + to - 1) | (blocksize - 1); | ||||
| 	orig_block_start = block_start; | ||||
| 
 | ||||
| 	lock_extent(tree, page_start, page_end, GFP_NOFS); | ||||
| 	while (block_start <= block_end) { | ||||
| 		em = get_extent(inode, page, page_offset, block_start, | ||||
| 				block_end - block_start + 1, 1); | ||||
| 		if (IS_ERR(em) || !em) | ||||
| 			goto err; | ||||
| 
 | ||||
| 		cur_end = min(block_end, extent_map_end(em) - 1); | ||||
| 		block_off_start = block_start & (PAGE_CACHE_SIZE - 1); | ||||
| 		block_off_end = block_off_start + blocksize; | ||||
| 		isnew = clear_extent_new(tree, block_start, cur_end, GFP_NOFS); | ||||
| 
 | ||||
| 		if (!PageUptodate(page) && isnew && | ||||
| 		    (block_off_end > to || block_off_start < from)) { | ||||
| 			void *kaddr; | ||||
| 
 | ||||
| 			kaddr = kmap_atomic(page, KM_USER0); | ||||
| 			if (block_off_end > to) | ||||
| 				memset(kaddr + to, 0, block_off_end - to); | ||||
| 			if (block_off_start < from) | ||||
| 				memset(kaddr + block_off_start, 0, | ||||
| 				       from - block_off_start); | ||||
| 			flush_dcache_page(page); | ||||
| 			kunmap_atomic(kaddr, KM_USER0); | ||||
| 		} | ||||
| 		if ((em->block_start != EXTENT_MAP_HOLE && | ||||
| 		     em->block_start != EXTENT_MAP_INLINE) && | ||||
| 		    !isnew && !PageUptodate(page) && | ||||
| 		    (block_off_end > to || block_off_start < from) && | ||||
| 		    !test_range_bit(tree, block_start, cur_end, | ||||
| 				    EXTENT_UPTODATE, 1, NULL)) { | ||||
| 			u64 sector; | ||||
| 			u64 extent_offset = block_start - em->start; | ||||
| 			size_t iosize; | ||||
| 			sector = (em->block_start + extent_offset) >> 9; | ||||
| 			iosize = (cur_end - block_start + blocksize) & | ||||
| 				~((u64)blocksize - 1); | ||||
| 			/*
 | ||||
| 			 * we've already got the extent locked, but we | ||||
| 			 * need to split the state such that our end_bio | ||||
| 			 * handler can clear the lock. | ||||
| 			 */ | ||||
| 			set_extent_bit(tree, block_start, | ||||
| 				       block_start + iosize - 1, | ||||
| 				       EXTENT_LOCKED, 0, NULL, NULL, GFP_NOFS); | ||||
| 			ret = submit_extent_page(READ, tree, page, | ||||
| 					 sector, iosize, page_offset, em->bdev, | ||||
| 					 NULL, 1, | ||||
| 					 end_bio_extent_preparewrite, 0, | ||||
| 					 0, 0); | ||||
| 			if (ret && !err) | ||||
| 				err = ret; | ||||
| 			iocount++; | ||||
| 			block_start = block_start + iosize; | ||||
| 		} else { | ||||
| 			struct extent_state *cached = NULL; | ||||
| 
 | ||||
| 			set_extent_uptodate(tree, block_start, cur_end, &cached, | ||||
| 					    GFP_NOFS); | ||||
| 			unlock_extent_cached(tree, block_start, cur_end, | ||||
| 					     &cached, GFP_NOFS); | ||||
| 			block_start = cur_end + 1; | ||||
| 		} | ||||
| 		page_offset = block_start & (PAGE_CACHE_SIZE - 1); | ||||
| 		free_extent_map(em); | ||||
| 	} | ||||
| 	if (iocount) { | ||||
| 		wait_extent_bit(tree, orig_block_start, | ||||
| 				block_end, EXTENT_LOCKED); | ||||
| 	} | ||||
| 	check_page_uptodate(tree, page); | ||||
| err: | ||||
| 	/* FIXME, zero out newly allocated blocks on error */ | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * a helper for releasepage, this tests for areas of the page that | ||||
|  * are locked or under IO and drops the related state bits if it is safe | ||||
| @ -2909,7 +2741,7 @@ int try_release_extent_mapping(struct extent_map_tree *map, | ||||
| 			len = end - start + 1; | ||||
| 			write_lock(&map->lock); | ||||
| 			em = lookup_extent_mapping(map, start, len); | ||||
| 			if (!em || IS_ERR(em)) { | ||||
| 			if (IS_ERR_OR_NULL(em)) { | ||||
| 				write_unlock(&map->lock); | ||||
| 				break; | ||||
| 			} | ||||
| @ -2937,33 +2769,6 @@ int try_release_extent_mapping(struct extent_map_tree *map, | ||||
| 	return try_release_extent_state(map, tree, page, mask); | ||||
| } | ||||
| 
 | ||||
| sector_t extent_bmap(struct address_space *mapping, sector_t iblock, | ||||
| 		get_extent_t *get_extent) | ||||
| { | ||||
| 	struct inode *inode = mapping->host; | ||||
| 	struct extent_state *cached_state = NULL; | ||||
| 	u64 start = iblock << inode->i_blkbits; | ||||
| 	sector_t sector = 0; | ||||
| 	size_t blksize = (1 << inode->i_blkbits); | ||||
| 	struct extent_map *em; | ||||
| 
 | ||||
| 	lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + blksize - 1, | ||||
| 			 0, &cached_state, GFP_NOFS); | ||||
| 	em = get_extent(inode, NULL, 0, start, blksize, 0); | ||||
| 	unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, | ||||
| 			     start + blksize - 1, &cached_state, GFP_NOFS); | ||||
| 	if (!em || IS_ERR(em)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (em->block_start > EXTENT_MAP_LAST_BYTE) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	sector = (em->block_start + start - em->start) >> inode->i_blkbits; | ||||
| out: | ||||
| 	free_extent_map(em); | ||||
| 	return sector; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * helper function for fiemap, which doesn't want to see any holes. | ||||
|  * This maps until we find something past 'last' | ||||
| @ -2986,7 +2791,7 @@ static struct extent_map *get_extent_skip_holes(struct inode *inode, | ||||
| 			break; | ||||
| 		len = (len + sectorsize - 1) & ~(sectorsize - 1); | ||||
| 		em = get_extent(inode, NULL, 0, offset, len, 0); | ||||
| 		if (!em || IS_ERR(em)) | ||||
| 		if (IS_ERR_OR_NULL(em)) | ||||
| 			return em; | ||||
| 
 | ||||
| 		/* if this isn't a hole return it */ | ||||
| @ -3040,7 +2845,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||||
| 	 * because there might be preallocation past i_size | ||||
| 	 */ | ||||
| 	ret = btrfs_lookup_file_extent(NULL, BTRFS_I(inode)->root, | ||||
| 				       path, inode->i_ino, -1, 0); | ||||
| 				       path, btrfs_ino(inode), -1, 0); | ||||
| 	if (ret < 0) { | ||||
| 		btrfs_free_path(path); | ||||
| 		return ret; | ||||
| @ -3053,7 +2858,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||||
| 	found_type = btrfs_key_type(&found_key); | ||||
| 
 | ||||
| 	/* No extents, but there might be delalloc bits */ | ||||
| 	if (found_key.objectid != inode->i_ino || | ||||
| 	if (found_key.objectid != btrfs_ino(inode) || | ||||
| 	    found_type != BTRFS_EXTENT_DATA_KEY) { | ||||
| 		/* have to trust i_size as the end */ | ||||
| 		last = (u64)-1; | ||||
| @ -3276,8 +3081,7 @@ static inline void btrfs_release_extent_buffer(struct extent_buffer *eb) | ||||
| 
 | ||||
| struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | ||||
| 					  u64 start, unsigned long len, | ||||
| 					  struct page *page0, | ||||
| 					  gfp_t mask) | ||||
| 					  struct page *page0) | ||||
| { | ||||
| 	unsigned long num_pages = num_extent_pages(start, len); | ||||
| 	unsigned long i; | ||||
| @ -3298,7 +3102,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | ||||
| 	} | ||||
| 	rcu_read_unlock(); | ||||
| 
 | ||||
| 	eb = __alloc_extent_buffer(tree, start, len, mask); | ||||
| 	eb = __alloc_extent_buffer(tree, start, len, GFP_NOFS); | ||||
| 	if (!eb) | ||||
| 		return NULL; | ||||
| 
 | ||||
| @ -3315,7 +3119,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | ||||
| 		i = 0; | ||||
| 	} | ||||
| 	for (; i < num_pages; i++, index++) { | ||||
| 		p = find_or_create_page(mapping, index, mask | __GFP_HIGHMEM); | ||||
| 		p = find_or_create_page(mapping, index, GFP_NOFS | __GFP_HIGHMEM); | ||||
| 		if (!p) { | ||||
| 			WARN_ON(1); | ||||
| 			goto free_eb; | ||||
| @ -3387,8 +3191,7 @@ free_eb: | ||||
| } | ||||
| 
 | ||||
| struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree, | ||||
| 					 u64 start, unsigned long len, | ||||
| 					  gfp_t mask) | ||||
| 					 u64 start, unsigned long len) | ||||
| { | ||||
| 	struct extent_buffer *eb; | ||||
| 
 | ||||
| @ -3449,13 +3252,6 @@ int clear_extent_buffer_dirty(struct extent_io_tree *tree, | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int wait_on_extent_buffer_writeback(struct extent_io_tree *tree, | ||||
| 				    struct extent_buffer *eb) | ||||
| { | ||||
| 	return wait_on_extent_writeback(tree, eb->start, | ||||
| 					eb->start + eb->len - 1); | ||||
| } | ||||
| 
 | ||||
| int set_extent_buffer_dirty(struct extent_io_tree *tree, | ||||
| 			     struct extent_buffer *eb) | ||||
| { | ||||
|  | ||||
| @ -153,23 +153,14 @@ static inline int extent_compress_type(unsigned long bio_flags) | ||||
| 
 | ||||
| struct extent_map_tree; | ||||
| 
 | ||||
| static inline struct extent_state *extent_state_next(struct extent_state *state) | ||||
| { | ||||
| 	struct rb_node *node; | ||||
| 	node = rb_next(&state->rb_node); | ||||
| 	if (!node) | ||||
| 		return NULL; | ||||
| 	return rb_entry(node, struct extent_state, rb_node); | ||||
| } | ||||
| 
 | ||||
| typedef struct extent_map *(get_extent_t)(struct inode *inode, | ||||
| 					  struct page *page, | ||||
| 					  size_t page_offset, | ||||
| 					  size_t pg_offset, | ||||
| 					  u64 start, u64 len, | ||||
| 					  int create); | ||||
| 
 | ||||
| void extent_io_tree_init(struct extent_io_tree *tree, | ||||
| 			  struct address_space *mapping, gfp_t mask); | ||||
| 			 struct address_space *mapping); | ||||
| int try_release_extent_mapping(struct extent_map_tree *map, | ||||
| 			       struct extent_io_tree *tree, struct page *page, | ||||
| 			       gfp_t mask); | ||||
| @ -215,14 +206,8 @@ int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, | ||||
| 		     gfp_t mask); | ||||
| int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, | ||||
| 		       gfp_t mask); | ||||
| int clear_extent_ordered(struct extent_io_tree *tree, u64 start, u64 end, | ||||
| 		       gfp_t mask); | ||||
| int clear_extent_ordered_metadata(struct extent_io_tree *tree, u64 start, | ||||
| 				  u64 end, gfp_t mask); | ||||
| int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end, | ||||
| 			struct extent_state **cached_state, gfp_t mask); | ||||
| int set_extent_ordered(struct extent_io_tree *tree, u64 start, u64 end, | ||||
| 		     gfp_t mask); | ||||
| int find_first_extent_bit(struct extent_io_tree *tree, u64 start, | ||||
| 			  u64 *start_ret, u64 *end_ret, int bits); | ||||
| struct extent_state *find_first_extent_bit_state(struct extent_io_tree *tree, | ||||
| @ -243,28 +228,17 @@ int extent_readpages(struct extent_io_tree *tree, | ||||
| 		     struct address_space *mapping, | ||||
| 		     struct list_head *pages, unsigned nr_pages, | ||||
| 		     get_extent_t get_extent); | ||||
| int extent_prepare_write(struct extent_io_tree *tree, | ||||
| 			 struct inode *inode, struct page *page, | ||||
| 			 unsigned from, unsigned to, get_extent_t *get_extent); | ||||
| int extent_commit_write(struct extent_io_tree *tree, | ||||
| 			struct inode *inode, struct page *page, | ||||
| 			unsigned from, unsigned to); | ||||
| sector_t extent_bmap(struct address_space *mapping, sector_t iblock, | ||||
| 		get_extent_t *get_extent); | ||||
| int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||||
| 		__u64 start, __u64 len, get_extent_t *get_extent); | ||||
| int set_range_dirty(struct extent_io_tree *tree, u64 start, u64 end); | ||||
| int set_state_private(struct extent_io_tree *tree, u64 start, u64 private); | ||||
| int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private); | ||||
| void set_page_extent_mapped(struct page *page); | ||||
| 
 | ||||
| struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | ||||
| 					  u64 start, unsigned long len, | ||||
| 					  struct page *page0, | ||||
| 					  gfp_t mask); | ||||
| 					  struct page *page0); | ||||
| struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree, | ||||
| 					 u64 start, unsigned long len, | ||||
| 					  gfp_t mask); | ||||
| 					 u64 start, unsigned long len); | ||||
| void free_extent_buffer(struct extent_buffer *eb); | ||||
| int read_extent_buffer_pages(struct extent_io_tree *tree, | ||||
| 			     struct extent_buffer *eb, u64 start, int wait, | ||||
| @ -292,16 +266,11 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset, | ||||
| 			   unsigned long src_offset, unsigned long len); | ||||
| void memset_extent_buffer(struct extent_buffer *eb, char c, | ||||
| 			  unsigned long start, unsigned long len); | ||||
| int wait_on_extent_buffer_writeback(struct extent_io_tree *tree, | ||||
| 				    struct extent_buffer *eb); | ||||
| int wait_on_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end); | ||||
| int wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits); | ||||
| int clear_extent_buffer_dirty(struct extent_io_tree *tree, | ||||
| 			      struct extent_buffer *eb); | ||||
| int set_extent_buffer_dirty(struct extent_io_tree *tree, | ||||
| 			     struct extent_buffer *eb); | ||||
| int test_extent_buffer_dirty(struct extent_io_tree *tree, | ||||
| 			     struct extent_buffer *eb); | ||||
| int set_extent_buffer_uptodate(struct extent_io_tree *tree, | ||||
| 			       struct extent_buffer *eb); | ||||
| int clear_extent_buffer_uptodate(struct extent_io_tree *tree, | ||||
| @ -319,7 +288,6 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset, | ||||
| 		      unsigned long *map_start, | ||||
| 		      unsigned long *map_len, int km); | ||||
| void unmap_extent_buffer(struct extent_buffer *eb, char *token, int km); | ||||
| int release_extent_buffer_tail_pages(struct extent_buffer *eb); | ||||
| int extent_range_uptodate(struct extent_io_tree *tree, | ||||
| 			  u64 start, u64 end); | ||||
| int extent_clear_unlock_delalloc(struct inode *inode, | ||||
|  | ||||
| @ -28,12 +28,11 @@ void extent_map_exit(void) | ||||
| /**
 | ||||
|  * extent_map_tree_init - initialize extent map tree | ||||
|  * @tree:		tree to initialize | ||||
|  * @mask:		flags for memory allocations during tree operations | ||||
|  * | ||||
|  * Initialize the extent tree @tree.  Should be called for each new inode | ||||
|  * or other user of the extent_map interface. | ||||
|  */ | ||||
| void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask) | ||||
| void extent_map_tree_init(struct extent_map_tree *tree) | ||||
| { | ||||
| 	tree->map = RB_ROOT; | ||||
| 	rwlock_init(&tree->lock); | ||||
| @ -41,16 +40,15 @@ void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask) | ||||
| 
 | ||||
| /**
 | ||||
|  * alloc_extent_map - allocate new extent map structure | ||||
|  * @mask:	memory allocation flags | ||||
|  * | ||||
|  * Allocate a new extent_map structure.  The new structure is | ||||
|  * returned with a reference count of one and needs to be | ||||
|  * freed using free_extent_map() | ||||
|  */ | ||||
| struct extent_map *alloc_extent_map(gfp_t mask) | ||||
| struct extent_map *alloc_extent_map(void) | ||||
| { | ||||
| 	struct extent_map *em; | ||||
| 	em = kmem_cache_alloc(extent_map_cache, mask); | ||||
| 	em = kmem_cache_alloc(extent_map_cache, GFP_NOFS); | ||||
| 	if (!em) | ||||
| 		return NULL; | ||||
| 	em->in_tree = 0; | ||||
|  | ||||
| @ -49,14 +49,14 @@ static inline u64 extent_map_block_end(struct extent_map *em) | ||||
| 	return em->block_start + em->block_len; | ||||
| } | ||||
| 
 | ||||
| void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask); | ||||
| void extent_map_tree_init(struct extent_map_tree *tree); | ||||
| struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, | ||||
| 					 u64 start, u64 len); | ||||
| int add_extent_mapping(struct extent_map_tree *tree, | ||||
| 		       struct extent_map *em); | ||||
| int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em); | ||||
| 
 | ||||
| struct extent_map *alloc_extent_map(gfp_t mask); | ||||
| struct extent_map *alloc_extent_map(void); | ||||
| void free_extent_map(struct extent_map *em); | ||||
| int __init extent_map_init(void); | ||||
| void extent_map_exit(void); | ||||
|  | ||||
| @ -193,7 +193,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | ||||
| 			u32 item_size; | ||||
| 
 | ||||
| 			if (item) | ||||
| 				btrfs_release_path(root, path); | ||||
| 				btrfs_release_path(path); | ||||
| 			item = btrfs_lookup_csum(NULL, root->fs_info->csum_root, | ||||
| 						 path, disk_bytenr, 0); | ||||
| 			if (IS_ERR(item)) { | ||||
| @ -208,12 +208,13 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | ||||
| 						EXTENT_NODATASUM, GFP_NOFS); | ||||
| 				} else { | ||||
| 					printk(KERN_INFO "btrfs no csum found " | ||||
| 					       "for inode %lu start %llu\n", | ||||
| 					       inode->i_ino, | ||||
| 					       "for inode %llu start %llu\n", | ||||
| 					       (unsigned long long) | ||||
| 					       btrfs_ino(inode), | ||||
| 					       (unsigned long long)offset); | ||||
| 				} | ||||
| 				item = NULL; | ||||
| 				btrfs_release_path(root, path); | ||||
| 				btrfs_release_path(path); | ||||
| 				goto found; | ||||
| 			} | ||||
| 			btrfs_item_key_to_cpu(path->nodes[0], &found_key, | ||||
| @ -266,7 +267,7 @@ int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, | ||||
| } | ||||
| 
 | ||||
| int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, | ||||
| 			     struct list_head *list) | ||||
| 			     struct list_head *list, int search_commit) | ||||
| { | ||||
| 	struct btrfs_key key; | ||||
| 	struct btrfs_path *path; | ||||
| @ -283,6 +284,12 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, | ||||
| 	path = btrfs_alloc_path(); | ||||
| 	BUG_ON(!path); | ||||
| 
 | ||||
| 	if (search_commit) { | ||||
| 		path->skip_locking = 1; | ||||
| 		path->reada = 2; | ||||
| 		path->search_commit_root = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; | ||||
| 	key.offset = start; | ||||
| 	key.type = BTRFS_EXTENT_CSUM_KEY; | ||||
| @ -495,7 +502,6 @@ static noinline int truncate_one_csum(struct btrfs_trans_handle *trans, | ||||
| 		u32 new_size = (bytenr - key->offset) >> blocksize_bits; | ||||
| 		new_size *= csum_size; | ||||
| 		ret = btrfs_truncate_item(trans, root, path, new_size, 1); | ||||
| 		BUG_ON(ret); | ||||
| 	} else if (key->offset >= bytenr && csum_end > end_byte && | ||||
| 		   end_byte > key->offset) { | ||||
| 		/*
 | ||||
| @ -508,7 +514,6 @@ static noinline int truncate_one_csum(struct btrfs_trans_handle *trans, | ||||
| 		new_size *= csum_size; | ||||
| 
 | ||||
| 		ret = btrfs_truncate_item(trans, root, path, new_size, 0); | ||||
| 		BUG_ON(ret); | ||||
| 
 | ||||
| 		key->offset = end_byte; | ||||
| 		ret = btrfs_set_item_key_safe(trans, root, path, key); | ||||
| @ -551,10 +556,10 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, | ||||
| 		ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | ||||
| 		if (ret > 0) { | ||||
| 			if (path->slots[0] == 0) | ||||
| 				goto out; | ||||
| 				break; | ||||
| 			path->slots[0]--; | ||||
| 		} else if (ret < 0) { | ||||
| 			goto out; | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		leaf = path->nodes[0]; | ||||
| @ -579,7 +584,8 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, | ||||
| 		/* delete the entire item, it is inside our range */ | ||||
| 		if (key.offset >= bytenr && csum_end <= end_byte) { | ||||
| 			ret = btrfs_del_item(trans, root, path); | ||||
| 			BUG_ON(ret); | ||||
| 			if (ret) | ||||
| 				goto out; | ||||
| 			if (key.offset == bytenr) | ||||
| 				break; | ||||
| 		} else if (key.offset < bytenr && csum_end > end_byte) { | ||||
| @ -631,11 +637,12 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, | ||||
| 			if (key.offset < bytenr) | ||||
| 				break; | ||||
| 		} | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 	} | ||||
| 	ret = 0; | ||||
| out: | ||||
| 	btrfs_free_path(path); | ||||
| 	return 0; | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, | ||||
| @ -722,7 +729,7 @@ again: | ||||
| 	 * at this point, we know the tree has an item, but it isn't big | ||||
| 	 * enough yet to put our csum in.  Grow it | ||||
| 	 */ | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	ret = btrfs_search_slot(trans, root, &file_key, path, | ||||
| 				csum_size, 1); | ||||
| 	if (ret < 0) | ||||
| @ -761,12 +768,11 @@ again: | ||||
| 			goto insert; | ||||
| 
 | ||||
| 		ret = btrfs_extend_item(trans, root, path, diff); | ||||
| 		BUG_ON(ret); | ||||
| 		goto csum; | ||||
| 	} | ||||
| 
 | ||||
| insert: | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	csum_offset = 0; | ||||
| 	if (found_next) { | ||||
| 		u64 tmp = total_bytes + root->sectorsize; | ||||
| @ -850,7 +856,7 @@ next_sector: | ||||
| 	} | ||||
| 	btrfs_mark_buffer_dirty(path->nodes[0]); | ||||
| 	if (total_bytes < sums->len) { | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 		cond_resched(); | ||||
| 		goto again; | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										302
									
								
								fs/btrfs/file.c
									
									
									
									
									
								
							
							
						
						
									
										302
									
								
								fs/btrfs/file.c
									
									
									
									
									
								
							| @ -40,6 +40,263 @@ | ||||
| #include "locking.h" | ||||
| #include "compat.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * when auto defrag is enabled we | ||||
|  * queue up these defrag structs to remember which | ||||
|  * inodes need defragging passes | ||||
|  */ | ||||
| struct inode_defrag { | ||||
| 	struct rb_node rb_node; | ||||
| 	/* objectid */ | ||||
| 	u64 ino; | ||||
| 	/*
 | ||||
| 	 * transid where the defrag was added, we search for | ||||
| 	 * extents newer than this | ||||
| 	 */ | ||||
| 	u64 transid; | ||||
| 
 | ||||
| 	/* root objectid */ | ||||
| 	u64 root; | ||||
| 
 | ||||
| 	/* last offset we were able to defrag */ | ||||
| 	u64 last_offset; | ||||
| 
 | ||||
| 	/* if we've wrapped around back to zero once already */ | ||||
| 	int cycled; | ||||
| }; | ||||
| 
 | ||||
| /* pop a record for an inode into the defrag tree.  The lock
 | ||||
|  * must be held already | ||||
|  * | ||||
|  * If you're inserting a record for an older transid than an | ||||
|  * existing record, the transid already in the tree is lowered | ||||
|  * | ||||
|  * If an existing record is found the defrag item you | ||||
|  * pass in is freed | ||||
|  */ | ||||
| static int __btrfs_add_inode_defrag(struct inode *inode, | ||||
| 				    struct inode_defrag *defrag) | ||||
| { | ||||
| 	struct btrfs_root *root = BTRFS_I(inode)->root; | ||||
| 	struct inode_defrag *entry; | ||||
| 	struct rb_node **p; | ||||
| 	struct rb_node *parent = NULL; | ||||
| 
 | ||||
| 	p = &root->fs_info->defrag_inodes.rb_node; | ||||
| 	while (*p) { | ||||
| 		parent = *p; | ||||
| 		entry = rb_entry(parent, struct inode_defrag, rb_node); | ||||
| 
 | ||||
| 		if (defrag->ino < entry->ino) | ||||
| 			p = &parent->rb_left; | ||||
| 		else if (defrag->ino > entry->ino) | ||||
| 			p = &parent->rb_right; | ||||
| 		else { | ||||
| 			/* if we're reinserting an entry for
 | ||||
| 			 * an old defrag run, make sure to | ||||
| 			 * lower the transid of our existing record | ||||
| 			 */ | ||||
| 			if (defrag->transid < entry->transid) | ||||
| 				entry->transid = defrag->transid; | ||||
| 			if (defrag->last_offset > entry->last_offset) | ||||
| 				entry->last_offset = defrag->last_offset; | ||||
| 			goto exists; | ||||
| 		} | ||||
| 	} | ||||
| 	BTRFS_I(inode)->in_defrag = 1; | ||||
| 	rb_link_node(&defrag->rb_node, parent, p); | ||||
| 	rb_insert_color(&defrag->rb_node, &root->fs_info->defrag_inodes); | ||||
| 	return 0; | ||||
| 
 | ||||
| exists: | ||||
| 	kfree(defrag); | ||||
| 	return 0; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * insert a defrag record for this inode if auto defrag is | ||||
|  * enabled | ||||
|  */ | ||||
| int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, | ||||
| 			   struct inode *inode) | ||||
| { | ||||
| 	struct btrfs_root *root = BTRFS_I(inode)->root; | ||||
| 	struct inode_defrag *defrag; | ||||
| 	int ret = 0; | ||||
| 	u64 transid; | ||||
| 
 | ||||
| 	if (!btrfs_test_opt(root, AUTO_DEFRAG)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (root->fs_info->closing) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (BTRFS_I(inode)->in_defrag) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (trans) | ||||
| 		transid = trans->transid; | ||||
| 	else | ||||
| 		transid = BTRFS_I(inode)->root->last_trans; | ||||
| 
 | ||||
| 	defrag = kzalloc(sizeof(*defrag), GFP_NOFS); | ||||
| 	if (!defrag) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	defrag->ino = inode->i_ino; | ||||
| 	defrag->transid = transid; | ||||
| 	defrag->root = root->root_key.objectid; | ||||
| 
 | ||||
| 	spin_lock(&root->fs_info->defrag_inodes_lock); | ||||
| 	if (!BTRFS_I(inode)->in_defrag) | ||||
| 		ret = __btrfs_add_inode_defrag(inode, defrag); | ||||
| 	spin_unlock(&root->fs_info->defrag_inodes_lock); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * must be called with the defrag_inodes lock held | ||||
|  */ | ||||
| struct inode_defrag *btrfs_find_defrag_inode(struct btrfs_fs_info *info, u64 ino, | ||||
| 					     struct rb_node **next) | ||||
| { | ||||
| 	struct inode_defrag *entry = NULL; | ||||
| 	struct rb_node *p; | ||||
| 	struct rb_node *parent = NULL; | ||||
| 
 | ||||
| 	p = info->defrag_inodes.rb_node; | ||||
| 	while (p) { | ||||
| 		parent = p; | ||||
| 		entry = rb_entry(parent, struct inode_defrag, rb_node); | ||||
| 
 | ||||
| 		if (ino < entry->ino) | ||||
| 			p = parent->rb_left; | ||||
| 		else if (ino > entry->ino) | ||||
| 			p = parent->rb_right; | ||||
| 		else | ||||
| 			return entry; | ||||
| 	} | ||||
| 
 | ||||
| 	if (next) { | ||||
| 		while (parent && ino > entry->ino) { | ||||
| 			parent = rb_next(parent); | ||||
| 			entry = rb_entry(parent, struct inode_defrag, rb_node); | ||||
| 		} | ||||
| 		*next = parent; | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * run through the list of inodes in the FS that need | ||||
|  * defragging | ||||
|  */ | ||||
| int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info) | ||||
| { | ||||
| 	struct inode_defrag *defrag; | ||||
| 	struct btrfs_root *inode_root; | ||||
| 	struct inode *inode; | ||||
| 	struct rb_node *n; | ||||
| 	struct btrfs_key key; | ||||
| 	struct btrfs_ioctl_defrag_range_args range; | ||||
| 	u64 first_ino = 0; | ||||
| 	int num_defrag; | ||||
| 	int defrag_batch = 1024; | ||||
| 
 | ||||
| 	memset(&range, 0, sizeof(range)); | ||||
| 	range.len = (u64)-1; | ||||
| 
 | ||||
| 	atomic_inc(&fs_info->defrag_running); | ||||
| 	spin_lock(&fs_info->defrag_inodes_lock); | ||||
| 	while(1) { | ||||
| 		n = NULL; | ||||
| 
 | ||||
| 		/* find an inode to defrag */ | ||||
| 		defrag = btrfs_find_defrag_inode(fs_info, first_ino, &n); | ||||
| 		if (!defrag) { | ||||
| 			if (n) | ||||
| 				defrag = rb_entry(n, struct inode_defrag, rb_node); | ||||
| 			else if (first_ino) { | ||||
| 				first_ino = 0; | ||||
| 				continue; | ||||
| 			} else { | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		/* remove it from the rbtree */ | ||||
| 		first_ino = defrag->ino + 1; | ||||
| 		rb_erase(&defrag->rb_node, &fs_info->defrag_inodes); | ||||
| 
 | ||||
| 		if (fs_info->closing) | ||||
| 			goto next_free; | ||||
| 
 | ||||
| 		spin_unlock(&fs_info->defrag_inodes_lock); | ||||
| 
 | ||||
| 		/* get the inode */ | ||||
| 		key.objectid = defrag->root; | ||||
| 		btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | ||||
| 		key.offset = (u64)-1; | ||||
| 		inode_root = btrfs_read_fs_root_no_name(fs_info, &key); | ||||
| 		if (IS_ERR(inode_root)) | ||||
| 			goto next; | ||||
| 
 | ||||
| 		key.objectid = defrag->ino; | ||||
| 		btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); | ||||
| 		key.offset = 0; | ||||
| 
 | ||||
| 		inode = btrfs_iget(fs_info->sb, &key, inode_root, NULL); | ||||
| 		if (IS_ERR(inode)) | ||||
| 			goto next; | ||||
| 
 | ||||
| 		/* do a chunk of defrag */ | ||||
| 		BTRFS_I(inode)->in_defrag = 0; | ||||
| 		range.start = defrag->last_offset; | ||||
| 		num_defrag = btrfs_defrag_file(inode, NULL, &range, defrag->transid, | ||||
| 					       defrag_batch); | ||||
| 		/*
 | ||||
| 		 * if we filled the whole defrag batch, there | ||||
| 		 * must be more work to do.  Queue this defrag | ||||
| 		 * again | ||||
| 		 */ | ||||
| 		if (num_defrag == defrag_batch) { | ||||
| 			defrag->last_offset = range.start; | ||||
| 			__btrfs_add_inode_defrag(inode, defrag); | ||||
| 			/*
 | ||||
| 			 * we don't want to kfree defrag, we added it back to | ||||
| 			 * the rbtree | ||||
| 			 */ | ||||
| 			defrag = NULL; | ||||
| 		} else if (defrag->last_offset && !defrag->cycled) { | ||||
| 			/*
 | ||||
| 			 * we didn't fill our defrag batch, but | ||||
| 			 * we didn't start at zero.  Make sure we loop | ||||
| 			 * around to the start of the file. | ||||
| 			 */ | ||||
| 			defrag->last_offset = 0; | ||||
| 			defrag->cycled = 1; | ||||
| 			__btrfs_add_inode_defrag(inode, defrag); | ||||
| 			defrag = NULL; | ||||
| 		} | ||||
| 
 | ||||
| 		iput(inode); | ||||
| next: | ||||
| 		spin_lock(&fs_info->defrag_inodes_lock); | ||||
| next_free: | ||||
| 		kfree(defrag); | ||||
| 	} | ||||
| 	spin_unlock(&fs_info->defrag_inodes_lock); | ||||
| 
 | ||||
| 	atomic_dec(&fs_info->defrag_running); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * during unmount, we use the transaction_wait queue to | ||||
| 	 * wait for the defragger to stop | ||||
| 	 */ | ||||
| 	wake_up(&fs_info->transaction_wait); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* simple helper to fault in pages and copy.  This should go away
 | ||||
|  * and be replaced with calls into generic code. | ||||
| @ -191,9 +448,9 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, | ||||
| 	} | ||||
| 	while (1) { | ||||
| 		if (!split) | ||||
| 			split = alloc_extent_map(GFP_NOFS); | ||||
| 			split = alloc_extent_map(); | ||||
| 		if (!split2) | ||||
| 			split2 = alloc_extent_map(GFP_NOFS); | ||||
| 			split2 = alloc_extent_map(); | ||||
| 		BUG_ON(!split || !split2); | ||||
| 
 | ||||
| 		write_lock(&em_tree->lock); | ||||
| @ -298,6 +555,7 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode, | ||||
| 	struct btrfs_path *path; | ||||
| 	struct btrfs_key key; | ||||
| 	struct btrfs_key new_key; | ||||
| 	u64 ino = btrfs_ino(inode); | ||||
| 	u64 search_start = start; | ||||
| 	u64 disk_bytenr = 0; | ||||
| 	u64 num_bytes = 0; | ||||
| @ -318,14 +576,14 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode, | ||||
| 
 | ||||
| 	while (1) { | ||||
| 		recow = 0; | ||||
| 		ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino, | ||||
| 		ret = btrfs_lookup_file_extent(trans, root, path, ino, | ||||
| 					       search_start, -1); | ||||
| 		if (ret < 0) | ||||
| 			break; | ||||
| 		if (ret > 0 && path->slots[0] > 0 && search_start == start) { | ||||
| 			leaf = path->nodes[0]; | ||||
| 			btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); | ||||
| 			if (key.objectid == inode->i_ino && | ||||
| 			if (key.objectid == ino && | ||||
| 			    key.type == BTRFS_EXTENT_DATA_KEY) | ||||
| 				path->slots[0]--; | ||||
| 		} | ||||
| @ -346,7 +604,7 @@ next_slot: | ||||
| 		} | ||||
| 
 | ||||
| 		btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); | ||||
| 		if (key.objectid > inode->i_ino || | ||||
| 		if (key.objectid > ino || | ||||
| 		    key.type > BTRFS_EXTENT_DATA_KEY || key.offset >= end) | ||||
| 			break; | ||||
| 
 | ||||
| @ -376,7 +634,7 @@ next_slot: | ||||
| 
 | ||||
| 		search_start = max(key.offset, start); | ||||
| 		if (recow) { | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| @ -393,7 +651,7 @@ next_slot: | ||||
| 			ret = btrfs_duplicate_item(trans, root, path, | ||||
| 						   &new_key); | ||||
| 			if (ret == -EAGAIN) { | ||||
| 				btrfs_release_path(root, path); | ||||
| 				btrfs_release_path(path); | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (ret < 0) | ||||
| @ -516,7 +774,7 @@ next_slot: | ||||
| 			del_nr = 0; | ||||
| 			del_slot = 0; | ||||
| 
 | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| @ -592,6 +850,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, | ||||
| 	int del_slot = 0; | ||||
| 	int recow; | ||||
| 	int ret; | ||||
| 	u64 ino = btrfs_ino(inode); | ||||
| 
 | ||||
| 	btrfs_drop_extent_cache(inode, start, end - 1, 0); | ||||
| 
 | ||||
| @ -600,7 +859,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, | ||||
| again: | ||||
| 	recow = 0; | ||||
| 	split = start; | ||||
| 	key.objectid = inode->i_ino; | ||||
| 	key.objectid = ino; | ||||
| 	key.type = BTRFS_EXTENT_DATA_KEY; | ||||
| 	key.offset = split; | ||||
| 
 | ||||
| @ -612,8 +871,7 @@ again: | ||||
| 
 | ||||
| 	leaf = path->nodes[0]; | ||||
| 	btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); | ||||
| 	BUG_ON(key.objectid != inode->i_ino || | ||||
| 	       key.type != BTRFS_EXTENT_DATA_KEY); | ||||
| 	BUG_ON(key.objectid != ino || key.type != BTRFS_EXTENT_DATA_KEY); | ||||
| 	fi = btrfs_item_ptr(leaf, path->slots[0], | ||||
| 			    struct btrfs_file_extent_item); | ||||
| 	BUG_ON(btrfs_file_extent_type(leaf, fi) != | ||||
| @ -630,7 +888,7 @@ again: | ||||
| 		other_start = 0; | ||||
| 		other_end = start; | ||||
| 		if (extent_mergeable(leaf, path->slots[0] - 1, | ||||
| 				     inode->i_ino, bytenr, orig_offset, | ||||
| 				     ino, bytenr, orig_offset, | ||||
| 				     &other_start, &other_end)) { | ||||
| 			new_key.offset = end; | ||||
| 			btrfs_set_item_key_safe(trans, root, path, &new_key); | ||||
| @ -653,7 +911,7 @@ again: | ||||
| 		other_start = end; | ||||
| 		other_end = 0; | ||||
| 		if (extent_mergeable(leaf, path->slots[0] + 1, | ||||
| 				     inode->i_ino, bytenr, orig_offset, | ||||
| 				     ino, bytenr, orig_offset, | ||||
| 				     &other_start, &other_end)) { | ||||
| 			fi = btrfs_item_ptr(leaf, path->slots[0], | ||||
| 					    struct btrfs_file_extent_item); | ||||
| @ -681,7 +939,7 @@ again: | ||||
| 		new_key.offset = split; | ||||
| 		ret = btrfs_duplicate_item(trans, root, path, &new_key); | ||||
| 		if (ret == -EAGAIN) { | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			goto again; | ||||
| 		} | ||||
| 		BUG_ON(ret < 0); | ||||
| @ -702,7 +960,7 @@ again: | ||||
| 
 | ||||
| 		ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0, | ||||
| 					   root->root_key.objectid, | ||||
| 					   inode->i_ino, orig_offset); | ||||
| 					   ino, orig_offset); | ||||
| 		BUG_ON(ret); | ||||
| 
 | ||||
| 		if (split == start) { | ||||
| @ -718,10 +976,10 @@ again: | ||||
| 	other_start = end; | ||||
| 	other_end = 0; | ||||
| 	if (extent_mergeable(leaf, path->slots[0] + 1, | ||||
| 			     inode->i_ino, bytenr, orig_offset, | ||||
| 			     ino, bytenr, orig_offset, | ||||
| 			     &other_start, &other_end)) { | ||||
| 		if (recow) { | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			goto again; | ||||
| 		} | ||||
| 		extent_end = other_end; | ||||
| @ -729,16 +987,16 @@ again: | ||||
| 		del_nr++; | ||||
| 		ret = btrfs_free_extent(trans, root, bytenr, num_bytes, | ||||
| 					0, root->root_key.objectid, | ||||
| 					inode->i_ino, orig_offset); | ||||
| 					ino, orig_offset); | ||||
| 		BUG_ON(ret); | ||||
| 	} | ||||
| 	other_start = 0; | ||||
| 	other_end = start; | ||||
| 	if (extent_mergeable(leaf, path->slots[0] - 1, | ||||
| 			     inode->i_ino, bytenr, orig_offset, | ||||
| 			     ino, bytenr, orig_offset, | ||||
| 			     &other_start, &other_end)) { | ||||
| 		if (recow) { | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			goto again; | ||||
| 		} | ||||
| 		key.offset = other_start; | ||||
| @ -746,7 +1004,7 @@ again: | ||||
| 		del_nr++; | ||||
| 		ret = btrfs_free_extent(trans, root, bytenr, num_bytes, | ||||
| 					0, root->root_key.objectid, | ||||
| 					inode->i_ino, orig_offset); | ||||
| 					ino, orig_offset); | ||||
| 		BUG_ON(ret); | ||||
| 	} | ||||
| 	if (del_nr == 0) { | ||||
| @ -1375,7 +1633,7 @@ static long btrfs_fallocate(struct file *file, int mode, | ||||
| 	while (1) { | ||||
| 		em = btrfs_get_extent(inode, NULL, 0, cur_offset, | ||||
| 				      alloc_end - cur_offset, 0); | ||||
| 		BUG_ON(IS_ERR(em) || !em); | ||||
| 		BUG_ON(IS_ERR_OR_NULL(em)); | ||||
| 		last_byte = min(extent_map_end(em), alloc_end); | ||||
| 		last_byte = (last_byte + mask) & ~mask; | ||||
| 		if (em->block_start == EXTENT_MAP_HOLE || | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -27,6 +27,25 @@ struct btrfs_free_space { | ||||
| 	struct list_head list; | ||||
| }; | ||||
| 
 | ||||
| struct btrfs_free_space_ctl { | ||||
| 	spinlock_t tree_lock; | ||||
| 	struct rb_root free_space_offset; | ||||
| 	u64 free_space; | ||||
| 	int extents_thresh; | ||||
| 	int free_extents; | ||||
| 	int total_bitmaps; | ||||
| 	int unit; | ||||
| 	u64 start; | ||||
| 	struct btrfs_free_space_op *op; | ||||
| 	void *private; | ||||
| }; | ||||
| 
 | ||||
| struct btrfs_free_space_op { | ||||
| 	void (*recalc_thresholds)(struct btrfs_free_space_ctl *ctl); | ||||
| 	bool (*use_bitmap)(struct btrfs_free_space_ctl *ctl, | ||||
| 			   struct btrfs_free_space *info); | ||||
| }; | ||||
| 
 | ||||
| struct inode *lookup_free_space_inode(struct btrfs_root *root, | ||||
| 				      struct btrfs_block_group_cache | ||||
| 				      *block_group, struct btrfs_path *path); | ||||
| @ -45,17 +64,38 @@ int btrfs_write_out_cache(struct btrfs_root *root, | ||||
| 			  struct btrfs_trans_handle *trans, | ||||
| 			  struct btrfs_block_group_cache *block_group, | ||||
| 			  struct btrfs_path *path); | ||||
| int btrfs_add_free_space(struct btrfs_block_group_cache *block_group, | ||||
| 			 u64 bytenr, u64 size); | ||||
| 
 | ||||
| struct inode *lookup_free_ino_inode(struct btrfs_root *root, | ||||
| 				    struct btrfs_path *path); | ||||
| int create_free_ino_inode(struct btrfs_root *root, | ||||
| 			  struct btrfs_trans_handle *trans, | ||||
| 			  struct btrfs_path *path); | ||||
| int load_free_ino_cache(struct btrfs_fs_info *fs_info, | ||||
| 			struct btrfs_root *root); | ||||
| int btrfs_write_out_ino_cache(struct btrfs_root *root, | ||||
| 			      struct btrfs_trans_handle *trans, | ||||
| 			      struct btrfs_path *path); | ||||
| 
 | ||||
| void btrfs_init_free_space_ctl(struct btrfs_block_group_cache *block_group); | ||||
| int __btrfs_add_free_space(struct btrfs_free_space_ctl *ctl, | ||||
| 			   u64 bytenr, u64 size); | ||||
| static inline int | ||||
| btrfs_add_free_space(struct btrfs_block_group_cache *block_group, | ||||
| 		     u64 bytenr, u64 size) | ||||
| { | ||||
| 	return __btrfs_add_free_space(block_group->free_space_ctl, | ||||
| 				      bytenr, size); | ||||
| } | ||||
| int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, | ||||
| 			    u64 bytenr, u64 size); | ||||
| void __btrfs_remove_free_space_cache(struct btrfs_free_space_ctl *ctl); | ||||
| void btrfs_remove_free_space_cache(struct btrfs_block_group_cache | ||||
| 				   *block_group); | ||||
| 				     *block_group); | ||||
| u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group, | ||||
| 			       u64 offset, u64 bytes, u64 empty_size); | ||||
| u64 btrfs_find_ino_for_alloc(struct btrfs_root *fs_root); | ||||
| void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group, | ||||
| 			   u64 bytes); | ||||
| u64 btrfs_block_group_free_space(struct btrfs_block_group_cache *block_group); | ||||
| int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, | ||||
| 			     struct btrfs_root *root, | ||||
| 			     struct btrfs_block_group_cache *block_group, | ||||
|  | ||||
| @ -130,7 +130,6 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, | ||||
| 			      item_size - (ptr + sub_item_len - item_start)); | ||||
| 	ret = btrfs_truncate_item(trans, root, path, | ||||
| 				  item_size - sub_item_len, 1); | ||||
| 	BUG_ON(ret); | ||||
| out: | ||||
| 	btrfs_free_path(path); | ||||
| 	return ret; | ||||
| @ -167,7 +166,6 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, | ||||
| 
 | ||||
| 		old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); | ||||
| 		ret = btrfs_extend_item(trans, root, path, ins_len); | ||||
| 		BUG_ON(ret); | ||||
| 		ref = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||||
| 				     struct btrfs_inode_ref); | ||||
| 		ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size); | ||||
|  | ||||
| @ -16,11 +16,446 @@ | ||||
|  * Boston, MA 021110-1307, USA. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/delay.h> | ||||
| #include <linux/kthread.h> | ||||
| #include <linux/pagemap.h> | ||||
| 
 | ||||
| #include "ctree.h" | ||||
| #include "disk-io.h" | ||||
| #include "free-space-cache.h" | ||||
| #include "inode-map.h" | ||||
| #include "transaction.h" | ||||
| 
 | ||||
| int btrfs_find_highest_inode(struct btrfs_root *root, u64 *objectid) | ||||
| static int caching_kthread(void *data) | ||||
| { | ||||
| 	struct btrfs_root *root = data; | ||||
| 	struct btrfs_fs_info *fs_info = root->fs_info; | ||||
| 	struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; | ||||
| 	struct btrfs_key key; | ||||
| 	struct btrfs_path *path; | ||||
| 	struct extent_buffer *leaf; | ||||
| 	u64 last = (u64)-1; | ||||
| 	int slot; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	path = btrfs_alloc_path(); | ||||
| 	if (!path) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	/* Since the commit root is read-only, we can safely skip locking. */ | ||||
| 	path->skip_locking = 1; | ||||
| 	path->search_commit_root = 1; | ||||
| 	path->reada = 2; | ||||
| 
 | ||||
| 	key.objectid = BTRFS_FIRST_FREE_OBJECTID; | ||||
| 	key.offset = 0; | ||||
| 	key.type = BTRFS_INODE_ITEM_KEY; | ||||
| again: | ||||
| 	/* need to make sure the commit_root doesn't disappear */ | ||||
| 	mutex_lock(&root->fs_commit_mutex); | ||||
| 
 | ||||
| 	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||||
| 	if (ret < 0) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	while (1) { | ||||
| 		smp_mb(); | ||||
| 		if (fs_info->closing) | ||||
| 			goto out; | ||||
| 
 | ||||
| 		leaf = path->nodes[0]; | ||||
| 		slot = path->slots[0]; | ||||
| 		if (slot >= btrfs_header_nritems(leaf)) { | ||||
| 			ret = btrfs_next_leaf(root, path); | ||||
| 			if (ret < 0) | ||||
| 				goto out; | ||||
| 			else if (ret > 0) | ||||
| 				break; | ||||
| 
 | ||||
| 			if (need_resched() || | ||||
| 			    btrfs_transaction_in_commit(fs_info)) { | ||||
| 				leaf = path->nodes[0]; | ||||
| 
 | ||||
| 				if (btrfs_header_nritems(leaf) == 0) { | ||||
| 					WARN_ON(1); | ||||
| 					break; | ||||
| 				} | ||||
| 
 | ||||
| 				/*
 | ||||
| 				 * Save the key so we can advances forward | ||||
| 				 * in the next search. | ||||
| 				 */ | ||||
| 				btrfs_item_key_to_cpu(leaf, &key, 0); | ||||
| 				btrfs_release_path(path); | ||||
| 				root->cache_progress = last; | ||||
| 				mutex_unlock(&root->fs_commit_mutex); | ||||
| 				schedule_timeout(1); | ||||
| 				goto again; | ||||
| 			} else | ||||
| 				continue; | ||||
| 		} | ||||
| 
 | ||||
| 		btrfs_item_key_to_cpu(leaf, &key, slot); | ||||
| 
 | ||||
| 		if (key.type != BTRFS_INODE_ITEM_KEY) | ||||
| 			goto next; | ||||
| 
 | ||||
| 		if (key.objectid >= root->highest_objectid) | ||||
| 			break; | ||||
| 
 | ||||
| 		if (last != (u64)-1 && last + 1 != key.objectid) { | ||||
| 			__btrfs_add_free_space(ctl, last + 1, | ||||
| 					       key.objectid - last - 1); | ||||
| 			wake_up(&root->cache_wait); | ||||
| 		} | ||||
| 
 | ||||
| 		last = key.objectid; | ||||
| next: | ||||
| 		path->slots[0]++; | ||||
| 	} | ||||
| 
 | ||||
| 	if (last < root->highest_objectid - 1) { | ||||
| 		__btrfs_add_free_space(ctl, last + 1, | ||||
| 				       root->highest_objectid - last - 1); | ||||
| 	} | ||||
| 
 | ||||
| 	spin_lock(&root->cache_lock); | ||||
| 	root->cached = BTRFS_CACHE_FINISHED; | ||||
| 	spin_unlock(&root->cache_lock); | ||||
| 
 | ||||
| 	root->cache_progress = (u64)-1; | ||||
| 	btrfs_unpin_free_ino(root); | ||||
| out: | ||||
| 	wake_up(&root->cache_wait); | ||||
| 	mutex_unlock(&root->fs_commit_mutex); | ||||
| 
 | ||||
| 	btrfs_free_path(path); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void start_caching(struct btrfs_root *root) | ||||
| { | ||||
| 	struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; | ||||
| 	struct task_struct *tsk; | ||||
| 	int ret; | ||||
| 	u64 objectid; | ||||
| 
 | ||||
| 	spin_lock(&root->cache_lock); | ||||
| 	if (root->cached != BTRFS_CACHE_NO) { | ||||
| 		spin_unlock(&root->cache_lock); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	root->cached = BTRFS_CACHE_STARTED; | ||||
| 	spin_unlock(&root->cache_lock); | ||||
| 
 | ||||
| 	ret = load_free_ino_cache(root->fs_info, root); | ||||
| 	if (ret == 1) { | ||||
| 		spin_lock(&root->cache_lock); | ||||
| 		root->cached = BTRFS_CACHE_FINISHED; | ||||
| 		spin_unlock(&root->cache_lock); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * It can be quite time-consuming to fill the cache by searching | ||||
| 	 * through the extent tree, and this can keep ino allocation path | ||||
| 	 * waiting. Therefore at start we quickly find out the highest | ||||
| 	 * inode number and we know we can use inode numbers which fall in | ||||
| 	 * [highest_ino + 1, BTRFS_LAST_FREE_OBJECTID]. | ||||
| 	 */ | ||||
| 	ret = btrfs_find_free_objectid(root, &objectid); | ||||
| 	if (!ret && objectid <= BTRFS_LAST_FREE_OBJECTID) { | ||||
| 		__btrfs_add_free_space(ctl, objectid, | ||||
| 				       BTRFS_LAST_FREE_OBJECTID - objectid + 1); | ||||
| 	} | ||||
| 
 | ||||
| 	tsk = kthread_run(caching_kthread, root, "btrfs-ino-cache-%llu\n", | ||||
| 			  root->root_key.objectid); | ||||
| 	BUG_ON(IS_ERR(tsk)); | ||||
| } | ||||
| 
 | ||||
| int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid) | ||||
| { | ||||
| again: | ||||
| 	*objectid = btrfs_find_ino_for_alloc(root); | ||||
| 
 | ||||
| 	if (*objectid != 0) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	start_caching(root); | ||||
| 
 | ||||
| 	wait_event(root->cache_wait, | ||||
| 		   root->cached == BTRFS_CACHE_FINISHED || | ||||
| 		   root->free_ino_ctl->free_space > 0); | ||||
| 
 | ||||
| 	if (root->cached == BTRFS_CACHE_FINISHED && | ||||
| 	    root->free_ino_ctl->free_space == 0) | ||||
| 		return -ENOSPC; | ||||
| 	else | ||||
| 		goto again; | ||||
| } | ||||
| 
 | ||||
| void btrfs_return_ino(struct btrfs_root *root, u64 objectid) | ||||
| { | ||||
| 	struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; | ||||
| 	struct btrfs_free_space_ctl *pinned = root->free_ino_pinned; | ||||
| again: | ||||
| 	if (root->cached == BTRFS_CACHE_FINISHED) { | ||||
| 		__btrfs_add_free_space(ctl, objectid, 1); | ||||
| 	} else { | ||||
| 		/*
 | ||||
| 		 * If we are in the process of caching free ino chunks, | ||||
| 		 * to avoid adding the same inode number to the free_ino | ||||
| 		 * tree twice due to cross transaction, we'll leave it | ||||
| 		 * in the pinned tree until a transaction is committed | ||||
| 		 * or the caching work is done. | ||||
| 		 */ | ||||
| 
 | ||||
| 		mutex_lock(&root->fs_commit_mutex); | ||||
| 		spin_lock(&root->cache_lock); | ||||
| 		if (root->cached == BTRFS_CACHE_FINISHED) { | ||||
| 			spin_unlock(&root->cache_lock); | ||||
| 			mutex_unlock(&root->fs_commit_mutex); | ||||
| 			goto again; | ||||
| 		} | ||||
| 		spin_unlock(&root->cache_lock); | ||||
| 
 | ||||
| 		start_caching(root); | ||||
| 
 | ||||
| 		if (objectid <= root->cache_progress || | ||||
| 		    objectid > root->highest_objectid) | ||||
| 			__btrfs_add_free_space(ctl, objectid, 1); | ||||
| 		else | ||||
| 			__btrfs_add_free_space(pinned, objectid, 1); | ||||
| 
 | ||||
| 		mutex_unlock(&root->fs_commit_mutex); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * When a transaction is committed, we'll move those inode numbers which | ||||
|  * are smaller than root->cache_progress from pinned tree to free_ino tree, | ||||
|  * and others will just be dropped, because the commit root we were | ||||
|  * searching has changed. | ||||
|  * | ||||
|  * Must be called with root->fs_commit_mutex held | ||||
|  */ | ||||
| void btrfs_unpin_free_ino(struct btrfs_root *root) | ||||
| { | ||||
| 	struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; | ||||
| 	struct rb_root *rbroot = &root->free_ino_pinned->free_space_offset; | ||||
| 	struct btrfs_free_space *info; | ||||
| 	struct rb_node *n; | ||||
| 	u64 count; | ||||
| 
 | ||||
| 	while (1) { | ||||
| 		n = rb_first(rbroot); | ||||
| 		if (!n) | ||||
| 			break; | ||||
| 
 | ||||
| 		info = rb_entry(n, struct btrfs_free_space, offset_index); | ||||
| 		BUG_ON(info->bitmap); | ||||
| 
 | ||||
| 		if (info->offset > root->cache_progress) | ||||
| 			goto free; | ||||
| 		else if (info->offset + info->bytes > root->cache_progress) | ||||
| 			count = root->cache_progress - info->offset + 1; | ||||
| 		else | ||||
| 			count = info->bytes; | ||||
| 
 | ||||
| 		__btrfs_add_free_space(ctl, info->offset, count); | ||||
| free: | ||||
| 		rb_erase(&info->offset_index, rbroot); | ||||
| 		kfree(info); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #define INIT_THRESHOLD	(((1024 * 32) / 2) / sizeof(struct btrfs_free_space)) | ||||
| #define INODES_PER_BITMAP (PAGE_CACHE_SIZE * 8) | ||||
| 
 | ||||
| /*
 | ||||
|  * The goal is to keep the memory used by the free_ino tree won't | ||||
|  * exceed the memory if we use bitmaps only. | ||||
|  */ | ||||
| static void recalculate_thresholds(struct btrfs_free_space_ctl *ctl) | ||||
| { | ||||
| 	struct btrfs_free_space *info; | ||||
| 	struct rb_node *n; | ||||
| 	int max_ino; | ||||
| 	int max_bitmaps; | ||||
| 
 | ||||
| 	n = rb_last(&ctl->free_space_offset); | ||||
| 	if (!n) { | ||||
| 		ctl->extents_thresh = INIT_THRESHOLD; | ||||
| 		return; | ||||
| 	} | ||||
| 	info = rb_entry(n, struct btrfs_free_space, offset_index); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Find the maximum inode number in the filesystem. Note we | ||||
| 	 * ignore the fact that this can be a bitmap, because we are | ||||
| 	 * not doing precise calculation. | ||||
| 	 */ | ||||
| 	max_ino = info->bytes - 1; | ||||
| 
 | ||||
| 	max_bitmaps = ALIGN(max_ino, INODES_PER_BITMAP) / INODES_PER_BITMAP; | ||||
| 	if (max_bitmaps <= ctl->total_bitmaps) { | ||||
| 		ctl->extents_thresh = 0; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	ctl->extents_thresh = (max_bitmaps - ctl->total_bitmaps) * | ||||
| 				PAGE_CACHE_SIZE / sizeof(*info); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * We don't fall back to bitmap, if we are below the extents threshold | ||||
|  * or this chunk of inode numbers is a big one. | ||||
|  */ | ||||
| static bool use_bitmap(struct btrfs_free_space_ctl *ctl, | ||||
| 		       struct btrfs_free_space *info) | ||||
| { | ||||
| 	if (ctl->free_extents < ctl->extents_thresh || | ||||
| 	    info->bytes > INODES_PER_BITMAP / 10) | ||||
| 		return false; | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static struct btrfs_free_space_op free_ino_op = { | ||||
| 	.recalc_thresholds	= recalculate_thresholds, | ||||
| 	.use_bitmap		= use_bitmap, | ||||
| }; | ||||
| 
 | ||||
| static void pinned_recalc_thresholds(struct btrfs_free_space_ctl *ctl) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static bool pinned_use_bitmap(struct btrfs_free_space_ctl *ctl, | ||||
| 			      struct btrfs_free_space *info) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * We always use extents for two reasons: | ||||
| 	 * | ||||
| 	 * - The pinned tree is only used during the process of caching | ||||
| 	 *   work. | ||||
| 	 * - Make code simpler. See btrfs_unpin_free_ino(). | ||||
| 	 */ | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| static struct btrfs_free_space_op pinned_free_ino_op = { | ||||
| 	.recalc_thresholds	= pinned_recalc_thresholds, | ||||
| 	.use_bitmap		= pinned_use_bitmap, | ||||
| }; | ||||
| 
 | ||||
| void btrfs_init_free_ino_ctl(struct btrfs_root *root) | ||||
| { | ||||
| 	struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; | ||||
| 	struct btrfs_free_space_ctl *pinned = root->free_ino_pinned; | ||||
| 
 | ||||
| 	spin_lock_init(&ctl->tree_lock); | ||||
| 	ctl->unit = 1; | ||||
| 	ctl->start = 0; | ||||
| 	ctl->private = NULL; | ||||
| 	ctl->op = &free_ino_op; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Initially we allow to use 16K of ram to cache chunks of | ||||
| 	 * inode numbers before we resort to bitmaps. This is somewhat | ||||
| 	 * arbitrary, but it will be adjusted in runtime. | ||||
| 	 */ | ||||
| 	ctl->extents_thresh = INIT_THRESHOLD; | ||||
| 
 | ||||
| 	spin_lock_init(&pinned->tree_lock); | ||||
| 	pinned->unit = 1; | ||||
| 	pinned->start = 0; | ||||
| 	pinned->private = NULL; | ||||
| 	pinned->extents_thresh = 0; | ||||
| 	pinned->op = &pinned_free_ino_op; | ||||
| } | ||||
| 
 | ||||
| int btrfs_save_ino_cache(struct btrfs_root *root, | ||||
| 			 struct btrfs_trans_handle *trans) | ||||
| { | ||||
| 	struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; | ||||
| 	struct btrfs_path *path; | ||||
| 	struct inode *inode; | ||||
| 	u64 alloc_hint = 0; | ||||
| 	int ret; | ||||
| 	int prealloc; | ||||
| 	bool retry = false; | ||||
| 
 | ||||
| 	path = btrfs_alloc_path(); | ||||
| 	if (!path) | ||||
| 		return -ENOMEM; | ||||
| again: | ||||
| 	inode = lookup_free_ino_inode(root, path); | ||||
| 	if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) { | ||||
| 		ret = PTR_ERR(inode); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	if (IS_ERR(inode)) { | ||||
| 		BUG_ON(retry); | ||||
| 		retry = true; | ||||
| 
 | ||||
| 		ret = create_free_ino_inode(root, trans, path); | ||||
| 		if (ret) | ||||
| 			goto out; | ||||
| 		goto again; | ||||
| 	} | ||||
| 
 | ||||
| 	BTRFS_I(inode)->generation = 0; | ||||
| 	ret = btrfs_update_inode(trans, root, inode); | ||||
| 	WARN_ON(ret); | ||||
| 
 | ||||
| 	if (i_size_read(inode) > 0) { | ||||
| 		ret = btrfs_truncate_free_space_cache(root, trans, path, inode); | ||||
| 		if (ret) | ||||
| 			goto out_put; | ||||
| 	} | ||||
| 
 | ||||
| 	spin_lock(&root->cache_lock); | ||||
| 	if (root->cached != BTRFS_CACHE_FINISHED) { | ||||
| 		ret = -1; | ||||
| 		spin_unlock(&root->cache_lock); | ||||
| 		goto out_put; | ||||
| 	} | ||||
| 	spin_unlock(&root->cache_lock); | ||||
| 
 | ||||
| 	spin_lock(&ctl->tree_lock); | ||||
| 	prealloc = sizeof(struct btrfs_free_space) * ctl->free_extents; | ||||
| 	prealloc = ALIGN(prealloc, PAGE_CACHE_SIZE); | ||||
| 	prealloc += ctl->total_bitmaps * PAGE_CACHE_SIZE; | ||||
| 	spin_unlock(&ctl->tree_lock); | ||||
| 
 | ||||
| 	/* Just to make sure we have enough space */ | ||||
| 	prealloc += 8 * PAGE_CACHE_SIZE; | ||||
| 
 | ||||
| 	ret = btrfs_check_data_free_space(inode, prealloc); | ||||
| 	if (ret) | ||||
| 		goto out_put; | ||||
| 
 | ||||
| 	ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, prealloc, | ||||
| 					      prealloc, prealloc, &alloc_hint); | ||||
| 	if (ret) | ||||
| 		goto out_put; | ||||
| 	btrfs_free_reserved_data_space(inode, prealloc); | ||||
| 
 | ||||
| out_put: | ||||
| 	iput(inode); | ||||
| out: | ||||
| 	if (ret == 0) | ||||
| 		ret = btrfs_write_out_ino_cache(root, trans, path); | ||||
| 
 | ||||
| 	btrfs_free_path(path); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int btrfs_find_highest_objectid(struct btrfs_root *root, u64 *objectid) | ||||
| { | ||||
| 	struct btrfs_path *path; | ||||
| 	int ret; | ||||
| @ -55,15 +490,14 @@ error: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| int btrfs_find_free_objectid(struct btrfs_trans_handle *trans, | ||||
| 			     struct btrfs_root *root, | ||||
| 			     u64 dirid, u64 *objectid) | ||||
| int btrfs_find_free_objectid(struct btrfs_root *root, u64 *objectid) | ||||
| { | ||||
| 	int ret; | ||||
| 	mutex_lock(&root->objectid_mutex); | ||||
| 
 | ||||
| 	if (unlikely(root->highest_objectid < BTRFS_FIRST_FREE_OBJECTID)) { | ||||
| 		ret = btrfs_find_highest_inode(root, &root->highest_objectid); | ||||
| 		ret = btrfs_find_highest_objectid(root, | ||||
| 						  &root->highest_objectid); | ||||
| 		if (ret) | ||||
| 			goto out; | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										13
									
								
								fs/btrfs/inode-map.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								fs/btrfs/inode-map.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| #ifndef __BTRFS_INODE_MAP | ||||
| #define __BTRFS_INODE_MAP | ||||
| 
 | ||||
| void btrfs_init_free_ino_ctl(struct btrfs_root *root); | ||||
| void btrfs_unpin_free_ino(struct btrfs_root *root); | ||||
| void btrfs_return_ino(struct btrfs_root *root, u64 objectid); | ||||
| int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid); | ||||
| int btrfs_save_ino_cache(struct btrfs_root *root, | ||||
| 			 struct btrfs_trans_handle *trans); | ||||
| 
 | ||||
| int btrfs_find_free_objectid(struct btrfs_root *root, u64 *objectid); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										700
									
								
								fs/btrfs/inode.c
									
									
									
									
									
								
							
							
						
						
									
										700
									
								
								fs/btrfs/inode.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										630
									
								
								fs/btrfs/ioctl.c
									
									
									
									
									
								
							
							
						
						
									
										630
									
								
								fs/btrfs/ioctl.c
									
									
									
									
									
								
							| @ -50,6 +50,7 @@ | ||||
| #include "print-tree.h" | ||||
| #include "volumes.h" | ||||
| #include "locking.h" | ||||
| #include "inode-map.h" | ||||
| 
 | ||||
| /* Mask out flags that are inappropriate for the given type of inode. */ | ||||
| static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) | ||||
| @ -281,8 +282,9 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) | ||||
| 	if (!capable(CAP_SYS_ADMIN)) | ||||
| 		return -EPERM; | ||||
| 
 | ||||
| 	mutex_lock(&fs_info->fs_devices->device_list_mutex); | ||||
| 	list_for_each_entry(device, &fs_info->fs_devices->devices, dev_list) { | ||||
| 	rcu_read_lock(); | ||||
| 	list_for_each_entry_rcu(device, &fs_info->fs_devices->devices, | ||||
| 				dev_list) { | ||||
| 		if (!device->bdev) | ||||
| 			continue; | ||||
| 		q = bdev_get_queue(device->bdev); | ||||
| @ -292,7 +294,7 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) | ||||
| 				     minlen); | ||||
| 		} | ||||
| 	} | ||||
| 	mutex_unlock(&fs_info->fs_devices->device_list_mutex); | ||||
| 	rcu_read_unlock(); | ||||
| 	if (!num_devices) | ||||
| 		return -EOPNOTSUPP; | ||||
| 
 | ||||
| @ -329,8 +331,7 @@ static noinline int create_subvol(struct btrfs_root *root, | ||||
| 	u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; | ||||
| 	u64 index = 0; | ||||
| 
 | ||||
| 	ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root, | ||||
| 				       0, &objectid); | ||||
| 	ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid); | ||||
| 	if (ret) { | ||||
| 		dput(parent); | ||||
| 		return ret; | ||||
| @ -422,7 +423,7 @@ static noinline int create_subvol(struct btrfs_root *root, | ||||
| 	BUG_ON(ret); | ||||
| 
 | ||||
| 	ret = btrfs_insert_dir_item(trans, root, | ||||
| 				    name, namelen, dir->i_ino, &key, | ||||
| 				    name, namelen, dir, &key, | ||||
| 				    BTRFS_FT_DIR, index); | ||||
| 	if (ret) | ||||
| 		goto fail; | ||||
| @ -433,7 +434,7 @@ static noinline int create_subvol(struct btrfs_root *root, | ||||
| 
 | ||||
| 	ret = btrfs_add_root_ref(trans, root->fs_info->tree_root, | ||||
| 				 objectid, root->root_key.objectid, | ||||
| 				 dir->i_ino, index, name, namelen); | ||||
| 				 btrfs_ino(dir), index, name, namelen); | ||||
| 
 | ||||
| 	BUG_ON(ret); | ||||
| 
 | ||||
| @ -655,6 +656,106 @@ out_unlock: | ||||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * When we're defragging a range, we don't want to kick it off again | ||||
|  * if it is really just waiting for delalloc to send it down. | ||||
|  * If we find a nice big extent or delalloc range for the bytes in the | ||||
|  * file you want to defrag, we return 0 to let you know to skip this | ||||
|  * part of the file | ||||
|  */ | ||||
| static int check_defrag_in_cache(struct inode *inode, u64 offset, int thresh) | ||||
| { | ||||
| 	struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | ||||
| 	struct extent_map *em = NULL; | ||||
| 	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | ||||
| 	u64 end; | ||||
| 
 | ||||
| 	read_lock(&em_tree->lock); | ||||
| 	em = lookup_extent_mapping(em_tree, offset, PAGE_CACHE_SIZE); | ||||
| 	read_unlock(&em_tree->lock); | ||||
| 
 | ||||
| 	if (em) { | ||||
| 		end = extent_map_end(em); | ||||
| 		free_extent_map(em); | ||||
| 		if (end - offset > thresh) | ||||
| 			return 0; | ||||
| 	} | ||||
| 	/* if we already have a nice delalloc here, just stop */ | ||||
| 	thresh /= 2; | ||||
| 	end = count_range_bits(io_tree, &offset, offset + thresh, | ||||
| 			       thresh, EXTENT_DELALLOC, 1); | ||||
| 	if (end >= thresh) | ||||
| 		return 0; | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * helper function to walk through a file and find extents | ||||
|  * newer than a specific transid, and smaller than thresh. | ||||
|  * | ||||
|  * This is used by the defragging code to find new and small | ||||
|  * extents | ||||
|  */ | ||||
| static int find_new_extents(struct btrfs_root *root, | ||||
| 			    struct inode *inode, u64 newer_than, | ||||
| 			    u64 *off, int thresh) | ||||
| { | ||||
| 	struct btrfs_path *path; | ||||
| 	struct btrfs_key min_key; | ||||
| 	struct btrfs_key max_key; | ||||
| 	struct extent_buffer *leaf; | ||||
| 	struct btrfs_file_extent_item *extent; | ||||
| 	int type; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	path = btrfs_alloc_path(); | ||||
| 	if (!path) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	min_key.objectid = inode->i_ino; | ||||
| 	min_key.type = BTRFS_EXTENT_DATA_KEY; | ||||
| 	min_key.offset = *off; | ||||
| 
 | ||||
| 	max_key.objectid = inode->i_ino; | ||||
| 	max_key.type = (u8)-1; | ||||
| 	max_key.offset = (u64)-1; | ||||
| 
 | ||||
| 	path->keep_locks = 1; | ||||
| 
 | ||||
| 	while(1) { | ||||
| 		ret = btrfs_search_forward(root, &min_key, &max_key, | ||||
| 					   path, 0, newer_than); | ||||
| 		if (ret != 0) | ||||
| 			goto none; | ||||
| 		if (min_key.objectid != inode->i_ino) | ||||
| 			goto none; | ||||
| 		if (min_key.type != BTRFS_EXTENT_DATA_KEY) | ||||
| 			goto none; | ||||
| 
 | ||||
| 		leaf = path->nodes[0]; | ||||
| 		extent = btrfs_item_ptr(leaf, path->slots[0], | ||||
| 					struct btrfs_file_extent_item); | ||||
| 
 | ||||
| 		type = btrfs_file_extent_type(leaf, extent); | ||||
| 		if (type == BTRFS_FILE_EXTENT_REG && | ||||
| 		    btrfs_file_extent_num_bytes(leaf, extent) < thresh && | ||||
| 		    check_defrag_in_cache(inode, min_key.offset, thresh)) { | ||||
| 			*off = min_key.offset; | ||||
| 			btrfs_free_path(path); | ||||
| 			return 0; | ||||
| 		} | ||||
| 
 | ||||
| 		if (min_key.offset == (u64)-1) | ||||
| 			goto none; | ||||
| 
 | ||||
| 		min_key.offset++; | ||||
| 		btrfs_release_path(path); | ||||
| 	} | ||||
| none: | ||||
| 	btrfs_free_path(path); | ||||
| 	return -ENOENT; | ||||
| } | ||||
| 
 | ||||
| static int should_defrag_range(struct inode *inode, u64 start, u64 len, | ||||
| 			       int thresh, u64 *last_len, u64 *skip, | ||||
| 			       u64 *defrag_end) | ||||
| @ -664,10 +765,6 @@ static int should_defrag_range(struct inode *inode, u64 start, u64 len, | ||||
| 	struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | ||||
| 	int ret = 1; | ||||
| 
 | ||||
| 
 | ||||
| 	if (thresh == 0) | ||||
| 		thresh = 256 * 1024; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * make sure that once we start defragging and extent, we keep on | ||||
| 	 * defragging it | ||||
| @ -726,27 +823,176 @@ static int should_defrag_range(struct inode *inode, u64 start, u64 len, | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int btrfs_defrag_file(struct file *file, | ||||
| 			     struct btrfs_ioctl_defrag_range_args *range) | ||||
| /*
 | ||||
|  * it doesn't do much good to defrag one or two pages | ||||
|  * at a time.  This pulls in a nice chunk of pages | ||||
|  * to COW and defrag. | ||||
|  * | ||||
|  * It also makes sure the delalloc code has enough | ||||
|  * dirty data to avoid making new small extents as part | ||||
|  * of the defrag | ||||
|  * | ||||
|  * It's a good idea to start RA on this range | ||||
|  * before calling this. | ||||
|  */ | ||||
| static int cluster_pages_for_defrag(struct inode *inode, | ||||
| 				    struct page **pages, | ||||
| 				    unsigned long start_index, | ||||
| 				    int num_pages) | ||||
| { | ||||
| 	struct inode *inode = fdentry(file)->d_inode; | ||||
| 	struct btrfs_root *root = BTRFS_I(inode)->root; | ||||
| 	struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | ||||
| 	struct btrfs_ordered_extent *ordered; | ||||
| 	struct page *page; | ||||
| 	struct btrfs_super_block *disk_super; | ||||
| 	unsigned long last_index; | ||||
| 	unsigned long ra_pages = root->fs_info->bdi.ra_pages; | ||||
| 	unsigned long total_read = 0; | ||||
| 	u64 features; | ||||
| 	unsigned long file_end; | ||||
| 	u64 isize = i_size_read(inode); | ||||
| 	u64 page_start; | ||||
| 	u64 page_end; | ||||
| 	int ret; | ||||
| 	int i; | ||||
| 	int i_done; | ||||
| 	struct btrfs_ordered_extent *ordered; | ||||
| 	struct extent_state *cached_state = NULL; | ||||
| 
 | ||||
| 	if (isize == 0) | ||||
| 		return 0; | ||||
| 	file_end = (isize - 1) >> PAGE_CACHE_SHIFT; | ||||
| 
 | ||||
| 	ret = btrfs_delalloc_reserve_space(inode, | ||||
| 					   num_pages << PAGE_CACHE_SHIFT); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| again: | ||||
| 	ret = 0; | ||||
| 	i_done = 0; | ||||
| 
 | ||||
| 	/* step one, lock all the pages */ | ||||
| 	for (i = 0; i < num_pages; i++) { | ||||
| 		struct page *page; | ||||
| 		page = grab_cache_page(inode->i_mapping, | ||||
| 					    start_index + i); | ||||
| 		if (!page) | ||||
| 			break; | ||||
| 
 | ||||
| 		if (!PageUptodate(page)) { | ||||
| 			btrfs_readpage(NULL, page); | ||||
| 			lock_page(page); | ||||
| 			if (!PageUptodate(page)) { | ||||
| 				unlock_page(page); | ||||
| 				page_cache_release(page); | ||||
| 				ret = -EIO; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		isize = i_size_read(inode); | ||||
| 		file_end = (isize - 1) >> PAGE_CACHE_SHIFT; | ||||
| 		if (!isize || page->index > file_end || | ||||
| 		    page->mapping != inode->i_mapping) { | ||||
| 			/* whoops, we blew past eof, skip this page */ | ||||
| 			unlock_page(page); | ||||
| 			page_cache_release(page); | ||||
| 			break; | ||||
| 		} | ||||
| 		pages[i] = page; | ||||
| 		i_done++; | ||||
| 	} | ||||
| 	if (!i_done || ret) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	if (!(inode->i_sb->s_flags & MS_ACTIVE)) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * so now we have a nice long stream of locked | ||||
| 	 * and up to date pages, lets wait on them | ||||
| 	 */ | ||||
| 	for (i = 0; i < i_done; i++) | ||||
| 		wait_on_page_writeback(pages[i]); | ||||
| 
 | ||||
| 	page_start = page_offset(pages[0]); | ||||
| 	page_end = page_offset(pages[i_done - 1]) + PAGE_CACHE_SIZE; | ||||
| 
 | ||||
| 	lock_extent_bits(&BTRFS_I(inode)->io_tree, | ||||
| 			 page_start, page_end - 1, 0, &cached_state, | ||||
| 			 GFP_NOFS); | ||||
| 	ordered = btrfs_lookup_first_ordered_extent(inode, page_end - 1); | ||||
| 	if (ordered && | ||||
| 	    ordered->file_offset + ordered->len > page_start && | ||||
| 	    ordered->file_offset < page_end) { | ||||
| 		btrfs_put_ordered_extent(ordered); | ||||
| 		unlock_extent_cached(&BTRFS_I(inode)->io_tree, | ||||
| 				     page_start, page_end - 1, | ||||
| 				     &cached_state, GFP_NOFS); | ||||
| 		for (i = 0; i < i_done; i++) { | ||||
| 			unlock_page(pages[i]); | ||||
| 			page_cache_release(pages[i]); | ||||
| 		} | ||||
| 		btrfs_wait_ordered_range(inode, page_start, | ||||
| 					 page_end - page_start); | ||||
| 		goto again; | ||||
| 	} | ||||
| 	if (ordered) | ||||
| 		btrfs_put_ordered_extent(ordered); | ||||
| 
 | ||||
| 	clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start, | ||||
| 			  page_end - 1, EXTENT_DIRTY | EXTENT_DELALLOC | | ||||
| 			  EXTENT_DO_ACCOUNTING, 0, 0, &cached_state, | ||||
| 			  GFP_NOFS); | ||||
| 
 | ||||
| 	if (i_done != num_pages) { | ||||
| 		atomic_inc(&BTRFS_I(inode)->outstanding_extents); | ||||
| 		btrfs_delalloc_release_space(inode, | ||||
| 				     (num_pages - i_done) << PAGE_CACHE_SHIFT); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	btrfs_set_extent_delalloc(inode, page_start, page_end - 1, | ||||
| 				  &cached_state); | ||||
| 
 | ||||
| 	unlock_extent_cached(&BTRFS_I(inode)->io_tree, | ||||
| 			     page_start, page_end - 1, &cached_state, | ||||
| 			     GFP_NOFS); | ||||
| 
 | ||||
| 	for (i = 0; i < i_done; i++) { | ||||
| 		clear_page_dirty_for_io(pages[i]); | ||||
| 		ClearPageChecked(pages[i]); | ||||
| 		set_page_extent_mapped(pages[i]); | ||||
| 		set_page_dirty(pages[i]); | ||||
| 		unlock_page(pages[i]); | ||||
| 		page_cache_release(pages[i]); | ||||
| 	} | ||||
| 	return i_done; | ||||
| out: | ||||
| 	for (i = 0; i < i_done; i++) { | ||||
| 		unlock_page(pages[i]); | ||||
| 		page_cache_release(pages[i]); | ||||
| 	} | ||||
| 	btrfs_delalloc_release_space(inode, num_pages << PAGE_CACHE_SHIFT); | ||||
| 	return ret; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| int btrfs_defrag_file(struct inode *inode, struct file *file, | ||||
| 		      struct btrfs_ioctl_defrag_range_args *range, | ||||
| 		      u64 newer_than, unsigned long max_to_defrag) | ||||
| { | ||||
| 	struct btrfs_root *root = BTRFS_I(inode)->root; | ||||
| 	struct btrfs_super_block *disk_super; | ||||
| 	struct file_ra_state *ra = NULL; | ||||
| 	unsigned long last_index; | ||||
| 	u64 features; | ||||
| 	u64 last_len = 0; | ||||
| 	u64 skip = 0; | ||||
| 	u64 defrag_end = 0; | ||||
| 	u64 newer_off = range->start; | ||||
| 	int newer_left = 0; | ||||
| 	unsigned long i; | ||||
| 	int ret; | ||||
| 	int defrag_count = 0; | ||||
| 	int compress_type = BTRFS_COMPRESS_ZLIB; | ||||
| 	int extent_thresh = range->extent_thresh; | ||||
| 	int newer_cluster = (256 * 1024) >> PAGE_CACHE_SHIFT; | ||||
| 	u64 new_align = ~((u64)128 * 1024 - 1); | ||||
| 	struct page **pages = NULL; | ||||
| 
 | ||||
| 	if (extent_thresh == 0) | ||||
| 		extent_thresh = 256 * 1024; | ||||
| 
 | ||||
| 	if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) { | ||||
| 		if (range->compress_type > BTRFS_COMPRESS_TYPES) | ||||
| @ -758,6 +1004,27 @@ static int btrfs_defrag_file(struct file *file, | ||||
| 	if (inode->i_size == 0) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * if we were not given a file, allocate a readahead | ||||
| 	 * context | ||||
| 	 */ | ||||
| 	if (!file) { | ||||
| 		ra = kzalloc(sizeof(*ra), GFP_NOFS); | ||||
| 		if (!ra) | ||||
| 			return -ENOMEM; | ||||
| 		file_ra_state_init(ra, inode->i_mapping); | ||||
| 	} else { | ||||
| 		ra = &file->f_ra; | ||||
| 	} | ||||
| 
 | ||||
| 	pages = kmalloc(sizeof(struct page *) * newer_cluster, | ||||
| 			GFP_NOFS); | ||||
| 	if (!pages) { | ||||
| 		ret = -ENOMEM; | ||||
| 		goto out_ra; | ||||
| 	} | ||||
| 
 | ||||
| 	/* find the last page to defrag */ | ||||
| 	if (range->start + range->len > range->start) { | ||||
| 		last_index = min_t(u64, inode->i_size - 1, | ||||
| 			 range->start + range->len - 1) >> PAGE_CACHE_SHIFT; | ||||
| @ -765,11 +1032,37 @@ static int btrfs_defrag_file(struct file *file, | ||||
| 		last_index = (inode->i_size - 1) >> PAGE_CACHE_SHIFT; | ||||
| 	} | ||||
| 
 | ||||
| 	i = range->start >> PAGE_CACHE_SHIFT; | ||||
| 	while (i <= last_index) { | ||||
| 		if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT, | ||||
| 	if (newer_than) { | ||||
| 		ret = find_new_extents(root, inode, newer_than, | ||||
| 				       &newer_off, 64 * 1024); | ||||
| 		if (!ret) { | ||||
| 			range->start = newer_off; | ||||
| 			/*
 | ||||
| 			 * we always align our defrag to help keep | ||||
| 			 * the extents in the file evenly spaced | ||||
| 			 */ | ||||
| 			i = (newer_off & new_align) >> PAGE_CACHE_SHIFT; | ||||
| 			newer_left = newer_cluster; | ||||
| 		} else | ||||
| 			goto out_ra; | ||||
| 	} else { | ||||
| 		i = range->start >> PAGE_CACHE_SHIFT; | ||||
| 	} | ||||
| 	if (!max_to_defrag) | ||||
| 		max_to_defrag = last_index - 1; | ||||
| 
 | ||||
| 	while (i <= last_index && defrag_count < max_to_defrag) { | ||||
| 		/*
 | ||||
| 		 * make sure we stop running if someone unmounts | ||||
| 		 * the FS | ||||
| 		 */ | ||||
| 		if (!(inode->i_sb->s_flags & MS_ACTIVE)) | ||||
| 			break; | ||||
| 
 | ||||
| 		if (!newer_than && | ||||
| 		    !should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT, | ||||
| 					PAGE_CACHE_SIZE, | ||||
| 					range->extent_thresh, | ||||
| 					extent_thresh, | ||||
| 					&last_len, &skip, | ||||
| 					&defrag_end)) { | ||||
| 			unsigned long next; | ||||
| @ -781,92 +1074,39 @@ static int btrfs_defrag_file(struct file *file, | ||||
| 			i = max(i + 1, next); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if (total_read % ra_pages == 0) { | ||||
| 			btrfs_force_ra(inode->i_mapping, &file->f_ra, file, i, | ||||
| 				       min(last_index, i + ra_pages - 1)); | ||||
| 		} | ||||
| 		total_read++; | ||||
| 		mutex_lock(&inode->i_mutex); | ||||
| 		if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) | ||||
| 			BTRFS_I(inode)->force_compress = compress_type; | ||||
| 
 | ||||
| 		ret  = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE); | ||||
| 		if (ret) | ||||
| 			goto err_unlock; | ||||
| again: | ||||
| 		if (inode->i_size == 0 || | ||||
| 		    i > ((inode->i_size - 1) >> PAGE_CACHE_SHIFT)) { | ||||
| 			ret = 0; | ||||
| 			goto err_reservations; | ||||
| 		} | ||||
| 		btrfs_force_ra(inode->i_mapping, ra, file, i, newer_cluster); | ||||
| 
 | ||||
| 		page = grab_cache_page(inode->i_mapping, i); | ||||
| 		if (!page) { | ||||
| 			ret = -ENOMEM; | ||||
| 			goto err_reservations; | ||||
| 		} | ||||
| 		ret = cluster_pages_for_defrag(inode, pages, i, newer_cluster); | ||||
| 		if (ret < 0) | ||||
| 			goto out_ra; | ||||
| 
 | ||||
| 		if (!PageUptodate(page)) { | ||||
| 			btrfs_readpage(NULL, page); | ||||
| 			lock_page(page); | ||||
| 			if (!PageUptodate(page)) { | ||||
| 				unlock_page(page); | ||||
| 				page_cache_release(page); | ||||
| 				ret = -EIO; | ||||
| 				goto err_reservations; | ||||
| 		defrag_count += ret; | ||||
| 		balance_dirty_pages_ratelimited_nr(inode->i_mapping, ret); | ||||
| 		i += ret; | ||||
| 
 | ||||
| 		if (newer_than) { | ||||
| 			if (newer_off == (u64)-1) | ||||
| 				break; | ||||
| 
 | ||||
| 			newer_off = max(newer_off + 1, | ||||
| 					(u64)i << PAGE_CACHE_SHIFT); | ||||
| 
 | ||||
| 			ret = find_new_extents(root, inode, | ||||
| 					       newer_than, &newer_off, | ||||
| 					       64 * 1024); | ||||
| 			if (!ret) { | ||||
| 				range->start = newer_off; | ||||
| 				i = (newer_off & new_align) >> PAGE_CACHE_SHIFT; | ||||
| 				newer_left = newer_cluster; | ||||
| 			} else { | ||||
| 				break; | ||||
| 			} | ||||
| 		} else { | ||||
| 			i++; | ||||
| 		} | ||||
| 
 | ||||
| 		if (page->mapping != inode->i_mapping) { | ||||
| 			unlock_page(page); | ||||
| 			page_cache_release(page); | ||||
| 			goto again; | ||||
| 		} | ||||
| 
 | ||||
| 		wait_on_page_writeback(page); | ||||
| 
 | ||||
| 		if (PageDirty(page)) { | ||||
| 			btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE); | ||||
| 			goto loop_unlock; | ||||
| 		} | ||||
| 
 | ||||
| 		page_start = (u64)page->index << PAGE_CACHE_SHIFT; | ||||
| 		page_end = page_start + PAGE_CACHE_SIZE - 1; | ||||
| 		lock_extent(io_tree, page_start, page_end, GFP_NOFS); | ||||
| 
 | ||||
| 		ordered = btrfs_lookup_ordered_extent(inode, page_start); | ||||
| 		if (ordered) { | ||||
| 			unlock_extent(io_tree, page_start, page_end, GFP_NOFS); | ||||
| 			unlock_page(page); | ||||
| 			page_cache_release(page); | ||||
| 			btrfs_start_ordered_extent(inode, ordered, 1); | ||||
| 			btrfs_put_ordered_extent(ordered); | ||||
| 			goto again; | ||||
| 		} | ||||
| 		set_page_extent_mapped(page); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * this makes sure page_mkwrite is called on the | ||||
| 		 * page if it is dirtied again later | ||||
| 		 */ | ||||
| 		clear_page_dirty_for_io(page); | ||||
| 		clear_extent_bits(&BTRFS_I(inode)->io_tree, page_start, | ||||
| 				  page_end, EXTENT_DIRTY | EXTENT_DELALLOC | | ||||
| 				  EXTENT_DO_ACCOUNTING, GFP_NOFS); | ||||
| 
 | ||||
| 		btrfs_set_extent_delalloc(inode, page_start, page_end, NULL); | ||||
| 		ClearPageChecked(page); | ||||
| 		set_page_dirty(page); | ||||
| 		unlock_extent(io_tree, page_start, page_end, GFP_NOFS); | ||||
| 
 | ||||
| loop_unlock: | ||||
| 		unlock_page(page); | ||||
| 		page_cache_release(page); | ||||
| 		mutex_unlock(&inode->i_mutex); | ||||
| 
 | ||||
| 		balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1); | ||||
| 		i++; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((range->flags & BTRFS_DEFRAG_RANGE_START_IO)) | ||||
| @ -898,12 +1138,14 @@ loop_unlock: | ||||
| 		btrfs_set_super_incompat_flags(disk_super, features); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 	if (!file) | ||||
| 		kfree(ra); | ||||
| 	return defrag_count; | ||||
| 
 | ||||
| err_reservations: | ||||
| 	btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE); | ||||
| err_unlock: | ||||
| 	mutex_unlock(&inode->i_mutex); | ||||
| out_ra: | ||||
| 	if (!file) | ||||
| 		kfree(ra); | ||||
| 	kfree(pages); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| @ -1129,7 +1371,7 @@ static noinline int btrfs_ioctl_subvol_getflags(struct file *file, | ||||
| 	int ret = 0; | ||||
| 	u64 flags = 0; | ||||
| 
 | ||||
| 	if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) | ||||
| 	if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	down_read(&root->fs_info->subvol_sem); | ||||
| @ -1156,7 +1398,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file, | ||||
| 	if (root->fs_info->sb->s_flags & MS_RDONLY) | ||||
| 		return -EROFS; | ||||
| 
 | ||||
| 	if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) | ||||
| 	if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (copy_from_user(&flags, arg, sizeof(flags))) | ||||
| @ -1279,7 +1521,6 @@ static noinline int copy_to_sk(struct btrfs_root *root, | ||||
| 	int nritems; | ||||
| 	int i; | ||||
| 	int slot; | ||||
| 	int found = 0; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	leaf = path->nodes[0]; | ||||
| @ -1326,7 +1567,7 @@ static noinline int copy_to_sk(struct btrfs_root *root, | ||||
| 					   item_off, item_len); | ||||
| 			*sk_offset += item_len; | ||||
| 		} | ||||
| 		found++; | ||||
| 		(*num_found)++; | ||||
| 
 | ||||
| 		if (*num_found >= sk->nr_items) | ||||
| 			break; | ||||
| @ -1345,7 +1586,6 @@ advance_key: | ||||
| 	} else | ||||
| 		ret = 1; | ||||
| overflow: | ||||
| 	*num_found += found; | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| @ -1402,7 +1642,7 @@ static noinline int search_ioctl(struct inode *inode, | ||||
| 		} | ||||
| 		ret = copy_to_sk(root, path, &key, sk, args->buf, | ||||
| 				 &sk_offset, &num_found); | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 		if (ret || num_found >= sk->nr_items) | ||||
| 			break; | ||||
| 
 | ||||
| @ -1509,7 +1749,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info, | ||||
| 		if (key.offset == BTRFS_FIRST_FREE_OBJECTID) | ||||
| 			break; | ||||
| 
 | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 		key.objectid = key.offset; | ||||
| 		key.offset = (u64)-1; | ||||
| 		dirid = key.objectid; | ||||
| @ -1639,7 +1879,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, | ||||
| 			goto out_dput; | ||||
| 	} | ||||
| 
 | ||||
| 	if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) { | ||||
| 	if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) { | ||||
| 		err = -EINVAL; | ||||
| 		goto out_dput; | ||||
| 	} | ||||
| @ -1757,7 +1997,10 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) | ||||
| 			/* the rest are all set to zero by kzalloc */ | ||||
| 			range->len = (u64)-1; | ||||
| 		} | ||||
| 		ret = btrfs_defrag_file(file, range); | ||||
| 		ret = btrfs_defrag_file(fdentry(file)->d_inode, file, | ||||
| 					range, 0, 0); | ||||
| 		if (ret > 0) | ||||
| 			ret = 0; | ||||
| 		kfree(range); | ||||
| 		break; | ||||
| 	default: | ||||
| @ -1809,6 +2052,75 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg) | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static long btrfs_ioctl_fs_info(struct btrfs_root *root, void __user *arg) | ||||
| { | ||||
| 	struct btrfs_ioctl_fs_info_args fi_args; | ||||
| 	struct btrfs_device *device; | ||||
| 	struct btrfs_device *next; | ||||
| 	struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; | ||||
| 
 | ||||
| 	if (!capable(CAP_SYS_ADMIN)) | ||||
| 		return -EPERM; | ||||
| 
 | ||||
| 	fi_args.num_devices = fs_devices->num_devices; | ||||
| 	fi_args.max_id = 0; | ||||
| 	memcpy(&fi_args.fsid, root->fs_info->fsid, sizeof(fi_args.fsid)); | ||||
| 
 | ||||
| 	mutex_lock(&fs_devices->device_list_mutex); | ||||
| 	list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) { | ||||
| 		if (device->devid > fi_args.max_id) | ||||
| 			fi_args.max_id = device->devid; | ||||
| 	} | ||||
| 	mutex_unlock(&fs_devices->device_list_mutex); | ||||
| 
 | ||||
| 	if (copy_to_user(arg, &fi_args, sizeof(fi_args))) | ||||
| 		return -EFAULT; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg) | ||||
| { | ||||
| 	struct btrfs_ioctl_dev_info_args *di_args; | ||||
| 	struct btrfs_device *dev; | ||||
| 	struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; | ||||
| 	int ret = 0; | ||||
| 	char *s_uuid = NULL; | ||||
| 	char empty_uuid[BTRFS_UUID_SIZE] = {0}; | ||||
| 
 | ||||
| 	if (!capable(CAP_SYS_ADMIN)) | ||||
| 		return -EPERM; | ||||
| 
 | ||||
| 	di_args = memdup_user(arg, sizeof(*di_args)); | ||||
| 	if (IS_ERR(di_args)) | ||||
| 		return PTR_ERR(di_args); | ||||
| 
 | ||||
| 	if (memcmp(empty_uuid, di_args->uuid, BTRFS_UUID_SIZE) != 0) | ||||
| 		s_uuid = di_args->uuid; | ||||
| 
 | ||||
| 	mutex_lock(&fs_devices->device_list_mutex); | ||||
| 	dev = btrfs_find_device(root, di_args->devid, s_uuid, NULL); | ||||
| 	mutex_unlock(&fs_devices->device_list_mutex); | ||||
| 
 | ||||
| 	if (!dev) { | ||||
| 		ret = -ENODEV; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	di_args->devid = dev->devid; | ||||
| 	di_args->bytes_used = dev->bytes_used; | ||||
| 	di_args->total_bytes = dev->total_bytes; | ||||
| 	memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid)); | ||||
| 	strncpy(di_args->path, dev->name, sizeof(di_args->path)); | ||||
| 
 | ||||
| out: | ||||
| 	if (ret == 0 && copy_to_user(arg, di_args, sizeof(*di_args))) | ||||
| 		ret = -EFAULT; | ||||
| 
 | ||||
| 	kfree(di_args); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | ||||
| 				       u64 off, u64 olen, u64 destoff) | ||||
| { | ||||
| @ -1925,7 +2237,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | ||||
| 	} | ||||
| 
 | ||||
| 	/* clone data */ | ||||
| 	key.objectid = src->i_ino; | ||||
| 	key.objectid = btrfs_ino(src); | ||||
| 	key.type = BTRFS_EXTENT_DATA_KEY; | ||||
| 	key.offset = 0; | ||||
| 
 | ||||
| @ -1952,7 +2264,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | ||||
| 
 | ||||
| 		btrfs_item_key_to_cpu(leaf, &key, slot); | ||||
| 		if (btrfs_key_type(&key) > BTRFS_EXTENT_DATA_KEY || | ||||
| 		    key.objectid != src->i_ino) | ||||
| 		    key.objectid != btrfs_ino(src)) | ||||
| 			break; | ||||
| 
 | ||||
| 		if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) { | ||||
| @ -1988,14 +2300,14 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | ||||
| 				datal = btrfs_file_extent_ram_bytes(leaf, | ||||
| 								    extent); | ||||
| 			} | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 
 | ||||
| 			if (key.offset + datal <= off || | ||||
| 			    key.offset >= off+len) | ||||
| 				goto next; | ||||
| 
 | ||||
| 			memcpy(&new_key, &key, sizeof(new_key)); | ||||
| 			new_key.objectid = inode->i_ino; | ||||
| 			new_key.objectid = btrfs_ino(inode); | ||||
| 			if (off <= key.offset) | ||||
| 				new_key.offset = key.offset + destoff - off; | ||||
| 			else | ||||
| @ -2049,7 +2361,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | ||||
| 					ret = btrfs_inc_extent_ref(trans, root, | ||||
| 							disko, diskl, 0, | ||||
| 							root->root_key.objectid, | ||||
| 							inode->i_ino, | ||||
| 							btrfs_ino(inode), | ||||
| 							new_key.offset - datao); | ||||
| 					BUG_ON(ret); | ||||
| 				} | ||||
| @ -2098,7 +2410,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | ||||
| 			} | ||||
| 
 | ||||
| 			btrfs_mark_buffer_dirty(leaf); | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 
 | ||||
| 			inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||||
| 
 | ||||
| @ -2119,12 +2431,12 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | ||||
| 			btrfs_end_transaction(trans, root); | ||||
| 		} | ||||
| next: | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 		key.offset++; | ||||
| 	} | ||||
| 	ret = 0; | ||||
| out: | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); | ||||
| out_unlock: | ||||
| 	mutex_unlock(&src->i_mutex); | ||||
| @ -2471,6 +2783,58 @@ static noinline long btrfs_ioctl_wait_sync(struct file *file, void __user *argp) | ||||
| 	return btrfs_wait_for_commit(root, transid); | ||||
| } | ||||
| 
 | ||||
| static long btrfs_ioctl_scrub(struct btrfs_root *root, void __user *arg) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct btrfs_ioctl_scrub_args *sa; | ||||
| 
 | ||||
| 	if (!capable(CAP_SYS_ADMIN)) | ||||
| 		return -EPERM; | ||||
| 
 | ||||
| 	sa = memdup_user(arg, sizeof(*sa)); | ||||
| 	if (IS_ERR(sa)) | ||||
| 		return PTR_ERR(sa); | ||||
| 
 | ||||
| 	ret = btrfs_scrub_dev(root, sa->devid, sa->start, sa->end, | ||||
| 			      &sa->progress, sa->flags & BTRFS_SCRUB_READONLY); | ||||
| 
 | ||||
| 	if (copy_to_user(arg, sa, sizeof(*sa))) | ||||
| 		ret = -EFAULT; | ||||
| 
 | ||||
| 	kfree(sa); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static long btrfs_ioctl_scrub_cancel(struct btrfs_root *root, void __user *arg) | ||||
| { | ||||
| 	if (!capable(CAP_SYS_ADMIN)) | ||||
| 		return -EPERM; | ||||
| 
 | ||||
| 	return btrfs_scrub_cancel(root); | ||||
| } | ||||
| 
 | ||||
| static long btrfs_ioctl_scrub_progress(struct btrfs_root *root, | ||||
| 				       void __user *arg) | ||||
| { | ||||
| 	struct btrfs_ioctl_scrub_args *sa; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!capable(CAP_SYS_ADMIN)) | ||||
| 		return -EPERM; | ||||
| 
 | ||||
| 	sa = memdup_user(arg, sizeof(*sa)); | ||||
| 	if (IS_ERR(sa)) | ||||
| 		return PTR_ERR(sa); | ||||
| 
 | ||||
| 	ret = btrfs_scrub_progress(root, sa->devid, &sa->progress); | ||||
| 
 | ||||
| 	if (copy_to_user(arg, sa, sizeof(*sa))) | ||||
| 		ret = -EFAULT; | ||||
| 
 | ||||
| 	kfree(sa); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| long btrfs_ioctl(struct file *file, unsigned int | ||||
| 		cmd, unsigned long arg) | ||||
| { | ||||
| @ -2510,6 +2874,10 @@ long btrfs_ioctl(struct file *file, unsigned int | ||||
| 		return btrfs_ioctl_add_dev(root, argp); | ||||
| 	case BTRFS_IOC_RM_DEV: | ||||
| 		return btrfs_ioctl_rm_dev(root, argp); | ||||
| 	case BTRFS_IOC_FS_INFO: | ||||
| 		return btrfs_ioctl_fs_info(root, argp); | ||||
| 	case BTRFS_IOC_DEV_INFO: | ||||
| 		return btrfs_ioctl_dev_info(root, argp); | ||||
| 	case BTRFS_IOC_BALANCE: | ||||
| 		return btrfs_balance(root->fs_info->dev_root); | ||||
| 	case BTRFS_IOC_CLONE: | ||||
| @ -2533,6 +2901,12 @@ long btrfs_ioctl(struct file *file, unsigned int | ||||
| 		return btrfs_ioctl_start_sync(file, argp); | ||||
| 	case BTRFS_IOC_WAIT_SYNC: | ||||
| 		return btrfs_ioctl_wait_sync(file, argp); | ||||
| 	case BTRFS_IOC_SCRUB: | ||||
| 		return btrfs_ioctl_scrub(root, argp); | ||||
| 	case BTRFS_IOC_SCRUB_CANCEL: | ||||
| 		return btrfs_ioctl_scrub_cancel(root, argp); | ||||
| 	case BTRFS_IOC_SCRUB_PROGRESS: | ||||
| 		return btrfs_ioctl_scrub_progress(root, argp); | ||||
| 	} | ||||
| 
 | ||||
| 	return -ENOTTY; | ||||
|  | ||||
							
								
								
									
										107
									
								
								fs/btrfs/ioctl.h
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								fs/btrfs/ioctl.h
									
									
									
									
									
								
							| @ -32,6 +32,8 @@ struct btrfs_ioctl_vol_args { | ||||
| 
 | ||||
| #define BTRFS_SUBVOL_CREATE_ASYNC	(1ULL << 0) | ||||
| #define BTRFS_SUBVOL_RDONLY		(1ULL << 1) | ||||
| #define BTRFS_FSID_SIZE 16 | ||||
| #define BTRFS_UUID_SIZE 16 | ||||
| 
 | ||||
| #define BTRFS_SUBVOL_NAME_MAX 4039 | ||||
| struct btrfs_ioctl_vol_args_v2 { | ||||
| @ -42,6 +44,71 @@ struct btrfs_ioctl_vol_args_v2 { | ||||
| 	char name[BTRFS_SUBVOL_NAME_MAX + 1]; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * structure to report errors and progress to userspace, either as a | ||||
|  * result of a finished scrub, a canceled scrub or a progress inquiry | ||||
|  */ | ||||
| struct btrfs_scrub_progress { | ||||
| 	__u64 data_extents_scrubbed;	/* # of data extents scrubbed */ | ||||
| 	__u64 tree_extents_scrubbed;	/* # of tree extents scrubbed */ | ||||
| 	__u64 data_bytes_scrubbed;	/* # of data bytes scrubbed */ | ||||
| 	__u64 tree_bytes_scrubbed;	/* # of tree bytes scrubbed */ | ||||
| 	__u64 read_errors;		/* # of read errors encountered (EIO) */ | ||||
| 	__u64 csum_errors;		/* # of failed csum checks */ | ||||
| 	__u64 verify_errors;		/* # of occurences, where the metadata
 | ||||
| 					 * of a tree block did not match the | ||||
| 					 * expected values, like generation or | ||||
| 					 * logical */ | ||||
| 	__u64 no_csum;			/* # of 4k data block for which no csum
 | ||||
| 					 * is present, probably the result of | ||||
| 					 * data written with nodatasum */ | ||||
| 	__u64 csum_discards;		/* # of csum for which no data was found
 | ||||
| 					 * in the extent tree. */ | ||||
| 	__u64 super_errors;		/* # of bad super blocks encountered */ | ||||
| 	__u64 malloc_errors;		/* # of internal kmalloc errors. These
 | ||||
| 					 * will likely cause an incomplete | ||||
| 					 * scrub */ | ||||
| 	__u64 uncorrectable_errors;	/* # of errors where either no intact
 | ||||
| 					 * copy was found or the writeback | ||||
| 					 * failed */ | ||||
| 	__u64 corrected_errors;		/* # of errors corrected */ | ||||
| 	__u64 last_physical;		/* last physical address scrubbed. In
 | ||||
| 					 * case a scrub was aborted, this can | ||||
| 					 * be used to restart the scrub */ | ||||
| 	__u64 unverified_errors;	/* # of occurences where a read for a
 | ||||
| 					 * full (64k) bio failed, but the re- | ||||
| 					 * check succeeded for each 4k piece. | ||||
| 					 * Intermittent error. */ | ||||
| }; | ||||
| 
 | ||||
| #define BTRFS_SCRUB_READONLY	1 | ||||
| struct btrfs_ioctl_scrub_args { | ||||
| 	__u64 devid;				/* in */ | ||||
| 	__u64 start;				/* in */ | ||||
| 	__u64 end;				/* in */ | ||||
| 	__u64 flags;				/* in */ | ||||
| 	struct btrfs_scrub_progress progress;	/* out */ | ||||
| 	/* pad to 1k */ | ||||
| 	__u64 unused[(1024-32-sizeof(struct btrfs_scrub_progress))/8]; | ||||
| }; | ||||
| 
 | ||||
| #define BTRFS_DEVICE_PATH_NAME_MAX 1024 | ||||
| struct btrfs_ioctl_dev_info_args { | ||||
| 	__u64 devid;				/* in/out */ | ||||
| 	__u8 uuid[BTRFS_UUID_SIZE];		/* in/out */ | ||||
| 	__u64 bytes_used;			/* out */ | ||||
| 	__u64 total_bytes;			/* out */ | ||||
| 	__u64 unused[379];			/* pad to 4k */ | ||||
| 	__u8 path[BTRFS_DEVICE_PATH_NAME_MAX];	/* out */ | ||||
| }; | ||||
| 
 | ||||
| struct btrfs_ioctl_fs_info_args { | ||||
| 	__u64 max_id;				/* out */ | ||||
| 	__u64 num_devices;			/* out */ | ||||
| 	__u8 fsid[BTRFS_FSID_SIZE];		/* out */ | ||||
| 	__u64 reserved[124];			/* pad to 1k */ | ||||
| }; | ||||
| 
 | ||||
| #define BTRFS_INO_LOOKUP_PATH_MAX 4080 | ||||
| struct btrfs_ioctl_ino_lookup_args { | ||||
| 	__u64 treeid; | ||||
| @ -114,37 +181,6 @@ struct btrfs_ioctl_clone_range_args { | ||||
| #define BTRFS_DEFRAG_RANGE_COMPRESS 1 | ||||
| #define BTRFS_DEFRAG_RANGE_START_IO 2 | ||||
| 
 | ||||
| struct btrfs_ioctl_defrag_range_args { | ||||
| 	/* start of the defrag operation */ | ||||
| 	__u64 start; | ||||
| 
 | ||||
| 	/* number of bytes to defrag, use (u64)-1 to say all */ | ||||
| 	__u64 len; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * flags for the operation, which can include turning | ||||
| 	 * on compression for this one defrag | ||||
| 	 */ | ||||
| 	__u64 flags; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * any extent bigger than this will be considered | ||||
| 	 * already defragged.  Use 0 to take the kernel default | ||||
| 	 * Use 1 to say every single extent must be rewritten | ||||
| 	 */ | ||||
| 	__u32 extent_thresh; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * which compression method to use if turning on compression | ||||
| 	 * for this defrag operation.  If unspecified, zlib will | ||||
| 	 * be used | ||||
| 	 */ | ||||
| 	__u32 compress_type; | ||||
| 
 | ||||
| 	/* spare for later */ | ||||
| 	__u32 unused[4]; | ||||
| }; | ||||
| 
 | ||||
| struct btrfs_ioctl_space_info { | ||||
| 	__u64 flags; | ||||
| 	__u64 total_bytes; | ||||
| @ -203,4 +239,13 @@ struct btrfs_ioctl_space_args { | ||||
| 				   struct btrfs_ioctl_vol_args_v2) | ||||
| #define BTRFS_IOC_SUBVOL_GETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 25, __u64) | ||||
| #define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64) | ||||
| #define BTRFS_IOC_SCRUB _IOWR(BTRFS_IOCTL_MAGIC, 27, \ | ||||
| 			      struct btrfs_ioctl_scrub_args) | ||||
| #define BTRFS_IOC_SCRUB_CANCEL _IO(BTRFS_IOCTL_MAGIC, 28) | ||||
| #define BTRFS_IOC_SCRUB_PROGRESS _IOWR(BTRFS_IOCTL_MAGIC, 29, \ | ||||
| 				       struct btrfs_ioctl_scrub_args) | ||||
| #define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \ | ||||
| 				 struct btrfs_ioctl_dev_info_args) | ||||
| #define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \ | ||||
| 			       struct btrfs_ioctl_fs_info_args) | ||||
| #endif | ||||
|  | ||||
| @ -185,31 +185,6 @@ sleep: | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Very quick trylock, this does not spin or schedule.  It returns | ||||
|  * 1 with the spinlock held if it was able to take the lock, or it | ||||
|  * returns zero if it was unable to take the lock. | ||||
|  * | ||||
|  * After this call, scheduling is not safe without first calling | ||||
|  * btrfs_set_lock_blocking() | ||||
|  */ | ||||
| int btrfs_try_tree_lock(struct extent_buffer *eb) | ||||
| { | ||||
| 	if (spin_trylock(&eb->lock)) { | ||||
| 		if (test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags)) { | ||||
| 			/*
 | ||||
| 			 * we've got the spinlock, but the real owner is | ||||
| 			 * blocking.  Drop the spinlock and return failure | ||||
| 			 */ | ||||
| 			spin_unlock(&eb->lock); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		return 1; | ||||
| 	} | ||||
| 	/* someone else has the spinlock giveup */ | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int btrfs_tree_unlock(struct extent_buffer *eb) | ||||
| { | ||||
| 	/*
 | ||||
|  | ||||
| @ -21,8 +21,6 @@ | ||||
| 
 | ||||
| int btrfs_tree_lock(struct extent_buffer *eb); | ||||
| int btrfs_tree_unlock(struct extent_buffer *eb); | ||||
| 
 | ||||
| int btrfs_try_tree_lock(struct extent_buffer *eb); | ||||
| int btrfs_try_spin_lock(struct extent_buffer *eb); | ||||
| 
 | ||||
| void btrfs_set_lock_blocking(struct extent_buffer *eb); | ||||
|  | ||||
| @ -23,56 +23,6 @@ | ||||
| #include "ref-cache.h" | ||||
| #include "transaction.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * leaf refs are used to cache the information about which extents | ||||
|  * a given leaf has references on.  This allows us to process that leaf | ||||
|  * in btrfs_drop_snapshot without needing to read it back from disk. | ||||
|  */ | ||||
| 
 | ||||
| /*
 | ||||
|  * kmalloc a leaf reference struct and update the counters for the | ||||
|  * total ref cache size | ||||
|  */ | ||||
| struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(struct btrfs_root *root, | ||||
| 					    int nr_extents) | ||||
| { | ||||
| 	struct btrfs_leaf_ref *ref; | ||||
| 	size_t size = btrfs_leaf_ref_size(nr_extents); | ||||
| 
 | ||||
| 	ref = kmalloc(size, GFP_NOFS); | ||||
| 	if (ref) { | ||||
| 		spin_lock(&root->fs_info->ref_cache_lock); | ||||
| 		root->fs_info->total_ref_cache_size += size; | ||||
| 		spin_unlock(&root->fs_info->ref_cache_lock); | ||||
| 
 | ||||
| 		memset(ref, 0, sizeof(*ref)); | ||||
| 		atomic_set(&ref->usage, 1); | ||||
| 		INIT_LIST_HEAD(&ref->list); | ||||
| 	} | ||||
| 	return ref; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * free a leaf reference struct and update the counters for the | ||||
|  * total ref cache size | ||||
|  */ | ||||
| void btrfs_free_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref) | ||||
| { | ||||
| 	if (!ref) | ||||
| 		return; | ||||
| 	WARN_ON(atomic_read(&ref->usage) == 0); | ||||
| 	if (atomic_dec_and_test(&ref->usage)) { | ||||
| 		size_t size = btrfs_leaf_ref_size(ref->nritems); | ||||
| 
 | ||||
| 		BUG_ON(ref->in_tree); | ||||
| 		kfree(ref); | ||||
| 
 | ||||
| 		spin_lock(&root->fs_info->ref_cache_lock); | ||||
| 		root->fs_info->total_ref_cache_size -= size; | ||||
| 		spin_unlock(&root->fs_info->ref_cache_lock); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static struct rb_node *tree_insert(struct rb_root *root, u64 bytenr, | ||||
| 				   struct rb_node *node) | ||||
| { | ||||
| @ -116,117 +66,3 @@ static struct rb_node *tree_search(struct rb_root *root, u64 bytenr) | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen, | ||||
| 			   int shared) | ||||
| { | ||||
| 	struct btrfs_leaf_ref *ref = NULL; | ||||
| 	struct btrfs_leaf_ref_tree *tree = root->ref_tree; | ||||
| 
 | ||||
| 	if (shared) | ||||
| 		tree = &root->fs_info->shared_ref_tree; | ||||
| 	if (!tree) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	spin_lock(&tree->lock); | ||||
| 	while (!list_empty(&tree->list)) { | ||||
| 		ref = list_entry(tree->list.next, struct btrfs_leaf_ref, list); | ||||
| 		BUG_ON(ref->tree != tree); | ||||
| 		if (ref->root_gen > max_root_gen) | ||||
| 			break; | ||||
| 		if (!xchg(&ref->in_tree, 0)) { | ||||
| 			cond_resched_lock(&tree->lock); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		rb_erase(&ref->rb_node, &tree->root); | ||||
| 		list_del_init(&ref->list); | ||||
| 
 | ||||
| 		spin_unlock(&tree->lock); | ||||
| 		btrfs_free_leaf_ref(root, ref); | ||||
| 		cond_resched(); | ||||
| 		spin_lock(&tree->lock); | ||||
| 	} | ||||
| 	spin_unlock(&tree->lock); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * find the leaf ref for a given extent.  This returns the ref struct with | ||||
|  * a usage reference incremented | ||||
|  */ | ||||
| struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, | ||||
| 					     u64 bytenr) | ||||
| { | ||||
| 	struct rb_node *rb; | ||||
| 	struct btrfs_leaf_ref *ref = NULL; | ||||
| 	struct btrfs_leaf_ref_tree *tree = root->ref_tree; | ||||
| again: | ||||
| 	if (tree) { | ||||
| 		spin_lock(&tree->lock); | ||||
| 		rb = tree_search(&tree->root, bytenr); | ||||
| 		if (rb) | ||||
| 			ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node); | ||||
| 		if (ref) | ||||
| 			atomic_inc(&ref->usage); | ||||
| 		spin_unlock(&tree->lock); | ||||
| 		if (ref) | ||||
| 			return ref; | ||||
| 	} | ||||
| 	if (tree != &root->fs_info->shared_ref_tree) { | ||||
| 		tree = &root->fs_info->shared_ref_tree; | ||||
| 		goto again; | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * add a fully filled in leaf ref struct | ||||
|  * remove all the refs older than a given root generation | ||||
|  */ | ||||
| int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref, | ||||
| 		       int shared) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	struct rb_node *rb; | ||||
| 	struct btrfs_leaf_ref_tree *tree = root->ref_tree; | ||||
| 
 | ||||
| 	if (shared) | ||||
| 		tree = &root->fs_info->shared_ref_tree; | ||||
| 
 | ||||
| 	spin_lock(&tree->lock); | ||||
| 	rb = tree_insert(&tree->root, ref->bytenr, &ref->rb_node); | ||||
| 	if (rb) { | ||||
| 		ret = -EEXIST; | ||||
| 	} else { | ||||
| 		atomic_inc(&ref->usage); | ||||
| 		ref->tree = tree; | ||||
| 		ref->in_tree = 1; | ||||
| 		list_add_tail(&ref->list, &tree->list); | ||||
| 	} | ||||
| 	spin_unlock(&tree->lock); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * remove a single leaf ref from the tree.  This drops the ref held by the tree | ||||
|  * only | ||||
|  */ | ||||
| int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref) | ||||
| { | ||||
| 	struct btrfs_leaf_ref_tree *tree; | ||||
| 
 | ||||
| 	if (!xchg(&ref->in_tree, 0)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	tree = ref->tree; | ||||
| 	spin_lock(&tree->lock); | ||||
| 
 | ||||
| 	rb_erase(&ref->rb_node, &tree->root); | ||||
| 	list_del_init(&ref->list); | ||||
| 
 | ||||
| 	spin_unlock(&tree->lock); | ||||
| 
 | ||||
| 	btrfs_free_leaf_ref(root, ref); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @ -49,28 +49,4 @@ static inline size_t btrfs_leaf_ref_size(int nr_extents) | ||||
| 	return sizeof(struct btrfs_leaf_ref) + | ||||
| 	       sizeof(struct btrfs_extent_info) * nr_extents; | ||||
| } | ||||
| 
 | ||||
| static inline void btrfs_leaf_ref_tree_init(struct btrfs_leaf_ref_tree *tree) | ||||
| { | ||||
| 	tree->root = RB_ROOT; | ||||
| 	INIT_LIST_HEAD(&tree->list); | ||||
| 	spin_lock_init(&tree->lock); | ||||
| } | ||||
| 
 | ||||
| static inline int btrfs_leaf_ref_tree_empty(struct btrfs_leaf_ref_tree *tree) | ||||
| { | ||||
| 	return RB_EMPTY_ROOT(&tree->root); | ||||
| } | ||||
| 
 | ||||
| void btrfs_leaf_ref_tree_init(struct btrfs_leaf_ref_tree *tree); | ||||
| struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(struct btrfs_root *root, | ||||
| 					    int nr_extents); | ||||
| void btrfs_free_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); | ||||
| struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, | ||||
| 					     u64 bytenr); | ||||
| int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref, | ||||
| 		       int shared); | ||||
| int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen, | ||||
| 			   int shared); | ||||
| int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); | ||||
| #endif | ||||
|  | ||||
| @ -30,6 +30,7 @@ | ||||
| #include "btrfs_inode.h" | ||||
| #include "async-thread.h" | ||||
| #include "free-space-cache.h" | ||||
| #include "inode-map.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * backref_node, mapping_node and tree_block start with this | ||||
| @ -507,6 +508,7 @@ static int update_backref_cache(struct btrfs_trans_handle *trans, | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static int should_ignore_root(struct btrfs_root *root) | ||||
| { | ||||
| 	struct btrfs_root *reloc_root; | ||||
| @ -529,7 +531,6 @@ static int should_ignore_root(struct btrfs_root *root) | ||||
| 	 */ | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * find reloc tree by address of tree root | ||||
|  */ | ||||
| @ -961,7 +962,7 @@ again: | ||||
| 			lower = upper; | ||||
| 			upper = NULL; | ||||
| 		} | ||||
| 		btrfs_release_path(root, path2); | ||||
| 		btrfs_release_path(path2); | ||||
| next: | ||||
| 		if (ptr < end) { | ||||
| 			ptr += btrfs_extent_inline_ref_size(key.type); | ||||
| @ -974,7 +975,7 @@ next: | ||||
| 		if (ptr >= end) | ||||
| 			path1->slots[0]++; | ||||
| 	} | ||||
| 	btrfs_release_path(rc->extent_root, path1); | ||||
| 	btrfs_release_path(path1); | ||||
| 
 | ||||
| 	cur->checked = 1; | ||||
| 	WARN_ON(exist); | ||||
| @ -1409,9 +1410,9 @@ again: | ||||
| 		prev = node; | ||||
| 		entry = rb_entry(node, struct btrfs_inode, rb_node); | ||||
| 
 | ||||
| 		if (objectid < entry->vfs_inode.i_ino) | ||||
| 		if (objectid < btrfs_ino(&entry->vfs_inode)) | ||||
| 			node = node->rb_left; | ||||
| 		else if (objectid > entry->vfs_inode.i_ino) | ||||
| 		else if (objectid > btrfs_ino(&entry->vfs_inode)) | ||||
| 			node = node->rb_right; | ||||
| 		else | ||||
| 			break; | ||||
| @ -1419,7 +1420,7 @@ again: | ||||
| 	if (!node) { | ||||
| 		while (prev) { | ||||
| 			entry = rb_entry(prev, struct btrfs_inode, rb_node); | ||||
| 			if (objectid <= entry->vfs_inode.i_ino) { | ||||
| 			if (objectid <= btrfs_ino(&entry->vfs_inode)) { | ||||
| 				node = prev; | ||||
| 				break; | ||||
| 			} | ||||
| @ -1434,7 +1435,7 @@ again: | ||||
| 			return inode; | ||||
| 		} | ||||
| 
 | ||||
| 		objectid = entry->vfs_inode.i_ino + 1; | ||||
| 		objectid = btrfs_ino(&entry->vfs_inode) + 1; | ||||
| 		if (cond_resched_lock(&root->inode_lock)) | ||||
| 			goto again; | ||||
| 
 | ||||
| @ -1470,7 +1471,7 @@ static int get_new_location(struct inode *reloc_inode, u64 *new_bytenr, | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	bytenr -= BTRFS_I(reloc_inode)->index_cnt; | ||||
| 	ret = btrfs_lookup_file_extent(NULL, root, path, reloc_inode->i_ino, | ||||
| 	ret = btrfs_lookup_file_extent(NULL, root, path, btrfs_ino(reloc_inode), | ||||
| 				       bytenr, 0); | ||||
| 	if (ret < 0) | ||||
| 		goto out; | ||||
| @ -1558,11 +1559,11 @@ int replace_file_extents(struct btrfs_trans_handle *trans, | ||||
| 			if (first) { | ||||
| 				inode = find_next_inode(root, key.objectid); | ||||
| 				first = 0; | ||||
| 			} else if (inode && inode->i_ino < key.objectid) { | ||||
| 			} else if (inode && btrfs_ino(inode) < key.objectid) { | ||||
| 				btrfs_add_delayed_iput(inode); | ||||
| 				inode = find_next_inode(root, key.objectid); | ||||
| 			} | ||||
| 			if (inode && inode->i_ino == key.objectid) { | ||||
| 			if (inode && btrfs_ino(inode) == key.objectid) { | ||||
| 				end = key.offset + | ||||
| 				      btrfs_file_extent_num_bytes(leaf, fi); | ||||
| 				WARN_ON(!IS_ALIGNED(key.offset, | ||||
| @ -1749,7 +1750,7 @@ again: | ||||
| 
 | ||||
| 		btrfs_node_key_to_cpu(path->nodes[level], &key, | ||||
| 				      path->slots[level]); | ||||
| 		btrfs_release_path(src, path); | ||||
| 		btrfs_release_path(path); | ||||
| 
 | ||||
| 		path->lowest_level = level; | ||||
| 		ret = btrfs_search_slot(trans, src, &key, path, 0, 1); | ||||
| @ -1893,6 +1894,7 @@ static int invalidate_extent_cache(struct btrfs_root *root, | ||||
| 	struct inode *inode = NULL; | ||||
| 	u64 objectid; | ||||
| 	u64 start, end; | ||||
| 	u64 ino; | ||||
| 
 | ||||
| 	objectid = min_key->objectid; | ||||
| 	while (1) { | ||||
| @ -1905,17 +1907,18 @@ static int invalidate_extent_cache(struct btrfs_root *root, | ||||
| 		inode = find_next_inode(root, objectid); | ||||
| 		if (!inode) | ||||
| 			break; | ||||
| 		ino = btrfs_ino(inode); | ||||
| 
 | ||||
| 		if (inode->i_ino > max_key->objectid) { | ||||
| 		if (ino > max_key->objectid) { | ||||
| 			iput(inode); | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		objectid = inode->i_ino + 1; | ||||
| 		objectid = ino + 1; | ||||
| 		if (!S_ISREG(inode->i_mode)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (unlikely(min_key->objectid == inode->i_ino)) { | ||||
| 		if (unlikely(min_key->objectid == ino)) { | ||||
| 			if (min_key->type > BTRFS_EXTENT_DATA_KEY) | ||||
| 				continue; | ||||
| 			if (min_key->type < BTRFS_EXTENT_DATA_KEY) | ||||
| @ -1928,7 +1931,7 @@ static int invalidate_extent_cache(struct btrfs_root *root, | ||||
| 			start = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		if (unlikely(max_key->objectid == inode->i_ino)) { | ||||
| 		if (unlikely(max_key->objectid == ino)) { | ||||
| 			if (max_key->type < BTRFS_EXTENT_DATA_KEY) | ||||
| 				continue; | ||||
| 			if (max_key->type > BTRFS_EXTENT_DATA_KEY) { | ||||
| @ -2496,7 +2499,7 @@ static int do_relocation(struct btrfs_trans_handle *trans, | ||||
| 			path->locks[upper->level] = 0; | ||||
| 
 | ||||
| 			slot = path->slots[upper->level]; | ||||
| 			btrfs_release_path(NULL, path); | ||||
| 			btrfs_release_path(path); | ||||
| 		} else { | ||||
| 			ret = btrfs_bin_search(upper->eb, key, upper->level, | ||||
| 					       &slot); | ||||
| @ -2737,7 +2740,7 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans, | ||||
| 		} else { | ||||
| 			path->lowest_level = node->level; | ||||
| 			ret = btrfs_search_slot(trans, root, key, path, 0, 1); | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			if (ret > 0) | ||||
| 				ret = 0; | ||||
| 		} | ||||
| @ -2870,7 +2873,7 @@ int setup_extent_mapping(struct inode *inode, u64 start, u64 end, | ||||
| 	struct extent_map *em; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	em = alloc_extent_map(GFP_NOFS); | ||||
| 	em = alloc_extent_map(); | ||||
| 	if (!em) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| @ -3119,7 +3122,7 @@ static int add_tree_block(struct reloc_control *rc, | ||||
| #endif | ||||
| 	} | ||||
| 
 | ||||
| 	btrfs_release_path(rc->extent_root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 
 | ||||
| 	BUG_ON(level == -1); | ||||
| 
 | ||||
| @ -3220,7 +3223,7 @@ static int delete_block_group_cache(struct btrfs_fs_info *fs_info, | ||||
| 	key.offset = 0; | ||||
| 
 | ||||
| 	inode = btrfs_iget(fs_info->sb, &key, root, NULL); | ||||
| 	if (!inode || IS_ERR(inode) || is_bad_inode(inode)) { | ||||
| 	if (IS_ERR_OR_NULL(inode) || is_bad_inode(inode)) { | ||||
| 		if (inode && !IS_ERR(inode)) | ||||
| 			iput(inode); | ||||
| 		return -ENOENT; | ||||
| @ -3505,7 +3508,7 @@ int add_data_references(struct reloc_control *rc, | ||||
| 		} | ||||
| 		path->slots[0]++; | ||||
| 	} | ||||
| 	btrfs_release_path(rc->extent_root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	if (err) | ||||
| 		free_block_list(blocks); | ||||
| 	return err; | ||||
| @ -3568,7 +3571,7 @@ next: | ||||
| 					    EXTENT_DIRTY); | ||||
| 
 | ||||
| 		if (ret == 0 && start <= key.objectid) { | ||||
| 			btrfs_release_path(rc->extent_root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			rc->search_start = end + 1; | ||||
| 		} else { | ||||
| 			rc->search_start = key.objectid + key.offset; | ||||
| @ -3576,7 +3579,7 @@ next: | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 	btrfs_release_path(rc->extent_root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| @ -3713,7 +3716,7 @@ restart: | ||||
| 				flags = BTRFS_EXTENT_FLAG_DATA; | ||||
| 
 | ||||
| 			if (path_change) { | ||||
| 				btrfs_release_path(rc->extent_root, path); | ||||
| 				btrfs_release_path(path); | ||||
| 
 | ||||
| 				path->search_commit_root = 1; | ||||
| 				path->skip_locking = 1; | ||||
| @ -3736,7 +3739,7 @@ restart: | ||||
| 			   (flags & BTRFS_EXTENT_FLAG_DATA)) { | ||||
| 			ret = add_data_references(rc, &key, path, &blocks); | ||||
| 		} else { | ||||
| 			btrfs_release_path(rc->extent_root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			ret = 0; | ||||
| 		} | ||||
| 		if (ret < 0) { | ||||
| @ -3799,7 +3802,7 @@ restart: | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	btrfs_release_path(rc->extent_root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	clear_extent_bits(&rc->processed_blocks, 0, (u64)-1, EXTENT_DIRTY, | ||||
| 			  GFP_NOFS); | ||||
| 
 | ||||
| @ -3867,7 +3870,7 @@ static int __insert_orphan_inode(struct btrfs_trans_handle *trans, | ||||
| 	btrfs_set_inode_flags(leaf, item, BTRFS_INODE_NOCOMPRESS | | ||||
| 					  BTRFS_INODE_PREALLOC); | ||||
| 	btrfs_mark_buffer_dirty(leaf); | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| out: | ||||
| 	btrfs_free_path(path); | ||||
| 	return ret; | ||||
| @ -3897,7 +3900,7 @@ struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info, | ||||
| 	if (IS_ERR(trans)) | ||||
| 		return ERR_CAST(trans); | ||||
| 
 | ||||
| 	err = btrfs_find_free_objectid(trans, root, objectid, &objectid); | ||||
| 	err = btrfs_find_free_objectid(root, &objectid); | ||||
| 	if (err) | ||||
| 		goto out; | ||||
| 
 | ||||
| @ -3935,7 +3938,7 @@ static struct reloc_control *alloc_reloc_control(void) | ||||
| 	INIT_LIST_HEAD(&rc->reloc_roots); | ||||
| 	backref_cache_init(&rc->backref_cache); | ||||
| 	mapping_tree_init(&rc->reloc_root_tree); | ||||
| 	extent_io_tree_init(&rc->processed_blocks, NULL, GFP_NOFS); | ||||
| 	extent_io_tree_init(&rc->processed_blocks, NULL); | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| @ -4109,7 +4112,7 @@ int btrfs_recover_relocation(struct btrfs_root *root) | ||||
| 		} | ||||
| 		leaf = path->nodes[0]; | ||||
| 		btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); | ||||
| 		btrfs_release_path(root->fs_info->tree_root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 
 | ||||
| 		if (key.objectid != BTRFS_TREE_RELOC_OBJECTID || | ||||
| 		    key.type != BTRFS_ROOT_ITEM_KEY) | ||||
| @ -4141,7 +4144,7 @@ int btrfs_recover_relocation(struct btrfs_root *root) | ||||
| 
 | ||||
| 		key.offset--; | ||||
| 	} | ||||
| 	btrfs_release_path(root->fs_info->tree_root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 
 | ||||
| 	if (list_empty(&reloc_roots)) | ||||
| 		goto out; | ||||
| @ -4242,7 +4245,7 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len) | ||||
| 
 | ||||
| 	disk_bytenr = file_pos + BTRFS_I(inode)->index_cnt; | ||||
| 	ret = btrfs_lookup_csums_range(root->fs_info->csum_root, disk_bytenr, | ||||
| 				       disk_bytenr + len - 1, &list); | ||||
| 				       disk_bytenr + len - 1, &list, 0); | ||||
| 
 | ||||
| 	while (!list_empty(&list)) { | ||||
| 		sums = list_entry(list.next, struct btrfs_ordered_sum, list); | ||||
|  | ||||
| @ -21,53 +21,6 @@ | ||||
| #include "disk-io.h" | ||||
| #include "print-tree.h" | ||||
| 
 | ||||
| /*
 | ||||
|  *  search forward for a root, starting with objectid 'search_start' | ||||
|  *  if a root key is found, the objectid we find is filled into 'found_objectid' | ||||
|  *  and 0 is returned.  < 0 is returned on error, 1 if there is nothing | ||||
|  *  left in the tree. | ||||
|  */ | ||||
| int btrfs_search_root(struct btrfs_root *root, u64 search_start, | ||||
| 		      u64 *found_objectid) | ||||
| { | ||||
| 	struct btrfs_path *path; | ||||
| 	struct btrfs_key search_key; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	root = root->fs_info->tree_root; | ||||
| 	search_key.objectid = search_start; | ||||
| 	search_key.type = (u8)-1; | ||||
| 	search_key.offset = (u64)-1; | ||||
| 
 | ||||
| 	path = btrfs_alloc_path(); | ||||
| 	BUG_ON(!path); | ||||
| again: | ||||
| 	ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); | ||||
| 	if (ret < 0) | ||||
| 		goto out; | ||||
| 	if (ret == 0) { | ||||
| 		ret = 1; | ||||
| 		goto out; | ||||
| 	} | ||||
| 	if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { | ||||
| 		ret = btrfs_next_leaf(root, path); | ||||
| 		if (ret) | ||||
| 			goto out; | ||||
| 	} | ||||
| 	btrfs_item_key_to_cpu(path->nodes[0], &search_key, path->slots[0]); | ||||
| 	if (search_key.type != BTRFS_ROOT_ITEM_KEY) { | ||||
| 		search_key.offset++; | ||||
| 		btrfs_release_path(root, path); | ||||
| 		goto again; | ||||
| 	} | ||||
| 	ret = 0; | ||||
| 	*found_objectid = search_key.objectid; | ||||
| 
 | ||||
| out: | ||||
| 	btrfs_free_path(path); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * lookup the root with the highest offset for a given objectid.  The key we do | ||||
|  * find is copied into 'key'.  If we find something return 0, otherwise 1, < 0 | ||||
| @ -230,7 +183,7 @@ again: | ||||
| 
 | ||||
| 		memcpy(&found_key, &key, sizeof(key)); | ||||
| 		key.offset++; | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 		dead_root = | ||||
| 			btrfs_read_fs_root_no_radix(root->fs_info->tree_root, | ||||
| 						    &found_key); | ||||
| @ -292,7 +245,7 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root) | ||||
| 		} | ||||
| 
 | ||||
| 		btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); | ||||
| 		btrfs_release_path(tree_root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 
 | ||||
| 		if (key.objectid != BTRFS_ORPHAN_OBJECTID || | ||||
| 		    key.type != BTRFS_ORPHAN_ITEM_KEY) | ||||
| @ -385,18 +338,22 @@ again: | ||||
| 		*sequence = btrfs_root_ref_sequence(leaf, ref); | ||||
| 
 | ||||
| 		ret = btrfs_del_item(trans, tree_root, path); | ||||
| 		BUG_ON(ret); | ||||
| 		if (ret) { | ||||
| 			err = ret; | ||||
| 			goto out; | ||||
| 		} | ||||
| 	} else | ||||
| 		err = -ENOENT; | ||||
| 
 | ||||
| 	if (key.type == BTRFS_ROOT_BACKREF_KEY) { | ||||
| 		btrfs_release_path(tree_root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 		key.objectid = ref_id; | ||||
| 		key.type = BTRFS_ROOT_REF_KEY; | ||||
| 		key.offset = root_id; | ||||
| 		goto again; | ||||
| 	} | ||||
| 
 | ||||
| out: | ||||
| 	btrfs_free_path(path); | ||||
| 	return err; | ||||
| } | ||||
| @ -463,7 +420,7 @@ again: | ||||
| 	btrfs_mark_buffer_dirty(leaf); | ||||
| 
 | ||||
| 	if (key.type == BTRFS_ROOT_BACKREF_KEY) { | ||||
| 		btrfs_release_path(tree_root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 		key.objectid = ref_id; | ||||
| 		key.type = BTRFS_ROOT_REF_KEY; | ||||
| 		key.offset = root_id; | ||||
|  | ||||
							
								
								
									
										1369
									
								
								fs/btrfs/scrub.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1369
									
								
								fs/btrfs/scrub.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -41,6 +41,7 @@ | ||||
| #include <linux/slab.h> | ||||
| #include <linux/cleancache.h> | ||||
| #include "compat.h" | ||||
| #include "delayed-inode.h" | ||||
| #include "ctree.h" | ||||
| #include "disk-io.h" | ||||
| #include "transaction.h" | ||||
| @ -160,7 +161,7 @@ enum { | ||||
| 	Opt_compress_type, Opt_compress_force, Opt_compress_force_type, | ||||
| 	Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard, | ||||
| 	Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed, | ||||
| 	Opt_enospc_debug, Opt_subvolrootid, Opt_err, | ||||
| 	Opt_enospc_debug, Opt_subvolrootid, Opt_defrag, Opt_err, | ||||
| }; | ||||
| 
 | ||||
| static match_table_t tokens = { | ||||
| @ -191,6 +192,7 @@ static match_table_t tokens = { | ||||
| 	{Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"}, | ||||
| 	{Opt_enospc_debug, "enospc_debug"}, | ||||
| 	{Opt_subvolrootid, "subvolrootid=%d"}, | ||||
| 	{Opt_defrag, "autodefrag"}, | ||||
| 	{Opt_err, NULL}, | ||||
| }; | ||||
| 
 | ||||
| @ -369,6 +371,10 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) | ||||
| 		case Opt_enospc_debug: | ||||
| 			btrfs_set_opt(info->mount_opt, ENOSPC_DEBUG); | ||||
| 			break; | ||||
| 		case Opt_defrag: | ||||
| 			printk(KERN_INFO "btrfs: enabling auto defrag"); | ||||
| 			btrfs_set_opt(info->mount_opt, AUTO_DEFRAG); | ||||
| 			break; | ||||
| 		case Opt_err: | ||||
| 			printk(KERN_INFO "btrfs: unrecognized mount option " | ||||
| 			       "'%s'\n", p); | ||||
| @ -507,8 +513,10 @@ static struct dentry *get_default_root(struct super_block *sb, | ||||
| 	 */ | ||||
| 	dir_id = btrfs_super_root_dir(&root->fs_info->super_copy); | ||||
| 	di = btrfs_lookup_dir_item(NULL, root, path, dir_id, "default", 7, 0); | ||||
| 	if (IS_ERR(di)) | ||||
| 	if (IS_ERR(di)) { | ||||
| 		btrfs_free_path(path); | ||||
| 		return ERR_CAST(di); | ||||
| 	} | ||||
| 	if (!di) { | ||||
| 		/*
 | ||||
| 		 * Ok the default dir item isn't there.  This is weird since | ||||
| @ -741,7 +749,7 @@ static int btrfs_set_super(struct super_block *s, void *data) | ||||
|  *	  for multiple device setup.  Make sure to keep it in sync. | ||||
|  */ | ||||
| static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, | ||||
| 		const char *dev_name, void *data) | ||||
| 		const char *device_name, void *data) | ||||
| { | ||||
| 	struct block_device *bdev = NULL; | ||||
| 	struct super_block *s; | ||||
| @ -764,7 +772,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, | ||||
| 	if (error) | ||||
| 		return ERR_PTR(error); | ||||
| 
 | ||||
| 	error = btrfs_scan_one_device(dev_name, mode, fs_type, &fs_devices); | ||||
| 	error = btrfs_scan_one_device(device_name, mode, fs_type, &fs_devices); | ||||
| 	if (error) | ||||
| 		goto error_free_subvol_name; | ||||
| 
 | ||||
| @ -915,6 +923,32 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* Used to sort the devices by max_avail(descending sort) */ | ||||
| static int btrfs_cmp_device_free_bytes(const void *dev_info1, | ||||
| 				       const void *dev_info2) | ||||
| { | ||||
| 	if (((struct btrfs_device_info *)dev_info1)->max_avail > | ||||
| 	    ((struct btrfs_device_info *)dev_info2)->max_avail) | ||||
| 		return -1; | ||||
| 	else if (((struct btrfs_device_info *)dev_info1)->max_avail < | ||||
| 		 ((struct btrfs_device_info *)dev_info2)->max_avail) | ||||
| 		return 1; | ||||
| 	else | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * sort the devices by max_avail, in which max free extent size of each device | ||||
|  * is stored.(Descending Sort) | ||||
|  */ | ||||
| static inline void btrfs_descending_sort_devices( | ||||
| 					struct btrfs_device_info *devices, | ||||
| 					size_t nr_devices) | ||||
| { | ||||
| 	sort(devices, nr_devices, sizeof(struct btrfs_device_info), | ||||
| 	     btrfs_cmp_device_free_bytes, NULL); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * The helper to calc the free space on the devices that can be used to store | ||||
|  * file data. | ||||
| @ -1208,10 +1242,14 @@ static int __init init_btrfs_fs(void) | ||||
| 	if (err) | ||||
| 		goto free_extent_io; | ||||
| 
 | ||||
| 	err = btrfs_interface_init(); | ||||
| 	err = btrfs_delayed_inode_init(); | ||||
| 	if (err) | ||||
| 		goto free_extent_map; | ||||
| 
 | ||||
| 	err = btrfs_interface_init(); | ||||
| 	if (err) | ||||
| 		goto free_delayed_inode; | ||||
| 
 | ||||
| 	err = register_filesystem(&btrfs_fs_type); | ||||
| 	if (err) | ||||
| 		goto unregister_ioctl; | ||||
| @ -1221,6 +1259,8 @@ static int __init init_btrfs_fs(void) | ||||
| 
 | ||||
| unregister_ioctl: | ||||
| 	btrfs_interface_exit(); | ||||
| free_delayed_inode: | ||||
| 	btrfs_delayed_inode_exit(); | ||||
| free_extent_map: | ||||
| 	extent_map_exit(); | ||||
| free_extent_io: | ||||
| @ -1237,6 +1277,7 @@ free_sysfs: | ||||
| static void __exit exit_btrfs_fs(void) | ||||
| { | ||||
| 	btrfs_destroy_cachep(); | ||||
| 	btrfs_delayed_inode_exit(); | ||||
| 	extent_map_exit(); | ||||
| 	extent_io_exit(); | ||||
| 	btrfs_interface_exit(); | ||||
|  | ||||
| @ -174,86 +174,9 @@ static const struct sysfs_ops btrfs_root_attr_ops = { | ||||
| 	.store	= btrfs_root_attr_store, | ||||
| }; | ||||
| 
 | ||||
| static struct kobj_type btrfs_root_ktype = { | ||||
| 	.default_attrs	= btrfs_root_attrs, | ||||
| 	.sysfs_ops	= &btrfs_root_attr_ops, | ||||
| 	.release	= btrfs_root_release, | ||||
| }; | ||||
| 
 | ||||
| static struct kobj_type btrfs_super_ktype = { | ||||
| 	.default_attrs	= btrfs_super_attrs, | ||||
| 	.sysfs_ops	= &btrfs_super_attr_ops, | ||||
| 	.release	= btrfs_super_release, | ||||
| }; | ||||
| 
 | ||||
| /* /sys/fs/btrfs/ entry */ | ||||
| static struct kset *btrfs_kset; | ||||
| 
 | ||||
| int btrfs_sysfs_add_super(struct btrfs_fs_info *fs) | ||||
| { | ||||
| 	int error; | ||||
| 	char *name; | ||||
| 	char c; | ||||
| 	int len = strlen(fs->sb->s_id) + 1; | ||||
| 	int i; | ||||
| 
 | ||||
| 	name = kmalloc(len, GFP_NOFS); | ||||
| 	if (!name) { | ||||
| 		error = -ENOMEM; | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < len; i++) { | ||||
| 		c = fs->sb->s_id[i]; | ||||
| 		if (c == '/' || c == '\\') | ||||
| 			c = '!'; | ||||
| 		name[i] = c; | ||||
| 	} | ||||
| 	name[len] = '\0'; | ||||
| 
 | ||||
| 	fs->super_kobj.kset = btrfs_kset; | ||||
| 	error = kobject_init_and_add(&fs->super_kobj, &btrfs_super_ktype, | ||||
| 				     NULL, "%s", name); | ||||
| 	kfree(name); | ||||
| 	if (error) | ||||
| 		goto fail; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| fail: | ||||
| 	printk(KERN_ERR "btrfs: sysfs creation for super failed\n"); | ||||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| int btrfs_sysfs_add_root(struct btrfs_root *root) | ||||
| { | ||||
| 	int error; | ||||
| 
 | ||||
| 	error = kobject_init_and_add(&root->root_kobj, &btrfs_root_ktype, | ||||
| 				     &root->fs_info->super_kobj, | ||||
| 				     "%s", root->name); | ||||
| 	if (error) | ||||
| 		goto fail; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| fail: | ||||
| 	printk(KERN_ERR "btrfs: sysfs creation for root failed\n"); | ||||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| void btrfs_sysfs_del_root(struct btrfs_root *root) | ||||
| { | ||||
| 	kobject_put(&root->root_kobj); | ||||
| 	wait_for_completion(&root->kobj_unregister); | ||||
| } | ||||
| 
 | ||||
| void btrfs_sysfs_del_super(struct btrfs_fs_info *fs) | ||||
| { | ||||
| 	kobject_put(&fs->super_kobj); | ||||
| 	wait_for_completion(&fs->kobj_unregister); | ||||
| } | ||||
| 
 | ||||
| int btrfs_init_sysfs(void) | ||||
| { | ||||
| 	btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj); | ||||
|  | ||||
| @ -27,6 +27,7 @@ | ||||
| #include "transaction.h" | ||||
| #include "locking.h" | ||||
| #include "tree-log.h" | ||||
| #include "inode-map.h" | ||||
| 
 | ||||
| #define BTRFS_ROOT_TRANS_TAG 0 | ||||
| 
 | ||||
| @ -80,8 +81,7 @@ static noinline int join_transaction(struct btrfs_root *root) | ||||
| 		INIT_LIST_HEAD(&cur_trans->pending_snapshots); | ||||
| 		list_add_tail(&cur_trans->list, &root->fs_info->trans_list); | ||||
| 		extent_io_tree_init(&cur_trans->dirty_pages, | ||||
| 				     root->fs_info->btree_inode->i_mapping, | ||||
| 				     GFP_NOFS); | ||||
| 				     root->fs_info->btree_inode->i_mapping); | ||||
| 		spin_lock(&root->fs_info->new_trans_lock); | ||||
| 		root->fs_info->running_transaction = cur_trans; | ||||
| 		spin_unlock(&root->fs_info->new_trans_lock); | ||||
| @ -347,49 +347,6 @@ out_unlock: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| #if 0 | ||||
| /*
 | ||||
|  * rate limit against the drop_snapshot code.  This helps to slow down new | ||||
|  * operations if the drop_snapshot code isn't able to keep up. | ||||
|  */ | ||||
| static void throttle_on_drops(struct btrfs_root *root) | ||||
| { | ||||
| 	struct btrfs_fs_info *info = root->fs_info; | ||||
| 	int harder_count = 0; | ||||
| 
 | ||||
| harder: | ||||
| 	if (atomic_read(&info->throttles)) { | ||||
| 		DEFINE_WAIT(wait); | ||||
| 		int thr; | ||||
| 		thr = atomic_read(&info->throttle_gen); | ||||
| 
 | ||||
| 		do { | ||||
| 			prepare_to_wait(&info->transaction_throttle, | ||||
| 					&wait, TASK_UNINTERRUPTIBLE); | ||||
| 			if (!atomic_read(&info->throttles)) { | ||||
| 				finish_wait(&info->transaction_throttle, &wait); | ||||
| 				break; | ||||
| 			} | ||||
| 			schedule(); | ||||
| 			finish_wait(&info->transaction_throttle, &wait); | ||||
| 		} while (thr == atomic_read(&info->throttle_gen)); | ||||
| 		harder_count++; | ||||
| 
 | ||||
| 		if (root->fs_info->total_ref_cache_size > 1 * 1024 * 1024 && | ||||
| 		    harder_count < 2) | ||||
| 			goto harder; | ||||
| 
 | ||||
| 		if (root->fs_info->total_ref_cache_size > 5 * 1024 * 1024 && | ||||
| 		    harder_count < 10) | ||||
| 			goto harder; | ||||
| 
 | ||||
| 		if (root->fs_info->total_ref_cache_size > 10 * 1024 * 1024 && | ||||
| 		    harder_count < 20) | ||||
| 			goto harder; | ||||
| 	} | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| void btrfs_throttle(struct btrfs_root *root) | ||||
| { | ||||
| 	mutex_lock(&root->fs_info->trans_mutex); | ||||
| @ -487,19 +444,40 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | ||||
| int btrfs_end_transaction(struct btrfs_trans_handle *trans, | ||||
| 			  struct btrfs_root *root) | ||||
| { | ||||
| 	return __btrfs_end_transaction(trans, root, 0, 1); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = __btrfs_end_transaction(trans, root, 0, 1); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, | ||||
| 				   struct btrfs_root *root) | ||||
| { | ||||
| 	return __btrfs_end_transaction(trans, root, 1, 1); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = __btrfs_end_transaction(trans, root, 1, 1); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int btrfs_end_transaction_nolock(struct btrfs_trans_handle *trans, | ||||
| 				 struct btrfs_root *root) | ||||
| { | ||||
| 	return __btrfs_end_transaction(trans, root, 0, 0); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = __btrfs_end_transaction(trans, root, 0, 0); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans, | ||||
| 				struct btrfs_root *root) | ||||
| { | ||||
| 	return __btrfs_end_transaction(trans, root, 1, 1); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -760,8 +738,14 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans, | ||||
| 			btrfs_update_reloc_root(trans, root); | ||||
| 			btrfs_orphan_commit_root(trans, root); | ||||
| 
 | ||||
| 			btrfs_save_ino_cache(root, trans); | ||||
| 
 | ||||
| 			if (root->commit_root != root->node) { | ||||
| 				mutex_lock(&root->fs_commit_mutex); | ||||
| 				switch_commit_root(root); | ||||
| 				btrfs_unpin_free_ino(root); | ||||
| 				mutex_unlock(&root->fs_commit_mutex); | ||||
| 
 | ||||
| 				btrfs_set_root_node(&root->root_item, | ||||
| 						    root->node); | ||||
| 			} | ||||
| @ -809,97 +793,6 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| #if 0 | ||||
| /*
 | ||||
|  * when dropping snapshots, we generate a ton of delayed refs, and it makes | ||||
|  * sense not to join the transaction while it is trying to flush the current | ||||
|  * queue of delayed refs out. | ||||
|  * | ||||
|  * This is used by the drop snapshot code only | ||||
|  */ | ||||
| static noinline int wait_transaction_pre_flush(struct btrfs_fs_info *info) | ||||
| { | ||||
| 	DEFINE_WAIT(wait); | ||||
| 
 | ||||
| 	mutex_lock(&info->trans_mutex); | ||||
| 	while (info->running_transaction && | ||||
| 	       info->running_transaction->delayed_refs.flushing) { | ||||
| 		prepare_to_wait(&info->transaction_wait, &wait, | ||||
| 				TASK_UNINTERRUPTIBLE); | ||||
| 		mutex_unlock(&info->trans_mutex); | ||||
| 
 | ||||
| 		schedule(); | ||||
| 
 | ||||
| 		mutex_lock(&info->trans_mutex); | ||||
| 		finish_wait(&info->transaction_wait, &wait); | ||||
| 	} | ||||
| 	mutex_unlock(&info->trans_mutex); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Given a list of roots that need to be deleted, call btrfs_drop_snapshot on | ||||
|  * all of them | ||||
|  */ | ||||
| int btrfs_drop_dead_root(struct btrfs_root *root) | ||||
| { | ||||
| 	struct btrfs_trans_handle *trans; | ||||
| 	struct btrfs_root *tree_root = root->fs_info->tree_root; | ||||
| 	unsigned long nr; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	while (1) { | ||||
| 		/*
 | ||||
| 		 * we don't want to jump in and create a bunch of | ||||
| 		 * delayed refs if the transaction is starting to close | ||||
| 		 */ | ||||
| 		wait_transaction_pre_flush(tree_root->fs_info); | ||||
| 		trans = btrfs_start_transaction(tree_root, 1); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * we've joined a transaction, make sure it isn't | ||||
| 		 * closing right now | ||||
| 		 */ | ||||
| 		if (trans->transaction->delayed_refs.flushing) { | ||||
| 			btrfs_end_transaction(trans, tree_root); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		ret = btrfs_drop_snapshot(trans, root); | ||||
| 		if (ret != -EAGAIN) | ||||
| 			break; | ||||
| 
 | ||||
| 		ret = btrfs_update_root(trans, tree_root, | ||||
| 					&root->root_key, | ||||
| 					&root->root_item); | ||||
| 		if (ret) | ||||
| 			break; | ||||
| 
 | ||||
| 		nr = trans->blocks_used; | ||||
| 		ret = btrfs_end_transaction(trans, tree_root); | ||||
| 		BUG_ON(ret); | ||||
| 
 | ||||
| 		btrfs_btree_balance_dirty(tree_root, nr); | ||||
| 		cond_resched(); | ||||
| 	} | ||||
| 	BUG_ON(ret); | ||||
| 
 | ||||
| 	ret = btrfs_del_root(trans, tree_root, &root->root_key); | ||||
| 	BUG_ON(ret); | ||||
| 
 | ||||
| 	nr = trans->blocks_used; | ||||
| 	ret = btrfs_end_transaction(trans, tree_root); | ||||
| 	BUG_ON(ret); | ||||
| 
 | ||||
| 	free_extent_buffer(root->node); | ||||
| 	free_extent_buffer(root->commit_root); | ||||
| 	kfree(root); | ||||
| 
 | ||||
| 	btrfs_btree_balance_dirty(tree_root, nr); | ||||
| 	return ret; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * new snapshots need to be created at a very specific time in the | ||||
|  * transaction commit.  This does the actual creation | ||||
| @ -930,7 +823,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = btrfs_find_free_objectid(trans, tree_root, 0, &objectid); | ||||
| 	ret = btrfs_find_free_objectid(tree_root, &objectid); | ||||
| 	if (ret) { | ||||
| 		pending->error = ret; | ||||
| 		goto fail; | ||||
| @ -967,7 +860,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | ||||
| 	BUG_ON(ret); | ||||
| 	ret = btrfs_insert_dir_item(trans, parent_root, | ||||
| 				dentry->d_name.name, dentry->d_name.len, | ||||
| 				parent_inode->i_ino, &key, | ||||
| 				parent_inode, &key, | ||||
| 				BTRFS_FT_DIR, index); | ||||
| 	BUG_ON(ret); | ||||
| 
 | ||||
| @ -1009,7 +902,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | ||||
| 	 */ | ||||
| 	ret = btrfs_add_root_ref(trans, tree_root, objectid, | ||||
| 				 parent_root->root_key.objectid, | ||||
| 				 parent_inode->i_ino, index, | ||||
| 				 btrfs_ino(parent_inode), index, | ||||
| 				 dentry->d_name.name, dentry->d_name.len); | ||||
| 	BUG_ON(ret); | ||||
| 	dput(parent); | ||||
| @ -1037,6 +930,14 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, | ||||
| 	int ret; | ||||
| 
 | ||||
| 	list_for_each_entry(pending, head, list) { | ||||
| 		/*
 | ||||
| 		 * We must deal with the delayed items before creating | ||||
| 		 * snapshots, or we will create a snapthot with inconsistent | ||||
| 		 * information. | ||||
| 		*/ | ||||
| 		ret = btrfs_run_delayed_items(trans, fs_info->fs_root); | ||||
| 		BUG_ON(ret); | ||||
| 
 | ||||
| 		ret = create_pending_snapshot(trans, fs_info, pending); | ||||
| 		BUG_ON(ret); | ||||
| 	} | ||||
| @ -1290,6 +1191,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | ||||
| 			BUG_ON(ret); | ||||
| 		} | ||||
| 
 | ||||
| 		ret = btrfs_run_delayed_items(trans, root); | ||||
| 		BUG_ON(ret); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * rename don't use btrfs_join_transaction, so, once we | ||||
| 		 * set the transaction to blocked above, we aren't going | ||||
| @ -1316,11 +1220,15 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | ||||
| 	ret = create_pending_snapshots(trans, root->fs_info); | ||||
| 	BUG_ON(ret); | ||||
| 
 | ||||
| 	ret = btrfs_run_delayed_items(trans, root); | ||||
| 	BUG_ON(ret); | ||||
| 
 | ||||
| 	ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); | ||||
| 	BUG_ON(ret); | ||||
| 
 | ||||
| 	WARN_ON(cur_trans != trans->transaction); | ||||
| 
 | ||||
| 	btrfs_scrub_pause(root); | ||||
| 	/* 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 | ||||
| @ -1405,6 +1313,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | ||||
| 
 | ||||
| 	mutex_unlock(&root->fs_info->trans_mutex); | ||||
| 
 | ||||
| 	btrfs_scrub_continue(root); | ||||
| 
 | ||||
| 	if (current->journal_info == trans) | ||||
| 		current->journal_info = NULL; | ||||
| 
 | ||||
| @ -1432,6 +1342,8 @@ int btrfs_clean_old_snapshots(struct btrfs_root *root) | ||||
| 		root = list_entry(list.next, struct btrfs_root, root_list); | ||||
| 		list_del(&root->root_list); | ||||
| 
 | ||||
| 		btrfs_kill_all_delayed_nodes(root); | ||||
| 
 | ||||
| 		if (btrfs_header_backref_rev(root->node) < | ||||
| 		    BTRFS_MIXED_BACKREF_REV) | ||||
| 			btrfs_drop_snapshot(root, NULL, 0); | ||||
|  | ||||
| @ -101,11 +101,8 @@ struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r, | ||||
| int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid); | ||||
| int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, | ||||
| 				     struct btrfs_root *root); | ||||
| int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, | ||||
| 			    struct btrfs_root *root); | ||||
| 
 | ||||
| int btrfs_add_dead_root(struct btrfs_root *root); | ||||
| int btrfs_drop_dead_root(struct btrfs_root *root); | ||||
| int btrfs_defrag_root(struct btrfs_root *root, int cacheonly); | ||||
| int btrfs_clean_old_snapshots(struct btrfs_root *root); | ||||
| int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | ||||
| @ -115,6 +112,8 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, | ||||
| 				   int wait_for_unblock); | ||||
| int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, | ||||
| 				   struct btrfs_root *root); | ||||
| int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans, | ||||
| 				struct btrfs_root *root); | ||||
| int btrfs_should_end_transaction(struct btrfs_trans_handle *trans, | ||||
| 				 struct btrfs_root *root); | ||||
| void btrfs_throttle(struct btrfs_root *root); | ||||
|  | ||||
| @ -97,7 +97,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | ||||
| 		ret = 0; | ||||
| 		goto out; | ||||
| 	} | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	wret = btrfs_search_slot(trans, root, &key, path, 0, 1); | ||||
| 
 | ||||
| 	if (wret < 0) { | ||||
|  | ||||
| @ -333,13 +333,13 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, | ||||
| 			goto insert; | ||||
| 
 | ||||
| 		if (item_size == 0) { | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		dst_copy = kmalloc(item_size, GFP_NOFS); | ||||
| 		src_copy = kmalloc(item_size, GFP_NOFS); | ||||
| 		if (!dst_copy || !src_copy) { | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			kfree(dst_copy); | ||||
| 			kfree(src_copy); | ||||
| 			return -ENOMEM; | ||||
| @ -361,13 +361,13 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, | ||||
| 		 * sync | ||||
| 		 */ | ||||
| 		if (ret == 0) { | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			return 0; | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| insert: | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	/* try to insert the key into the destination tree */ | ||||
| 	ret = btrfs_insert_empty_item(trans, root, path, | ||||
| 				      key, item_size); | ||||
| @ -382,7 +382,6 @@ insert: | ||||
| 		} else if (found_size < item_size) { | ||||
| 			ret = btrfs_extend_item(trans, root, path, | ||||
| 						item_size - found_size); | ||||
| 			BUG_ON(ret); | ||||
| 		} | ||||
| 	} else if (ret) { | ||||
| 		return ret; | ||||
| @ -438,7 +437,7 @@ insert: | ||||
| 	} | ||||
| no_copy: | ||||
| 	btrfs_mark_buffer_dirty(path->nodes[0]); | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -519,7 +518,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | ||||
| 	 * file.  This must be done before the btrfs_drop_extents run | ||||
| 	 * so we don't try to drop this extent. | ||||
| 	 */ | ||||
| 	ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino, | ||||
| 	ret = btrfs_lookup_file_extent(trans, root, path, btrfs_ino(inode), | ||||
| 				       start, 0); | ||||
| 
 | ||||
| 	if (ret == 0 && | ||||
| @ -544,11 +543,11 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | ||||
| 		 * we don't have to do anything | ||||
| 		 */ | ||||
| 		if (memcmp(&cmp1, &cmp2, sizeof(cmp1)) == 0) { | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			goto out; | ||||
| 		} | ||||
| 	} | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 
 | ||||
| 	saved_nbytes = inode_get_bytes(inode); | ||||
| 	/* drop any overlapping extents */ | ||||
| @ -590,6 +589,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | ||||
| 						ins.objectid, ins.offset, | ||||
| 						0, root->root_key.objectid, | ||||
| 						key->objectid, offset); | ||||
| 				BUG_ON(ret); | ||||
| 			} else { | ||||
| 				/*
 | ||||
| 				 * insert the extent pointer in the extent | ||||
| @ -600,7 +600,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | ||||
| 						key->objectid, offset, &ins); | ||||
| 				BUG_ON(ret); | ||||
| 			} | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 
 | ||||
| 			if (btrfs_file_extent_compression(eb, item)) { | ||||
| 				csum_start = ins.objectid; | ||||
| @ -614,7 +614,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | ||||
| 
 | ||||
| 			ret = btrfs_lookup_csums_range(root->log_root, | ||||
| 						csum_start, csum_end - 1, | ||||
| 						&ordered_sums); | ||||
| 						&ordered_sums, 0); | ||||
| 			BUG_ON(ret); | ||||
| 			while (!list_empty(&ordered_sums)) { | ||||
| 				struct btrfs_ordered_sum *sums; | ||||
| @ -629,7 +629,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | ||||
| 				kfree(sums); | ||||
| 			} | ||||
| 		} else { | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 		} | ||||
| 	} else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | ||||
| 		/* inline extents are easy, we just overwrite them */ | ||||
| @ -675,10 +675,13 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans, | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	read_extent_buffer(leaf, name, (unsigned long)(di + 1), name_len); | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 
 | ||||
| 	inode = read_one_inode(root, location.objectid); | ||||
| 	BUG_ON(!inode); | ||||
| 	if (!inode) { | ||||
| 		kfree(name); | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = link_to_fixup_dir(trans, root, path, location.objectid); | ||||
| 	BUG_ON(ret); | ||||
| @ -713,7 +716,7 @@ static noinline int inode_in_dir(struct btrfs_root *root, | ||||
| 			goto out; | ||||
| 	} else | ||||
| 		goto out; | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 
 | ||||
| 	di = btrfs_lookup_dir_item(NULL, root, path, dirid, name, name_len, 0); | ||||
| 	if (di && !IS_ERR(di)) { | ||||
| @ -724,7 +727,7 @@ static noinline int inode_in_dir(struct btrfs_root *root, | ||||
| 		goto out; | ||||
| 	match = 1; | ||||
| out: | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	return match; | ||||
| } | ||||
| 
 | ||||
| @ -817,7 +820,10 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, | ||||
| 		return -ENOENT; | ||||
| 
 | ||||
| 	inode = read_one_inode(root, key->objectid); | ||||
| 	BUG_ON(!inode); | ||||
| 	if (!inode) { | ||||
| 		iput(dir); | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 
 | ||||
| 	ref_ptr = btrfs_item_ptr_offset(eb, slot); | ||||
| 	ref_end = ref_ptr + btrfs_item_size_nr(eb, slot); | ||||
| @ -832,7 +838,7 @@ again: | ||||
| 	read_extent_buffer(eb, name, (unsigned long)(ref + 1), namelen); | ||||
| 
 | ||||
| 	/* if we already have a perfect match, we're done */ | ||||
| 	if (inode_in_dir(root, path, dir->i_ino, inode->i_ino, | ||||
| 	if (inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode), | ||||
| 			 btrfs_inode_ref_index(eb, ref), | ||||
| 			 name, namelen)) { | ||||
| 		goto out; | ||||
| @ -884,7 +890,7 @@ again: | ||||
| 			if (!backref_in_log(log, key, victim_name, | ||||
| 					    victim_name_len)) { | ||||
| 				btrfs_inc_nlink(inode); | ||||
| 				btrfs_release_path(root, path); | ||||
| 				btrfs_release_path(path); | ||||
| 
 | ||||
| 				ret = btrfs_unlink_inode(trans, root, dir, | ||||
| 							 inode, victim_name, | ||||
| @ -901,7 +907,7 @@ again: | ||||
| 		 */ | ||||
| 		search_done = 1; | ||||
| 	} | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 
 | ||||
| insert: | ||||
| 	/* insert our name */ | ||||
| @ -922,7 +928,7 @@ out: | ||||
| 	BUG_ON(ret); | ||||
| 
 | ||||
| out_nowrite: | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	iput(dir); | ||||
| 	iput(inode); | ||||
| 	return 0; | ||||
| @ -960,8 +966,9 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans, | ||||
| 	unsigned long ptr; | ||||
| 	unsigned long ptr_end; | ||||
| 	int name_len; | ||||
| 	u64 ino = btrfs_ino(inode); | ||||
| 
 | ||||
| 	key.objectid = inode->i_ino; | ||||
| 	key.objectid = ino; | ||||
| 	key.type = BTRFS_INODE_REF_KEY; | ||||
| 	key.offset = (u64)-1; | ||||
| 
 | ||||
| @ -980,7 +987,7 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans, | ||||
| 		} | ||||
| 		btrfs_item_key_to_cpu(path->nodes[0], &key, | ||||
| 				      path->slots[0]); | ||||
| 		if (key.objectid != inode->i_ino || | ||||
| 		if (key.objectid != ino || | ||||
| 		    key.type != BTRFS_INODE_REF_KEY) | ||||
| 			break; | ||||
| 		ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]); | ||||
| @ -999,9 +1006,9 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans, | ||||
| 		if (key.offset == 0) | ||||
| 			break; | ||||
| 		key.offset--; | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 	} | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	if (nlink != inode->i_nlink) { | ||||
| 		inode->i_nlink = nlink; | ||||
| 		btrfs_update_inode(trans, root, inode); | ||||
| @ -1011,10 +1018,10 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans, | ||||
| 	if (inode->i_nlink == 0) { | ||||
| 		if (S_ISDIR(inode->i_mode)) { | ||||
| 			ret = replay_dir_deletes(trans, root, NULL, path, | ||||
| 						 inode->i_ino, 1); | ||||
| 						 ino, 1); | ||||
| 			BUG_ON(ret); | ||||
| 		} | ||||
| 		ret = insert_orphan_item(trans, root, inode->i_ino); | ||||
| 		ret = insert_orphan_item(trans, root, ino); | ||||
| 		BUG_ON(ret); | ||||
| 	} | ||||
| 	btrfs_free_path(path); | ||||
| @ -1050,11 +1057,13 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans, | ||||
| 			break; | ||||
| 
 | ||||
| 		ret = btrfs_del_item(trans, root, path); | ||||
| 		BUG_ON(ret); | ||||
| 		if (ret) | ||||
| 			goto out; | ||||
| 
 | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 		inode = read_one_inode(root, key.offset); | ||||
| 		BUG_ON(!inode); | ||||
| 		if (!inode) | ||||
| 			return -EIO; | ||||
| 
 | ||||
| 		ret = fixup_inode_link_count(trans, root, inode); | ||||
| 		BUG_ON(ret); | ||||
| @ -1068,8 +1077,10 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans, | ||||
| 		 */ | ||||
| 		key.offset = (u64)-1; | ||||
| 	} | ||||
| 	btrfs_release_path(root, path); | ||||
| 	return 0; | ||||
| 	ret = 0; | ||||
| out: | ||||
| 	btrfs_release_path(path); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -1088,7 +1099,8 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans, | ||||
| 	struct inode *inode; | ||||
| 
 | ||||
| 	inode = read_one_inode(root, objectid); | ||||
| 	BUG_ON(!inode); | ||||
| 	if (!inode) | ||||
| 		return -EIO; | ||||
| 
 | ||||
| 	key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID; | ||||
| 	btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY); | ||||
| @ -1096,7 +1108,7 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans, | ||||
| 
 | ||||
| 	ret = btrfs_insert_empty_item(trans, root, path, &key, 0); | ||||
| 
 | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	if (ret == 0) { | ||||
| 		btrfs_inc_nlink(inode); | ||||
| 		btrfs_update_inode(trans, root, inode); | ||||
| @ -1175,7 +1187,8 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, | ||||
| 	int ret; | ||||
| 
 | ||||
| 	dir = read_one_inode(root, key->objectid); | ||||
| 	BUG_ON(!dir); | ||||
| 	if (!dir) | ||||
| 		return -EIO; | ||||
| 
 | ||||
| 	name_len = btrfs_dir_name_len(eb, di); | ||||
| 	name = kmalloc(name_len, GFP_NOFS); | ||||
| @ -1192,7 +1205,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, | ||||
| 		exists = 1; | ||||
| 	else | ||||
| 		exists = 0; | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 
 | ||||
| 	if (key->type == BTRFS_DIR_ITEM_KEY) { | ||||
| 		dst_di = btrfs_lookup_dir_item(trans, root, path, key->objectid, | ||||
| @ -1205,7 +1218,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, | ||||
| 	} else { | ||||
| 		BUG(); | ||||
| 	} | ||||
| 	if (!dst_di || IS_ERR(dst_di)) { | ||||
| 	if (IS_ERR_OR_NULL(dst_di)) { | ||||
| 		/* we need a sequence number to insert, so we only
 | ||||
| 		 * do inserts for the BTRFS_DIR_INDEX_KEY types | ||||
| 		 */ | ||||
| @ -1236,13 +1249,13 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, | ||||
| 	if (key->type == BTRFS_DIR_INDEX_KEY) | ||||
| 		goto insert; | ||||
| out: | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	kfree(name); | ||||
| 	iput(dir); | ||||
| 	return 0; | ||||
| 
 | ||||
| insert: | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	ret = insert_one_name(trans, root, path, key->objectid, key->offset, | ||||
| 			      name, name_len, log_type, &log_key); | ||||
| 
 | ||||
| @ -1363,7 +1376,7 @@ next: | ||||
| 	*end_ret = found_end; | ||||
| 	ret = 0; | ||||
| out: | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| @ -1426,12 +1439,15 @@ again: | ||||
| 						     dir_key->offset, | ||||
| 						     name, name_len, 0); | ||||
| 		} | ||||
| 		if (!log_di || IS_ERR(log_di)) { | ||||
| 		if (IS_ERR_OR_NULL(log_di)) { | ||||
| 			btrfs_dir_item_key_to_cpu(eb, di, &location); | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(log, log_path); | ||||
| 			btrfs_release_path(path); | ||||
| 			btrfs_release_path(log_path); | ||||
| 			inode = read_one_inode(root, location.objectid); | ||||
| 			BUG_ON(!inode); | ||||
| 			if (!inode) { | ||||
| 				kfree(name); | ||||
| 				return -EIO; | ||||
| 			} | ||||
| 
 | ||||
| 			ret = link_to_fixup_dir(trans, root, | ||||
| 						path, location.objectid); | ||||
| @ -1453,7 +1469,7 @@ again: | ||||
| 			ret = 0; | ||||
| 			goto out; | ||||
| 		} | ||||
| 		btrfs_release_path(log, log_path); | ||||
| 		btrfs_release_path(log_path); | ||||
| 		kfree(name); | ||||
| 
 | ||||
| 		ptr = (unsigned long)(di + 1); | ||||
| @ -1461,8 +1477,8 @@ again: | ||||
| 	} | ||||
| 	ret = 0; | ||||
| out: | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(log, log_path); | ||||
| 	btrfs_release_path(path); | ||||
| 	btrfs_release_path(log_path); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| @ -1550,7 +1566,7 @@ again: | ||||
| 				break; | ||||
| 			dir_key.offset = found_key.offset + 1; | ||||
| 		} | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 		if (range_end == (u64)-1) | ||||
| 			break; | ||||
| 		range_start = range_end + 1; | ||||
| @ -1561,11 +1577,11 @@ next_type: | ||||
| 	if (key_type == BTRFS_DIR_LOG_ITEM_KEY) { | ||||
| 		key_type = BTRFS_DIR_LOG_INDEX_KEY; | ||||
| 		dir_key.type = BTRFS_DIR_INDEX_KEY; | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 		goto again; | ||||
| 	} | ||||
| out: | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	btrfs_free_path(log_path); | ||||
| 	iput(dir); | ||||
| 	return ret; | ||||
| @ -2093,7 +2109,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | ||||
| 	 * the running transaction open, so a full commit can't hop | ||||
| 	 * in and cause problems either. | ||||
| 	 */ | ||||
| 	btrfs_scrub_pause_super(root); | ||||
| 	write_ctree_super(trans, root->fs_info->tree_root, 1); | ||||
| 	btrfs_scrub_continue_super(root); | ||||
| 	ret = 0; | ||||
| 
 | ||||
| 	mutex_lock(&root->log_mutex); | ||||
| @ -2197,6 +2215,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, | ||||
| 	int ret; | ||||
| 	int err = 0; | ||||
| 	int bytes_del = 0; | ||||
| 	u64 dir_ino = btrfs_ino(dir); | ||||
| 
 | ||||
| 	if (BTRFS_I(dir)->logged_trans < trans->transid) | ||||
| 		return 0; | ||||
| @ -2214,7 +2233,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, | ||||
| 		goto out_unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino, | ||||
| 	di = btrfs_lookup_dir_item(trans, log, path, dir_ino, | ||||
| 				   name, name_len, -1); | ||||
| 	if (IS_ERR(di)) { | ||||
| 		err = PTR_ERR(di); | ||||
| @ -2225,8 +2244,8 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, | ||||
| 		bytes_del += name_len; | ||||
| 		BUG_ON(ret); | ||||
| 	} | ||||
| 	btrfs_release_path(log, path); | ||||
| 	di = btrfs_lookup_dir_index_item(trans, log, path, dir->i_ino, | ||||
| 	btrfs_release_path(path); | ||||
| 	di = btrfs_lookup_dir_index_item(trans, log, path, dir_ino, | ||||
| 					 index, name, name_len, -1); | ||||
| 	if (IS_ERR(di)) { | ||||
| 		err = PTR_ERR(di); | ||||
| @ -2244,10 +2263,10 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, | ||||
| 	if (bytes_del) { | ||||
| 		struct btrfs_key key; | ||||
| 
 | ||||
| 		key.objectid = dir->i_ino; | ||||
| 		key.objectid = dir_ino; | ||||
| 		key.offset = 0; | ||||
| 		key.type = BTRFS_INODE_ITEM_KEY; | ||||
| 		btrfs_release_path(log, path); | ||||
| 		btrfs_release_path(path); | ||||
| 
 | ||||
| 		ret = btrfs_search_slot(trans, log, &key, path, 0, 1); | ||||
| 		if (ret < 0) { | ||||
| @ -2269,7 +2288,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, | ||||
| 			btrfs_mark_buffer_dirty(path->nodes[0]); | ||||
| 		} else | ||||
| 			ret = 0; | ||||
| 		btrfs_release_path(log, path); | ||||
| 		btrfs_release_path(path); | ||||
| 	} | ||||
| fail: | ||||
| 	btrfs_free_path(path); | ||||
| @ -2303,7 +2322,7 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans, | ||||
| 	log = root->log_root; | ||||
| 	mutex_lock(&BTRFS_I(inode)->log_mutex); | ||||
| 
 | ||||
| 	ret = btrfs_del_inode_ref(trans, log, name, name_len, inode->i_ino, | ||||
| 	ret = btrfs_del_inode_ref(trans, log, name, name_len, btrfs_ino(inode), | ||||
| 				  dirid, &index); | ||||
| 	mutex_unlock(&BTRFS_I(inode)->log_mutex); | ||||
| 	if (ret == -ENOSPC) { | ||||
| @ -2344,7 +2363,7 @@ static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans, | ||||
| 			      struct btrfs_dir_log_item); | ||||
| 	btrfs_set_dir_log_end(path->nodes[0], item, last_offset); | ||||
| 	btrfs_mark_buffer_dirty(path->nodes[0]); | ||||
| 	btrfs_release_path(log, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -2369,13 +2388,14 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, | ||||
| 	int nritems; | ||||
| 	u64 first_offset = min_offset; | ||||
| 	u64 last_offset = (u64)-1; | ||||
| 	u64 ino = btrfs_ino(inode); | ||||
| 
 | ||||
| 	log = root->log_root; | ||||
| 	max_key.objectid = inode->i_ino; | ||||
| 	max_key.objectid = ino; | ||||
| 	max_key.offset = (u64)-1; | ||||
| 	max_key.type = key_type; | ||||
| 
 | ||||
| 	min_key.objectid = inode->i_ino; | ||||
| 	min_key.objectid = ino; | ||||
| 	min_key.type = key_type; | ||||
| 	min_key.offset = min_offset; | ||||
| 
 | ||||
| @ -2388,18 +2408,17 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, | ||||
| 	 * we didn't find anything from this transaction, see if there | ||||
| 	 * is anything at all | ||||
| 	 */ | ||||
| 	if (ret != 0 || min_key.objectid != inode->i_ino || | ||||
| 	    min_key.type != key_type) { | ||||
| 		min_key.objectid = inode->i_ino; | ||||
| 	if (ret != 0 || min_key.objectid != ino || min_key.type != key_type) { | ||||
| 		min_key.objectid = ino; | ||||
| 		min_key.type = key_type; | ||||
| 		min_key.offset = (u64)-1; | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 		ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0); | ||||
| 		if (ret < 0) { | ||||
| 			btrfs_release_path(root, path); | ||||
| 			btrfs_release_path(path); | ||||
| 			return ret; | ||||
| 		} | ||||
| 		ret = btrfs_previous_item(root, path, inode->i_ino, key_type); | ||||
| 		ret = btrfs_previous_item(root, path, ino, key_type); | ||||
| 
 | ||||
| 		/* if ret == 0 there are items for this type,
 | ||||
| 		 * create a range to tell us the last key of this type. | ||||
| @ -2417,7 +2436,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, | ||||
| 	} | ||||
| 
 | ||||
| 	/* go backward to find any previous key */ | ||||
| 	ret = btrfs_previous_item(root, path, inode->i_ino, key_type); | ||||
| 	ret = btrfs_previous_item(root, path, ino, key_type); | ||||
| 	if (ret == 0) { | ||||
| 		struct btrfs_key tmp; | ||||
| 		btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]); | ||||
| @ -2432,7 +2451,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(path); | ||||
| 
 | ||||
| 	/* find the first key from this transaction again */ | ||||
| 	ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0); | ||||
| @ -2452,8 +2471,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, | ||||
| 		for (i = path->slots[0]; i < nritems; i++) { | ||||
| 			btrfs_item_key_to_cpu(src, &min_key, i); | ||||
| 
 | ||||
| 			if (min_key.objectid != inode->i_ino || | ||||
| 			    min_key.type != key_type) | ||||
| 			if (min_key.objectid != ino || min_key.type != key_type) | ||||
| 				goto done; | ||||
| 			ret = overwrite_item(trans, log, dst_path, src, i, | ||||
| 					     &min_key); | ||||
| @ -2474,7 +2492,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, | ||||
| 			goto done; | ||||
| 		} | ||||
| 		btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]); | ||||
| 		if (tmp.objectid != inode->i_ino || tmp.type != key_type) { | ||||
| 		if (tmp.objectid != ino || tmp.type != key_type) { | ||||
| 			last_offset = (u64)-1; | ||||
| 			goto done; | ||||
| 		} | ||||
| @ -2490,8 +2508,8 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, | ||||
| 		} | ||||
| 	} | ||||
| done: | ||||
| 	btrfs_release_path(root, path); | ||||
| 	btrfs_release_path(log, dst_path); | ||||
| 	btrfs_release_path(path); | ||||
| 	btrfs_release_path(dst_path); | ||||
| 
 | ||||
| 	if (err == 0) { | ||||
| 		*last_offset_ret = last_offset; | ||||
| @ -2500,8 +2518,7 @@ done: | ||||
| 		 * is valid | ||||
| 		 */ | ||||
| 		ret = insert_dir_log_key(trans, log, path, key_type, | ||||
| 					 inode->i_ino, first_offset, | ||||
| 					 last_offset); | ||||
| 					 ino, first_offset, last_offset); | ||||
| 		if (ret) | ||||
| 			err = ret; | ||||
| 	} | ||||
| @ -2587,10 +2604,11 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans, | ||||
| 			break; | ||||
| 
 | ||||
| 		ret = btrfs_del_item(trans, log, path); | ||||
| 		BUG_ON(ret); | ||||
| 		btrfs_release_path(log, path); | ||||
| 		if (ret) | ||||
| 			break; | ||||
| 		btrfs_release_path(path); | ||||
| 	} | ||||
| 	btrfs_release_path(log, path); | ||||
| 	btrfs_release_path(path); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| @ -2665,6 +2683,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | ||||
| 			extent = btrfs_item_ptr(src, start_slot + i, | ||||
| 						struct btrfs_file_extent_item); | ||||
| 
 | ||||
| 			if (btrfs_file_extent_generation(src, extent) < trans->transid) | ||||
| 				continue; | ||||
| 
 | ||||
| 			found_type = btrfs_file_extent_type(src, extent); | ||||
| 			if (found_type == BTRFS_FILE_EXTENT_REG || | ||||
| 			    found_type == BTRFS_FILE_EXTENT_PREALLOC) { | ||||
| @ -2689,14 +2710,14 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | ||||
| 				ret = btrfs_lookup_csums_range( | ||||
| 						log->fs_info->csum_root, | ||||
| 						ds + cs, ds + cs + cl - 1, | ||||
| 						&ordered_sums); | ||||
| 						&ordered_sums, 0); | ||||
| 				BUG_ON(ret); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	btrfs_mark_buffer_dirty(dst_path->nodes[0]); | ||||
| 	btrfs_release_path(log, dst_path); | ||||
| 	btrfs_release_path(dst_path); | ||||
| 	kfree(ins_data); | ||||
| 
 | ||||
| 	/*
 | ||||
| @ -2745,6 +2766,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | ||||
| 	int nritems; | ||||
| 	int ins_start_slot = 0; | ||||
| 	int ins_nr; | ||||
| 	u64 ino = btrfs_ino(inode); | ||||
| 
 | ||||
| 	log = root->log_root; | ||||
| 
 | ||||
| @ -2757,11 +2779,11 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	min_key.objectid = inode->i_ino; | ||||
| 	min_key.objectid = ino; | ||||
| 	min_key.type = BTRFS_INODE_ITEM_KEY; | ||||
| 	min_key.offset = 0; | ||||
| 
 | ||||
| 	max_key.objectid = inode->i_ino; | ||||
| 	max_key.objectid = ino; | ||||
| 
 | ||||
| 	/* today the code can only do partial logging of directories */ | ||||
| 	if (!S_ISDIR(inode->i_mode)) | ||||
| @ -2773,6 +2795,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | ||||
| 		max_key.type = (u8)-1; | ||||
| 	max_key.offset = (u64)-1; | ||||
| 
 | ||||
| 	ret = btrfs_commit_inode_delayed_items(trans, inode); | ||||
| 	if (ret) { | ||||
| 		btrfs_free_path(path); | ||||
| 		btrfs_free_path(dst_path); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	mutex_lock(&BTRFS_I(inode)->log_mutex); | ||||
| 
 | ||||
| 	/*
 | ||||
| @ -2784,8 +2813,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | ||||
| 
 | ||||
| 		if (inode_only == LOG_INODE_EXISTS) | ||||
| 			max_key_type = BTRFS_XATTR_ITEM_KEY; | ||||
| 		ret = drop_objectid_items(trans, log, path, | ||||
| 					  inode->i_ino, max_key_type); | ||||
| 		ret = drop_objectid_items(trans, log, path, ino, max_key_type); | ||||
| 	} else { | ||||
| 		ret = btrfs_truncate_inode_items(trans, log, inode, 0, 0); | ||||
| 	} | ||||
| @ -2803,7 +2831,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | ||||
| 			break; | ||||
| again: | ||||
| 		/* note, ins_nr might be > 0 here, cleanup outside the loop */ | ||||
| 		if (min_key.objectid != inode->i_ino) | ||||
| 		if (min_key.objectid != ino) | ||||
| 			break; | ||||
| 		if (min_key.type > max_key.type) | ||||
| 			break; | ||||
| @ -2845,7 +2873,7 @@ next_slot: | ||||
| 			} | ||||
| 			ins_nr = 0; | ||||
| 		} | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 
 | ||||
| 		if (min_key.offset < (u64)-1) | ||||
| 			min_key.offset++; | ||||
| @ -2868,8 +2896,8 @@ next_slot: | ||||
| 	} | ||||
| 	WARN_ON(ins_nr); | ||||
| 	if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) { | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(log, dst_path); | ||||
| 		btrfs_release_path(path); | ||||
| 		btrfs_release_path(dst_path); | ||||
| 		ret = log_directory_changes(trans, root, inode, path, dst_path); | ||||
| 		if (ret) { | ||||
| 			err = ret; | ||||
| @ -3136,7 +3164,7 @@ again: | ||||
| 		} | ||||
| 		btrfs_item_key_to_cpu(path->nodes[0], &found_key, | ||||
| 				      path->slots[0]); | ||||
| 		btrfs_release_path(log_root_tree, path); | ||||
| 		btrfs_release_path(path); | ||||
| 		if (found_key.objectid != BTRFS_TREE_LOG_OBJECTID) | ||||
| 			break; | ||||
| 
 | ||||
| @ -3171,7 +3199,7 @@ again: | ||||
| 		if (found_key.offset == 0) | ||||
| 			break; | ||||
| 	} | ||||
| 	btrfs_release_path(log_root_tree, path); | ||||
| 	btrfs_release_path(path); | ||||
| 
 | ||||
| 	/* step one is to pin it all, step two is to replay just inodes */ | ||||
| 	if (wc.pin) { | ||||
|  | ||||
| @ -38,7 +38,6 @@ 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); | ||||
| int btrfs_join_running_log_trans(struct btrfs_root *root); | ||||
| int btrfs_end_log_trans(struct btrfs_root *root); | ||||
| int btrfs_pin_log_trans(struct btrfs_root *root); | ||||
| int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | ||||
|  | ||||
| @ -1,43 +0,0 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # determine-version -- report a useful version for releases | ||||
| # | ||||
| # Copyright 2008, Aron Griffis <agriffis@n01se.net> | ||||
| # Copyright 2008, Oracle | ||||
| # Released under the GNU GPLv2 | ||||
|   | ||||
| v="v0.16" | ||||
| 
 | ||||
| which git &> /dev/null | ||||
| if [ $? == 0 ]; then | ||||
|     git branch >& /dev/null | ||||
|     if [ $? == 0 ]; then | ||||
| 	    if head=`git rev-parse --verify HEAD 2>/dev/null`; then | ||||
| 		if tag=`git describe --tags 2>/dev/null`; then | ||||
| 		    v="$tag" | ||||
| 		fi | ||||
| 
 | ||||
| 		# Are there uncommitted changes? | ||||
| 		git update-index --refresh --unmerged > /dev/null | ||||
| 		if git diff-index --name-only HEAD | \ | ||||
| 		    grep -v "^scripts/package" \ | ||||
| 		    | read dummy; then | ||||
| 		    v="$v"-dirty | ||||
| 		fi | ||||
| 	    fi | ||||
|     fi | ||||
| fi | ||||
|   | ||||
| echo "#ifndef __BUILD_VERSION" > .build-version.h | ||||
| echo "#define __BUILD_VERSION" >> .build-version.h | ||||
| echo "#define BTRFS_BUILD_VERSION \"Btrfs $v\"" >> .build-version.h | ||||
| echo "#endif" >> .build-version.h | ||||
| 
 | ||||
| diff -q version.h .build-version.h >& /dev/null | ||||
| 
 | ||||
| if [ $? == 0 ]; then | ||||
|     rm .build-version.h | ||||
|     exit 0 | ||||
| fi | ||||
| 
 | ||||
| mv .build-version.h version.h | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -85,7 +85,12 @@ struct btrfs_device { | ||||
| 	/* physical drive uuid (or lvm uuid) */ | ||||
| 	u8 uuid[BTRFS_UUID_SIZE]; | ||||
| 
 | ||||
| 	/* per-device scrub information */ | ||||
| 	struct scrub_dev *scrub_device; | ||||
| 
 | ||||
| 	struct btrfs_work work; | ||||
| 	struct rcu_head rcu; | ||||
| 	struct work_struct rcu_work; | ||||
| }; | ||||
| 
 | ||||
| struct btrfs_fs_devices { | ||||
| @ -144,6 +149,7 @@ struct btrfs_device_info { | ||||
| 	struct btrfs_device *dev; | ||||
| 	u64 dev_offset; | ||||
| 	u64 max_avail; | ||||
| 	u64 total_avail; | ||||
| }; | ||||
| 
 | ||||
| struct map_lookup { | ||||
| @ -157,20 +163,8 @@ struct map_lookup { | ||||
| 	struct btrfs_bio_stripe stripes[]; | ||||
| }; | ||||
| 
 | ||||
| /* Used to sort the devices by max_avail(descending sort) */ | ||||
| int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2); | ||||
| 
 | ||||
| /*
 | ||||
|  * sort the devices by max_avail, in which max free extent size of each device | ||||
|  * is stored.(Descending Sort) | ||||
|  */ | ||||
| static inline void btrfs_descending_sort_devices( | ||||
| 					struct btrfs_device_info *devices, | ||||
| 					size_t nr_devices) | ||||
| { | ||||
| 	sort(devices, nr_devices, sizeof(struct btrfs_device_info), | ||||
| 	     btrfs_cmp_device_free_bytes, NULL); | ||||
| } | ||||
| #define map_lookup_size(n) (sizeof(struct map_lookup) + \ | ||||
| 			    (sizeof(struct btrfs_bio_stripe) * (n))) | ||||
| 
 | ||||
| int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, | ||||
| 				   u64 end, u64 *length); | ||||
| @ -196,7 +190,6 @@ void btrfs_mapping_init(struct btrfs_mapping_tree *tree); | ||||
| void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree); | ||||
| int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, | ||||
| 		  int mirror_num, int async_submit); | ||||
| int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf); | ||||
| int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, | ||||
| 		       fmode_t flags, void *holder); | ||||
| int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, | ||||
| @ -209,8 +202,6 @@ int btrfs_add_device(struct btrfs_trans_handle *trans, | ||||
| int btrfs_rm_device(struct btrfs_root *root, char *device_path); | ||||
| int btrfs_cleanup_fs_uuids(void); | ||||
| int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len); | ||||
| int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree, | ||||
| 		      u64 logical, struct page *page); | ||||
| int btrfs_grow_device(struct btrfs_trans_handle *trans, | ||||
| 		      struct btrfs_device *device, u64 new_size); | ||||
| struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid, | ||||
| @ -218,8 +209,6 @@ struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid, | ||||
| int btrfs_shrink_device(struct btrfs_device *device, u64 new_size); | ||||
| int btrfs_init_new_device(struct btrfs_root *root, char *path); | ||||
| int btrfs_balance(struct btrfs_root *dev_root); | ||||
| void btrfs_unlock_volumes(void); | ||||
| void btrfs_lock_volumes(void); | ||||
| int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); | ||||
| int find_free_dev_extent(struct btrfs_trans_handle *trans, | ||||
| 			 struct btrfs_device *device, u64 num_bytes, | ||||
|  | ||||
| @ -44,7 +44,7 @@ ssize_t __btrfs_getxattr(struct inode *inode, const char *name, | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	/* lookup the xattr by name */ | ||||
| 	di = btrfs_lookup_xattr(NULL, root, path, inode->i_ino, name, | ||||
| 	di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), name, | ||||
| 				strlen(name), 0); | ||||
| 	if (!di) { | ||||
| 		ret = -ENODATA; | ||||
| @ -103,7 +103,7 @@ static int do_setxattr(struct btrfs_trans_handle *trans, | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	/* first lets see if we already have this xattr */ | ||||
| 	di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name, | ||||
| 	di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), name, | ||||
| 				strlen(name), -1); | ||||
| 	if (IS_ERR(di)) { | ||||
| 		ret = PTR_ERR(di); | ||||
| @ -120,13 +120,13 @@ static int do_setxattr(struct btrfs_trans_handle *trans, | ||||
| 
 | ||||
| 		ret = btrfs_delete_one_dir_name(trans, root, path, di); | ||||
| 		BUG_ON(ret); | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 
 | ||||
| 		/* if we don't have a value then we are removing the xattr */ | ||||
| 		if (!value) | ||||
| 			goto out; | ||||
| 	} else { | ||||
| 		btrfs_release_path(root, path); | ||||
| 		btrfs_release_path(path); | ||||
| 
 | ||||
| 		if (flags & XATTR_REPLACE) { | ||||
| 			/* we couldn't find the attr to replace */ | ||||
| @ -136,7 +136,7 @@ static int do_setxattr(struct btrfs_trans_handle *trans, | ||||
| 	} | ||||
| 
 | ||||
| 	/* ok we have to create a completely new xattr */ | ||||
| 	ret = btrfs_insert_xattr_item(trans, root, path, inode->i_ino, | ||||
| 	ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode), | ||||
| 				      name, name_len, value, size); | ||||
| 	BUG_ON(ret); | ||||
| out: | ||||
| @ -190,7 +190,7 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) | ||||
| 	 * NOTE: we set key.offset = 0; because we want to start with the | ||||
| 	 * first xattr that we find and walk forward | ||||
| 	 */ | ||||
| 	key.objectid = inode->i_ino; | ||||
| 	key.objectid = btrfs_ino(inode); | ||||
| 	btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); | ||||
| 	key.offset = 0; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user