mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-14 06:24:53 +08:00
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