summaryrefslogtreecommitdiff
path: root/fs/btrfs
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
committerScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
commit62b8c978ee6b8d135d9e7953221de58000dba986 (patch)
tree683b04b2e627f6710c22c151b23c8cc9a165315e /fs/btrfs
parent78fd82238d0e5716578c326404184a27ba67fd6e (diff)
downloadlinux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/Kconfig18
-rw-r--r--fs/btrfs/Makefile4
-rw-r--r--fs/btrfs/acl.c2
-rw-r--r--fs/btrfs/async-thread.c3
-rw-r--r--fs/btrfs/backref.c8
-rw-r--r--fs/btrfs/btrfs_inode.h20
-rw-r--r--fs/btrfs/check-integrity.c75
-rw-r--r--fs/btrfs/check-integrity.h2
-rw-r--r--fs/btrfs/compat.h7
-rw-r--r--fs/btrfs/compression.c3
-rw-r--r--fs/btrfs/ctree.c75
-rw-r--r--fs/btrfs/ctree.h47
-rw-r--r--fs/btrfs/delayed-inode.c19
-rw-r--r--fs/btrfs/dev-replace.c28
-rw-r--r--fs/btrfs/dir-item.c8
-rw-r--r--fs/btrfs/disk-io.c269
-rw-r--r--fs/btrfs/disk-io.h4
-rw-r--r--fs/btrfs/export.c1
-rw-r--r--fs/btrfs/extent-tree.c174
-rw-r--r--fs/btrfs/extent_io.c158
-rw-r--r--fs/btrfs/extent_io.h8
-rw-r--r--fs/btrfs/extent_map.h8
-rw-r--r--fs/btrfs/file-item.c7
-rw-r--r--fs/btrfs/file.c163
-rw-r--r--fs/btrfs/free-space-cache.c21
-rw-r--r--fs/btrfs/free-space-cache.h4
-rw-r--r--fs/btrfs/inode-item.c2
-rw-r--r--fs/btrfs/inode-map.c13
-rw-r--r--fs/btrfs/inode.c213
-rw-r--r--fs/btrfs/ioctl.c85
-rw-r--r--fs/btrfs/ordered-data.c55
-rw-r--r--fs/btrfs/ordered-data.h6
-rw-r--r--fs/btrfs/print-tree.c2
-rw-r--r--fs/btrfs/raid56.c1
-rw-r--r--fs/btrfs/relocation.c94
-rw-r--r--fs/btrfs/scrub.c85
-rw-r--r--fs/btrfs/send.c193
-rw-r--r--fs/btrfs/super.c31
-rw-r--r--fs/btrfs/tests/btrfs-tests.c74
-rw-r--r--fs/btrfs/tests/btrfs-tests.h25
-rw-r--r--fs/btrfs/tests/extent-buffer-tests.c229
-rw-r--r--fs/btrfs/tests/extent-io-tests.c276
-rw-r--r--fs/btrfs/tests/inode-tests.c955
-rw-r--r--fs/btrfs/transaction.c85
-rw-r--r--fs/btrfs/transaction.h2
-rw-r--r--fs/btrfs/tree-defrag.c5
-rw-r--r--fs/btrfs/tree-log.c153
-rw-r--r--fs/btrfs/uuid-tree.c6
-rw-r--r--fs/btrfs/volumes.c28
-rw-r--r--fs/btrfs/volumes.h24
50 files changed, 1095 insertions, 2683 deletions
diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig
index aa976ec..398cbd5 100644
--- a/fs/btrfs/Kconfig
+++ b/fs/btrfs/Kconfig
@@ -9,17 +9,12 @@ config BTRFS_FS
select XOR_BLOCKS
help
- Btrfs is a general purpose copy-on-write filesystem with extents,
- writable snapshotting, support for multiple devices and many more
- features focused on fault tolerance, repair and easy administration.
+ Btrfs is a new filesystem with extents, writable snapshotting,
+ support for multiple devices and many more features.
- The filesystem disk format is no longer unstable, and it's not
- expected to change unless there are strong reasons to do so. If there
- is a format change, file systems with a unchanged format will
- continue to be mountable and usable by newer kernels.
-
- For more information, please see the web pages at
- http://btrfs.wiki.kernel.org.
+ Btrfs is highly experimental, and THE DISK FORMAT IS NOT YET
+ FINALIZED. You should say N here unless you are interested in
+ testing Btrfs with non-critical data.
To compile this file system support as a module, choose M here. The
module will be called btrfs.
@@ -64,8 +59,7 @@ config BTRFS_FS_RUN_SANITY_TESTS
help
This will run some basic sanity tests on the free space cache
code to make sure it is acting as it should. These are mostly
- regression tests and are only really interesting to btrfs
- developers.
+ regression tests and are only really interesting to btrfs devlopers.
If unsure, say N.
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
index 1a44e42..a91a6a3 100644
--- a/fs/btrfs/Makefile
+++ b/fs/btrfs/Makefile
@@ -14,6 +14,4 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
-btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o \
- tests/extent-buffer-tests.o tests/btrfs-tests.o \
- tests/extent-io-tests.o tests/inode-tests.o
+btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index 0890c83..e15d2b0 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -229,7 +229,7 @@ int btrfs_init_acl(struct btrfs_trans_handle *trans,
if (ret > 0) {
/* we need an acl */
ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS);
- } else if (ret < 0) {
+ } else {
cache_no_acl(inode);
}
} else {
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c
index c1e0b0c..08cc08f 100644
--- a/fs/btrfs/async-thread.c
+++ b/fs/btrfs/async-thread.c
@@ -262,7 +262,7 @@ static struct btrfs_work *get_next_work(struct btrfs_worker_thread *worker,
struct btrfs_work *work = NULL;
struct list_head *cur = NULL;
- if (!list_empty(prio_head))
+ if(!list_empty(prio_head))
cur = prio_head->next;
smp_mb();
@@ -495,7 +495,6 @@ static int __btrfs_start_workers(struct btrfs_workers *workers)
spin_lock_irq(&workers->lock);
if (workers->stopping) {
spin_unlock_irq(&workers->lock);
- ret = -EINVAL;
goto fail_kthread;
}
list_add_tail(&worker->worker_list, &workers->idle_list);
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 3775947..0552a59 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -185,9 +185,6 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id,
{
struct __prelim_ref *ref;
- if (root_id == BTRFS_DATA_RELOC_TREE_OBJECTID)
- return 0;
-
ref = kmem_cache_alloc(btrfs_prelim_ref_cache, gfp_mask);
if (!ref)
return -ENOMEM;
@@ -326,7 +323,8 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
eb = path->nodes[level];
while (!eb) {
- if (WARN_ON(!level)) {
+ if (!level) {
+ WARN_ON(1);
ret = 1;
goto out;
}
@@ -1621,7 +1619,7 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,
btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
btrfs_release_path(path);
- item = btrfs_item_nr(slot);
+ item = btrfs_item_nr(eb, slot);
iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref);
for (cur = 0; cur < btrfs_item_size(eb, item); cur += len) {
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index ac0b39d..71f074e 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -19,7 +19,6 @@
#ifndef __BTRFS_I__
#define __BTRFS_I__
-#include <linux/hash.h>
#include "extent_map.h"
#include "extent_io.h"
#include "ordered-data.h"
@@ -180,25 +179,6 @@ static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
return container_of(inode, struct btrfs_inode, vfs_inode);
}
-static inline unsigned long btrfs_inode_hash(u64 objectid,
- const struct btrfs_root *root)
-{
- u64 h = objectid ^ (root->objectid * GOLDEN_RATIO_PRIME);
-
-#if BITS_PER_LONG == 32
- h = (h >> 32) ^ (h & 0xffffffff);
-#endif
-
- return (unsigned long)h;
-}
-
-static inline void btrfs_insert_inode_hash(struct inode *inode)
-{
- unsigned long h = btrfs_inode_hash(inode->i_ino, BTRFS_I(inode)->root);
-
- __insert_inode_hash(inode, h);
-}
-
static inline u64 btrfs_ino(struct inode *inode)
{
u64 ino = BTRFS_I(inode)->location.objectid;
diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c
index 131d828..1c47be1 100644
--- a/fs/btrfs/check-integrity.c
+++ b/fs/btrfs/check-integrity.c
@@ -77,15 +77,6 @@
* the integrity of (super)-block write requests, do not
* enable the config option BTRFS_FS_CHECK_INTEGRITY to
* include and compile the integrity check tool.
- *
- * Expect millions of lines of information in the kernel log with an
- * enabled check_int_print_mask. Therefore set LOG_BUF_SHIFT in the
- * kernel config to at least 26 (which is 64MB). Usually the value is
- * limited to 21 (which is 2MB) in init/Kconfig. The file needs to be
- * changed like this before LOG_BUF_SHIFT can be set to a high value:
- * config LOG_BUF_SHIFT
- * int "Kernel log buffer size (16 => 64KB, 17 => 128KB)"
- * range 12 30
*/
#include <linux/sched.h>
@@ -133,7 +124,6 @@
#define BTRFSIC_PRINT_MASK_INITIAL_DATABASE 0x00000400
#define BTRFSIC_PRINT_MASK_NUM_COPIES 0x00000800
#define BTRFSIC_PRINT_MASK_TREE_WITH_ALL_MIRRORS 0x00001000
-#define BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH_VERBOSE 0x00002000
struct btrfsic_dev_state;
struct btrfsic_state;
@@ -333,6 +323,7 @@ static void btrfsic_release_block_ctx(struct btrfsic_block_data_ctx *block_ctx);
static int btrfsic_read_block(struct btrfsic_state *state,
struct btrfsic_block_data_ctx *block_ctx);
static void btrfsic_dump_database(struct btrfsic_state *state);
+static void btrfsic_complete_bio_end_io(struct bio *bio, int err);
static int btrfsic_test_for_metadata(struct btrfsic_state *state,
char **datav, unsigned int num_pages);
static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
@@ -1047,7 +1038,7 @@ leaf_item_out_of_bounce_error:
disk_item_offset,
sizeof(struct btrfs_item));
item_offset = btrfs_stack_item_offset(&disk_item);
- item_size = btrfs_stack_item_size(&disk_item);
+ item_size = btrfs_stack_item_offset(&disk_item);
disk_key = &disk_item.key;
type = btrfs_disk_key_type(disk_key);
@@ -1686,6 +1677,7 @@ static int btrfsic_read_block(struct btrfsic_state *state,
for (i = 0; i < num_pages;) {
struct bio *bio;
unsigned int j;
+ DECLARE_COMPLETION_ONSTACK(complete);
bio = btrfs_io_bio_alloc(GFP_NOFS, num_pages - i);
if (!bio) {
@@ -1696,6 +1688,8 @@ static int btrfsic_read_block(struct btrfsic_state *state,
}
bio->bi_bdev = block_ctx->dev->bdev;
bio->bi_sector = dev_bytenr >> 9;
+ bio->bi_end_io = btrfsic_complete_bio_end_io;
+ bio->bi_private = &complete;
for (j = i; j < num_pages; j++) {
ret = bio_add_page(bio, block_ctx->pagev[j],
@@ -1708,7 +1702,12 @@ static int btrfsic_read_block(struct btrfsic_state *state,
"btrfsic: error, failed to add a single page!\n");
return -1;
}
- if (submit_bio_wait(READ, bio)) {
+ submit_bio(READ, bio);
+
+ /* this will also unplug the queue */
+ wait_for_completion(&complete);
+
+ if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
printk(KERN_INFO
"btrfsic: read error at logical %llu dev %s!\n",
block_ctx->start, block_ctx->dev->name);
@@ -1731,6 +1730,11 @@ static int btrfsic_read_block(struct btrfsic_state *state,
return block_ctx->len;
}
+static void btrfsic_complete_bio_end_io(struct bio *bio, int err)
+{
+ complete((struct completion *)bio->bi_private);
+}
+
static void btrfsic_dump_database(struct btrfsic_state *state)
{
struct list_head *elem_all;
@@ -1896,9 +1900,7 @@ again:
dev_state,
dev_bytenr);
}
- if (block->logical_bytenr != bytenr &&
- !(!block->is_metadata &&
- block->logical_bytenr == 0))
+ if (block->logical_bytenr != bytenr) {
printk(KERN_INFO
"Written block @%llu (%s/%llu/%d)"
" found in hash table, %c,"
@@ -1908,14 +1910,15 @@ again:
block->mirror_num,
btrfsic_get_block_type(state, block),
block->logical_bytenr);
- else if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
+ block->logical_bytenr = bytenr;
+ } else if (state->print_mask &
+ BTRFSIC_PRINT_MASK_VERBOSE)
printk(KERN_INFO
"Written block @%llu (%s/%llu/%d)"
" found in hash table, %c.\n",
bytenr, dev_state->name, dev_bytenr,
block->mirror_num,
btrfsic_get_block_type(state, block));
- block->logical_bytenr = bytenr;
} else {
if (num_pages * PAGE_CACHE_SIZE <
state->datablock_size) {
@@ -2460,8 +2463,10 @@ static int btrfsic_process_written_superblock(
}
}
- if (WARN_ON(-1 == btrfsic_check_all_ref_blocks(state, superblock, 0)))
+ if (-1 == btrfsic_check_all_ref_blocks(state, superblock, 0)) {
+ WARN_ON(1);
btrfsic_dump_tree(state);
+ }
return 0;
}
@@ -2901,7 +2906,7 @@ static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
btrfsic_release_block_ctx(&block_ctx);
}
- if (WARN_ON(!match)) {
+ if (!match) {
printk(KERN_INFO "btrfs: attempt to write M-block which contains logical bytenr that doesn't map to dev+physical bytenr of submit_bio,"
" buffer->log_bytenr=%llu, submit_bio(bdev=%s,"
" phys_bytenr=%llu)!\n",
@@ -2918,6 +2923,7 @@ static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
bytenr, block_ctx.dev->name,
block_ctx.dev_bytenr, mirror_num);
}
+ WARN_ON(1);
}
}
@@ -2994,12 +3000,14 @@ int btrfsic_submit_bh(int rw, struct buffer_head *bh)
return submit_bh(rw, bh);
}
-static void __btrfsic_submit_bio(int rw, struct bio *bio)
+void btrfsic_submit_bio(int rw, struct bio *bio)
{
struct btrfsic_dev_state *dev_state;
- if (!btrfsic_is_initialized)
+ if (!btrfsic_is_initialized) {
+ submit_bio(rw, bio);
return;
+ }
mutex_lock(&btrfsic_mutex);
/* since btrfsic_submit_bio() is also called before
@@ -3009,7 +3017,6 @@ static void __btrfsic_submit_bio(int rw, struct bio *bio)
(rw & WRITE) && NULL != bio->bi_io_vec) {
unsigned int i;
u64 dev_bytenr;
- u64 cur_bytenr;
int bio_is_patched;
char **mapped_datav;
@@ -3028,7 +3035,6 @@ static void __btrfsic_submit_bio(int rw, struct bio *bio)
GFP_NOFS);
if (!mapped_datav)
goto leave;
- cur_bytenr = dev_bytenr;
for (i = 0; i < bio->bi_vcnt; i++) {
BUG_ON(bio->bi_io_vec[i].bv_len != PAGE_CACHE_SIZE);
mapped_datav[i] = kmap(bio->bi_io_vec[i].bv_page);
@@ -3040,13 +3046,16 @@ static void __btrfsic_submit_bio(int rw, struct bio *bio)
kfree(mapped_datav);
goto leave;
}
- if (dev_state->state->print_mask &
- BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH_VERBOSE)
+ if ((BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH |
+ BTRFSIC_PRINT_MASK_VERBOSE) ==
+ (dev_state->state->print_mask &
+ (BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH |
+ BTRFSIC_PRINT_MASK_VERBOSE)))
printk(KERN_INFO
- "#%u: bytenr=%llu, len=%u, offset=%u\n",
- i, cur_bytenr, bio->bi_io_vec[i].bv_len,
+ "#%u: page=%p, len=%u, offset=%u\n",
+ i, bio->bi_io_vec[i].bv_page,
+ bio->bi_io_vec[i].bv_len,
bio->bi_io_vec[i].bv_offset);
- cur_bytenr += bio->bi_io_vec[i].bv_len;
}
btrfsic_process_written_block(dev_state, dev_bytenr,
mapped_datav, bio->bi_vcnt,
@@ -3090,20 +3099,10 @@ static void __btrfsic_submit_bio(int rw, struct bio *bio)
}
leave:
mutex_unlock(&btrfsic_mutex);
-}
-void btrfsic_submit_bio(int rw, struct bio *bio)
-{
- __btrfsic_submit_bio(rw, bio);
submit_bio(rw, bio);
}
-int btrfsic_submit_bio_wait(int rw, struct bio *bio)
-{
- __btrfsic_submit_bio(rw, bio);
- return submit_bio_wait(rw, bio);
-}
-
int btrfsic_mount(struct btrfs_root *root,
struct btrfs_fs_devices *fs_devices,
int including_extent_data, u32 print_mask)
diff --git a/fs/btrfs/check-integrity.h b/fs/btrfs/check-integrity.h
index 13b8566..8b59175 100644
--- a/fs/btrfs/check-integrity.h
+++ b/fs/btrfs/check-integrity.h
@@ -22,11 +22,9 @@
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
int btrfsic_submit_bh(int rw, struct buffer_head *bh);
void btrfsic_submit_bio(int rw, struct bio *bio);
-int btrfsic_submit_bio_wait(int rw, struct bio *bio);
#else
#define btrfsic_submit_bh submit_bh
#define btrfsic_submit_bio submit_bio
-#define btrfsic_submit_bio_wait submit_bio_wait
#endif
int btrfsic_mount(struct btrfs_root *root,
diff --git a/fs/btrfs/compat.h b/fs/btrfs/compat.h
new file mode 100644
index 0000000..7c4503e
--- /dev/null
+++ b/fs/btrfs/compat.h
@@ -0,0 +1,7 @@
+#ifndef _COMPAT_H_
+#define _COMPAT_H_
+
+#define btrfs_drop_nlink(inode) drop_nlink(inode)
+#define btrfs_inc_nlink(inode) inc_nlink(inode)
+
+#endif /* _COMPAT_H_ */
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index 1499b27..6aad98c 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -32,6 +32,7 @@
#include <linux/writeback.h>
#include <linux/bit_spinlock.h>
#include <linux/slab.h>
+#include "compat.h"
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
@@ -359,7 +360,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS);
- if (!bio) {
+ if(!bio) {
kfree(cb);
return -ENOMEM;
}
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 316136b..61b5bcd 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -274,7 +274,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
else
btrfs_set_header_owner(cow, new_root_objectid);
- write_extent_buffer(cow, root->fs_info->fsid, btrfs_header_fsid(),
+ write_extent_buffer(cow, root->fs_info->fsid, btrfs_header_fsid(cow),
BTRFS_FSID_SIZE);
WARN_ON(btrfs_header_generation(buf) > trans->transid);
@@ -996,7 +996,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
else
btrfs_set_header_owner(cow, root->root_key.objectid);
- write_extent_buffer(cow, root->fs_info->fsid, btrfs_header_fsid(),
+ write_extent_buffer(cow, root->fs_info->fsid, btrfs_header_fsid(cow),
BTRFS_FSID_SIZE);
ret = update_ref_for_cow(trans, root, buf, cow, &last_ref);
@@ -1285,10 +1285,11 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
free_extent_buffer(eb_root);
blocksize = btrfs_level_size(root, old_root->level);
old = read_tree_block(root, logical, blocksize, 0);
- if (WARN_ON(!old || !extent_buffer_uptodate(old))) {
+ if (!old || !extent_buffer_uptodate(old)) {
free_extent_buffer(old);
pr_warn("btrfs: failed to read tree block %llu from get_old_root\n",
logical);
+ WARN_ON(1);
} else {
eb = btrfs_clone_extent_buffer(old);
free_extent_buffer(old);
@@ -2757,7 +2758,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key,
int level;
int lowest_unlock = 1;
u8 lowest_level = 0;
- int prev_cmp = -1;
+ int prev_cmp;
lowest_level = p->lowest_level;
WARN_ON(p->nodes[0] != NULL);
@@ -2768,6 +2769,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key,
}
again:
+ prev_cmp = -1;
b = get_old_root(root, time_seq);
level = btrfs_header_level(b);
p->locks[level] = BTRFS_READ_LOCK;
@@ -2785,11 +2787,6 @@ again:
*/
btrfs_unlock_up_safe(p, level + 1);
- /*
- * Since we can unwind eb's we want to do a real search every
- * time.
- */
- prev_cmp = -1;
ret = key_search(b, key, level, &prev_cmp, &slot);
if (level != 0) {
@@ -3151,7 +3148,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV);
btrfs_set_header_owner(c, root->root_key.objectid);
- write_extent_buffer(c, root->fs_info->fsid, btrfs_header_fsid(),
+ write_extent_buffer(c, root->fs_info->fsid, btrfs_header_fsid(c),
BTRFS_FSID_SIZE);
write_extent_buffer(c, root->fs_info->chunk_tree_uuid,
@@ -3290,7 +3287,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
btrfs_set_header_backref_rev(split, BTRFS_MIXED_BACKREF_REV);
btrfs_set_header_owner(split, root->root_key.objectid);
write_extent_buffer(split, root->fs_info->fsid,
- btrfs_header_fsid(), BTRFS_FSID_SIZE);
+ btrfs_header_fsid(split), BTRFS_FSID_SIZE);
write_extent_buffer(split, root->fs_info->chunk_tree_uuid,
btrfs_header_chunk_tree_uuid(split),
BTRFS_UUID_SIZE);
@@ -3340,8 +3337,8 @@ static int leaf_space_used(struct extent_buffer *l, int start, int nr)
if (!nr)
return 0;
btrfs_init_map_token(&token);
- start_item = btrfs_item_nr(start);
- end_item = btrfs_item_nr(end);
+ start_item = btrfs_item_nr(l, start);
+ end_item = btrfs_item_nr(l, end);
data_len = btrfs_token_item_offset(l, start_item, &token) +
btrfs_token_item_size(l, start_item, &token);
data_len = data_len - btrfs_token_item_offset(l, end_item, &token);
@@ -3409,7 +3406,7 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
slot = path->slots[1];
i = left_nritems - 1;
while (i >= nr) {
- item = btrfs_item_nr(i);
+ item = btrfs_item_nr(left, i);
if (!empty && push_items > 0) {
if (path->slots[0] > i)
@@ -3473,7 +3470,7 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
btrfs_set_header_nritems(right, right_nritems);
push_space = BTRFS_LEAF_DATA_SIZE(root);
for (i = 0; i < right_nritems; i++) {
- item = btrfs_item_nr(i);
+ item = btrfs_item_nr(right, i);
push_space -= btrfs_token_item_size(right, item, &token);
btrfs_set_token_item_offset(right, item, push_space, &token);
}
@@ -3615,7 +3612,7 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
nr = min(right_nritems - 1, max_slot);
for (i = 0; i < nr; i++) {
- item = btrfs_item_nr(i);
+ item = btrfs_item_nr(right, i);
if (!empty && push_items > 0) {
if (path->slots[0] < i)
@@ -3642,7 +3639,8 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
ret = 1;
goto out;
}
- WARN_ON(!empty && push_items == btrfs_header_nritems(right));
+ if (!empty && push_items == btrfs_header_nritems(right))
+ WARN_ON(1);
/* push data from right to left */
copy_extent_buffer(left, right,
@@ -3665,7 +3663,7 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
for (i = old_left_nritems; i < old_left_nritems + push_items; i++) {
u32 ioff;
- item = btrfs_item_nr(i);
+ item = btrfs_item_nr(left, i);
ioff = btrfs_token_item_offset(left, item, &token);
btrfs_set_token_item_offset(left, item,
@@ -3696,7 +3694,7 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
btrfs_set_header_nritems(right, right_nritems);
push_space = BTRFS_LEAF_DATA_SIZE(root);
for (i = 0; i < right_nritems; i++) {
- item = btrfs_item_nr(i);
+ item = btrfs_item_nr(right, i);
push_space = push_space - btrfs_token_item_size(right,
item, &token);
@@ -3837,7 +3835,7 @@ static noinline void copy_for_split(struct btrfs_trans_handle *trans,
btrfs_item_end_nr(l, mid);
for (i = 0; i < nritems; i++) {
- struct btrfs_item *item = btrfs_item_nr(i);
+ struct btrfs_item *item = btrfs_item_nr(right, i);
u32 ioff;
ioff = btrfs_token_item_offset(right, item, &token);
@@ -4018,7 +4016,7 @@ again:
data_size > BTRFS_LEAF_DATA_SIZE(root)) {
if (data_size && !tried_avoid_double)
goto push_for_double;
- split = 2;
+ split = 2 ;
}
}
}
@@ -4044,7 +4042,7 @@ again:
btrfs_set_header_owner(right, root->root_key.objectid);
btrfs_set_header_level(right, 0);
write_extent_buffer(right, root->fs_info->fsid,
- btrfs_header_fsid(), BTRFS_FSID_SIZE);
+ btrfs_header_fsid(right), BTRFS_FSID_SIZE);
write_extent_buffer(right, root->fs_info->chunk_tree_uuid,
btrfs_header_chunk_tree_uuid(right),
@@ -4179,7 +4177,7 @@ static noinline int split_item(struct btrfs_trans_handle *trans,
btrfs_set_path_blocking(path);
- item = btrfs_item_nr(path->slots[0]);
+ item = btrfs_item_nr(leaf, path->slots[0]);
orig_offset = btrfs_item_offset(leaf, item);
item_size = btrfs_item_size(leaf, item);
@@ -4202,7 +4200,7 @@ static noinline int split_item(struct btrfs_trans_handle *trans,
btrfs_cpu_key_to_disk(&disk_key, new_key);
btrfs_set_item_key(leaf, &disk_key, slot);
- new_item = btrfs_item_nr(slot);
+ new_item = btrfs_item_nr(leaf, slot);
btrfs_set_item_offset(leaf, new_item, orig_offset);
btrfs_set_item_size(leaf, new_item, item_size - split_offset);
@@ -4341,7 +4339,7 @@ void btrfs_truncate_item(struct btrfs_root *root, struct btrfs_path *path,
/* first correct the data pointers */
for (i = slot; i < nritems; i++) {
u32 ioff;
- item = btrfs_item_nr(i);
+ item = btrfs_item_nr(leaf, i);
ioff = btrfs_token_item_offset(leaf, item, &token);
btrfs_set_token_item_offset(leaf, item,
@@ -4389,7 +4387,7 @@ void btrfs_truncate_item(struct btrfs_root *root, struct btrfs_path *path,
fixup_low_keys(root, path, &disk_key, 1);
}
- item = btrfs_item_nr(slot);
+ item = btrfs_item_nr(leaf, slot);
btrfs_set_item_size(leaf, item, new_size);
btrfs_mark_buffer_dirty(leaf);
@@ -4443,7 +4441,7 @@ void btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
/* first correct the data pointers */
for (i = slot; i < nritems; i++) {
u32 ioff;
- item = btrfs_item_nr(i);
+ item = btrfs_item_nr(leaf, i);
ioff = btrfs_token_item_offset(leaf, item, &token);
btrfs_set_token_item_offset(leaf, item,
@@ -4457,7 +4455,7 @@ void btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
data_end = old_data;
old_size = btrfs_item_size_nr(leaf, slot);
- item = btrfs_item_nr(slot);
+ item = btrfs_item_nr(leaf, slot);
btrfs_set_item_size(leaf, item, old_size + data_size);
btrfs_mark_buffer_dirty(leaf);
@@ -4516,7 +4514,7 @@ void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,
for (i = slot; i < nritems; i++) {
u32 ioff;
- item = btrfs_item_nr( i);
+ item = btrfs_item_nr(leaf, i);
ioff = btrfs_token_item_offset(leaf, item, &token);
btrfs_set_token_item_offset(leaf, item,
ioff - total_data, &token);
@@ -4537,7 +4535,7 @@ void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,
for (i = 0; i < nr; i++) {
btrfs_cpu_key_to_disk(&disk_key, cpu_key + i);
btrfs_set_item_key(leaf, &disk_key, slot + i);
- item = btrfs_item_nr(slot + i);
+ item = btrfs_item_nr(leaf, slot + i);
btrfs_set_token_item_offset(leaf, item,
data_end - data_size[i], &token);
data_end -= data_size[i];
@@ -4732,7 +4730,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
for (i = slot + nr; i < nritems; i++) {
u32 ioff;
- item = btrfs_item_nr(i);
+ item = btrfs_item_nr(leaf, i);
ioff = btrfs_token_item_offset(leaf, item, &token);
btrfs_set_token_item_offset(leaf, item,
ioff + dsize, &token);
@@ -4825,18 +4823,14 @@ static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
btrfs_item_key_to_cpu(path->nodes[0], &key, 0);
- if (key.offset > 0) {
+ if (key.offset > 0)
key.offset--;
- } else if (key.type > 0) {
+ else if (key.type > 0)
key.type--;
- key.offset = (u64)-1;
- } else if (key.objectid > 0) {
+ else if (key.objectid > 0)
key.objectid--;
- key.type = (u8)-1;
- key.offset = (u64)-1;
- } else {
+ else
return 1;
- }
btrfs_release_path(path);
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
@@ -4872,6 +4866,7 @@ static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
* was nothing in the tree that matched the search criteria.
*/
int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
+ struct btrfs_key *max_key,
struct btrfs_path *path,
u64 min_trans)
{
@@ -4916,8 +4911,10 @@ again:
* If it is too old, old, skip to the next one.
*/
while (slot < nritems) {
+ u64 blockptr;
u64 gen;
+ blockptr = btrfs_node_blockptr(cur, slot);
gen = btrfs_node_ptr_generation(cur, slot);
if (gen < min_trans) {
slot++;
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 54ab861..0506f40 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -47,12 +47,6 @@ extern struct kmem_cache *btrfs_path_cachep;
extern struct kmem_cache *btrfs_free_space_cachep;
struct btrfs_ordered_sum;
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-#define STATIC noinline
-#else
-#define STATIC static noinline
-#endif
-
#define BTRFS_MAGIC 0x4D5F53665248425FULL /* ascii _BHRfS_M, no null */
#define BTRFS_MAX_MIRRORS 3
@@ -1586,6 +1580,7 @@ struct btrfs_fs_info {
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;
struct btrfs_workers scrub_wr_completion_workers;
@@ -1729,9 +1724,7 @@ struct btrfs_root {
int ref_cows;
int track_dirty;
int in_radix;
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
- int dummy_root;
-#endif
+
u64 defrag_trans_start;
struct btrfs_key defrag_progress;
struct btrfs_key defrag_max;
@@ -2468,7 +2461,8 @@ static inline unsigned long btrfs_item_nr_offset(int nr)
sizeof(struct btrfs_item) * nr;
}
-static inline struct btrfs_item *btrfs_item_nr(int nr)
+static inline struct btrfs_item *btrfs_item_nr(struct extent_buffer *eb,
+ int nr)
{
return (struct btrfs_item *)btrfs_item_nr_offset(nr);
}
@@ -2481,30 +2475,30 @@ static inline u32 btrfs_item_end(struct extent_buffer *eb,
static inline u32 btrfs_item_end_nr(struct extent_buffer *eb, int nr)
{
- return btrfs_item_end(eb, btrfs_item_nr(nr));
+ return btrfs_item_end(eb, btrfs_item_nr(eb, nr));
}
static inline u32 btrfs_item_offset_nr(struct extent_buffer *eb, int nr)
{
- return btrfs_item_offset(eb, btrfs_item_nr(nr));
+ return btrfs_item_offset(eb, btrfs_item_nr(eb, nr));
}
static inline u32 btrfs_item_size_nr(struct extent_buffer *eb, int nr)
{
- return btrfs_item_size(eb, btrfs_item_nr(nr));
+ return btrfs_item_size(eb, btrfs_item_nr(eb, nr));
}
static inline void btrfs_item_key(struct extent_buffer *eb,
struct btrfs_disk_key *disk_key, int nr)
{
- struct btrfs_item *item = btrfs_item_nr(nr);
+ struct btrfs_item *item = btrfs_item_nr(eb, nr);
read_eb_member(eb, item, struct btrfs_item, key, disk_key);
}
static inline void btrfs_set_item_key(struct extent_buffer *eb,
struct btrfs_disk_key *disk_key, int nr)
{
- struct btrfs_item *item = btrfs_item_nr(nr);
+ struct btrfs_item *item = btrfs_item_nr(eb, nr);
write_eb_member(eb, item, struct btrfs_item, key, disk_key);
}
@@ -2672,7 +2666,7 @@ static inline void btrfs_set_header_backref_rev(struct extent_buffer *eb,
btrfs_set_header_flags(eb, flags);
}
-static inline unsigned long btrfs_header_fsid(void)
+static inline unsigned long btrfs_header_fsid(struct extent_buffer *eb)
{
return offsetof(struct btrfs_header, fsid);
}
@@ -3111,6 +3105,11 @@ static inline u32 btrfs_level_size(struct btrfs_root *root, int level)
((unsigned long)(btrfs_leaf_data(leaf) + \
btrfs_item_offset_nr(leaf, slot)))
+static inline struct dentry *fdentry(struct file *file)
+{
+ return file->f_path.dentry;
+}
+
static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info)
{
return ((space_info->flags & BTRFS_BLOCK_GROUP_METADATA) &&
@@ -3309,6 +3308,7 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
struct btrfs_key *key, int lowest_level,
u64 min_trans);
int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
+ struct btrfs_key *max_key,
struct btrfs_path *path,
u64 min_trans);
enum btrfs_compare_tree_result {
@@ -3613,6 +3613,9 @@ 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_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 search_commit);
/* inode.c */
@@ -3672,7 +3675,8 @@ 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_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput);
+int btrfs_start_all_delalloc_inodes(struct btrfs_fs_info *fs_info,
+ int delay_iput);
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
struct extent_state **cached_state);
int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
@@ -3741,6 +3745,9 @@ void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info);
int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync);
void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
int skip_pinned);
+int btrfs_replace_extent_cache(struct inode *inode, struct extent_map *replace,
+ u64 start, u64 end, int skip_pinned,
+ int modified);
extern const struct file_operations btrfs_file_operations;
int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode,
@@ -3937,7 +3944,9 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
u64 end, struct btrfs_scrub_progress *progress,
int readonly, int is_dev_replace);
void btrfs_scrub_pause(struct btrfs_root *root);
+void btrfs_scrub_pause_super(struct btrfs_root *root);
void btrfs_scrub_continue(struct btrfs_root *root);
+void btrfs_scrub_continue_super(struct btrfs_root *root);
int btrfs_scrub_cancel(struct btrfs_fs_info *info);
int btrfs_scrub_cancel_dev(struct btrfs_fs_info *info,
struct btrfs_device *dev);
@@ -4019,9 +4028,5 @@ static inline int btrfs_defrag_cancelled(struct btrfs_fs_info *fs_info)
return signal_pending(current);
}
-/* Sanity test specific functions */
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-void btrfs_test_destroy_inode(struct inode *inode);
-#endif
#endif
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index 8d292fb..cbd9523 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -108,8 +108,8 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node(struct inode *inode)
return node;
}
btrfs_inode->delayed_node = node;
- /* can be accessed and cached in the inode */
- atomic_add(2, &node->refs);
+ atomic_inc(&node->refs); /* can be accessed */
+ atomic_inc(&node->refs); /* cached in the inode */
spin_unlock(&root->inode_lock);
return node;
}
@@ -138,8 +138,8 @@ again:
return ERR_PTR(-ENOMEM);
btrfs_init_delayed_node(node, root, ino);
- /* cached in the btrfs inode and can be accessed */
- atomic_add(2, &node->refs);
+ atomic_inc(&node->refs); /* cached in the btrfs inode */
+ atomic_inc(&node->refs); /* can be accessed */
ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM);
if (ret) {
@@ -649,13 +649,14 @@ static int btrfs_delayed_inode_reserve_metadata(
goto out;
ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
- if (!WARN_ON(ret))
+ if (!ret)
goto out;
/*
* Ok this is a problem, let's just steal from the global rsv
* since this really shouldn't happen that often.
*/
+ WARN_ON(1);
ret = btrfs_block_rsv_migrate(&root->fs_info->global_block_rsv,
dst_rsv, num_bytes);
goto out;
@@ -770,13 +771,13 @@ static int btrfs_batch_insert_items(struct btrfs_root *root,
*/
btrfs_set_path_blocking(path);
- keys = kmalloc_array(nitems, sizeof(struct btrfs_key), GFP_NOFS);
+ keys = kmalloc(sizeof(struct btrfs_key) * nitems, GFP_NOFS);
if (!keys) {
ret = -ENOMEM;
goto out;
}
- data_size = kmalloc_array(nitems, sizeof(u32), GFP_NOFS);
+ data_size = kmalloc(sizeof(u32) * nitems, GFP_NOFS);
if (!data_size) {
ret = -ENOMEM;
goto error;
@@ -1173,10 +1174,8 @@ int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
mutex_unlock(&delayed_node->mutex);
path = btrfs_alloc_path();
- if (!path) {
- btrfs_release_delayed_node(delayed_node);
+ if (!path)
return -ENOMEM;
- }
path->leave_spinning = 1;
block_rsv = trans->block_rsv;
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index 2cfc3df..9efb94e 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -26,6 +26,7 @@
#include <linux/kthread.h>
#include <linux/math64.h>
#include <asm/div64.h>
+#include "compat.h"
#include "ctree.h"
#include "extent_map.h"
#include "disk-io.h"
@@ -37,6 +38,7 @@
#include "rcu-string.h"
#include "dev-replace.h"
+static u64 btrfs_get_seconds_since_1970(void);
static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
int scrub_ret);
static void btrfs_dev_replace_update_device_in_mapping_tree(
@@ -294,6 +296,13 @@ void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info)
dev_replace->cursor_left_last_write_of_item;
}
+static u64 btrfs_get_seconds_since_1970(void)
+{
+ struct timespec t = CURRENT_TIME_SEC;
+
+ return t.tv_sec;
+}
+
int btrfs_dev_replace_start(struct btrfs_root *root,
struct btrfs_ioctl_dev_replace_args *args)
{
@@ -366,7 +375,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
dev_replace->tgtdev = tgt_device;
printk_in_rcu(KERN_INFO
- "btrfs: dev_replace from %s (devid %llu) to %s started\n",
+ "btrfs: dev_replace from %s (devid %llu) to %s) started\n",
src_device->missing ? "<missing disk>" :
rcu_str_deref(src_device->name),
src_device->devid,
@@ -381,7 +390,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
* go to the tgtdev as well (refer to btrfs_map_block()).
*/
dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED;
- dev_replace->time_started = get_seconds();
+ dev_replace->time_started = btrfs_get_seconds_since_1970();
dev_replace->cursor_left = 0;
dev_replace->committed_cursor_left = 0;
dev_replace->cursor_left_last_write_of_item = 0;
@@ -391,7 +400,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
btrfs_dev_replace_unlock(dev_replace);
- btrfs_wait_ordered_roots(root->fs_info, -1);
+ btrfs_wait_all_ordered_extents(root->fs_info);
/* force writing the updated state information to disk */
trans = btrfs_start_transaction(root, 0);
@@ -461,12 +470,12 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
* flush all outstanding I/O and inode extent mappings before the
* copy operation is declared as being finished
*/
- ret = btrfs_start_delalloc_roots(root->fs_info, 0);
+ ret = btrfs_start_all_delalloc_inodes(root->fs_info, 0);
if (ret) {
mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
return ret;
}
- btrfs_wait_ordered_roots(root->fs_info, -1);
+ btrfs_wait_all_ordered_extents(root->fs_info);
trans = btrfs_start_transaction(root, 0);
if (IS_ERR(trans)) {
@@ -484,7 +493,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
: BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED;
dev_replace->tgtdev = NULL;
dev_replace->srcdev = NULL;
- dev_replace->time_stopped = get_seconds();
+ dev_replace->time_stopped = btrfs_get_seconds_since_1970();
dev_replace->item_needs_writeback = 1;
if (scrub_ret) {
@@ -641,9 +650,6 @@ static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
u64 result;
int ret;
- if (fs_info->sb->s_flags & MS_RDONLY)
- return -EROFS;
-
mutex_lock(&dev_replace->lock_finishing_cancel_unmount);
btrfs_dev_replace_lock(dev_replace);
switch (dev_replace->replace_state) {
@@ -662,7 +668,7 @@ static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
break;
}
dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED;
- dev_replace->time_stopped = get_seconds();
+ dev_replace->time_stopped = btrfs_get_seconds_since_1970();
dev_replace->item_needs_writeback = 1;
btrfs_dev_replace_unlock(dev_replace);
btrfs_scrub_cancel(fs_info);
@@ -697,7 +703,7 @@ void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info)
case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
dev_replace->replace_state =
BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED;
- dev_replace->time_stopped = get_seconds();
+ dev_replace->time_stopped = btrfs_get_seconds_since_1970();
dev_replace->item_needs_writeback = 1;
pr_info("btrfs: suspending dev_replace for unmount\n");
break;
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c
index c031ea3..79e594e 100644
--- a/fs/btrfs/dir-item.c
+++ b/fs/btrfs/dir-item.c
@@ -58,7 +58,7 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
return ERR_PTR(ret);
WARN_ON(ret > 0);
leaf = path->nodes[0];
- item = btrfs_item_nr(path->slots[0]);
+ item = btrfs_item_nr(leaf, path->slots[0]);
ptr = btrfs_item_ptr(leaf, path->slots[0], char);
BUG_ON(data_size > btrfs_item_size(leaf, item));
ptr += btrfs_item_size(leaf, item) - data_size;
@@ -474,10 +474,8 @@ int verify_dir_item(struct btrfs_root *root,
}
/* BTRFS_MAX_XATTR_SIZE is the same for all dir items */
- if ((btrfs_dir_data_len(leaf, dir_item) +
- btrfs_dir_name_len(leaf, dir_item)) > BTRFS_MAX_XATTR_SIZE(root)) {
- printk(KERN_CRIT "btrfs: invalid dir item name + data len: %u + %u\n",
- (unsigned)btrfs_dir_name_len(leaf, dir_item),
+ if (btrfs_dir_data_len(leaf, dir_item) > BTRFS_MAX_XATTR_SIZE(root)) {
+ printk(KERN_CRIT "btrfs: invalid dir item data len: %u\n",
(unsigned)btrfs_dir_data_len(leaf, dir_item));
return 1;
}
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 8072cfa..62176ad 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -33,6 +33,7 @@
#include <linux/uuid.h>
#include <linux/semaphore.h>
#include <asm/unaligned.h>
+#include "compat.h"
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
@@ -63,6 +64,7 @@ static void btrfs_destroy_ordered_operations(struct btrfs_transaction *t,
static void btrfs_destroy_ordered_extents(struct btrfs_root *root);
static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
struct btrfs_root *root);
+static void btrfs_evict_pending_snapshots(struct btrfs_transaction *t);
static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root);
static int btrfs_destroy_marked_extents(struct btrfs_root *root,
struct extent_io_tree *dirty_pages,
@@ -475,8 +477,14 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
if (page != eb->pages[0])
return 0;
found_start = btrfs_header_bytenr(eb);
- if (WARN_ON(found_start != start || !PageUptodate(page)))
+ if (found_start != start) {
+ WARN_ON(1);
return 0;
+ }
+ if (!PageUptodate(page)) {
+ WARN_ON(1);
+ return 0;
+ }
csum_tree_block(root, eb, 0);
return 0;
}
@@ -488,7 +496,7 @@ static int check_tree_block_fsid(struct btrfs_root *root,
u8 fsid[BTRFS_UUID_SIZE];
int ret = 1;
- read_extent_buffer(eb, fsid, btrfs_header_fsid(), BTRFS_FSID_SIZE);
+ read_extent_buffer(eb, fsid, btrfs_header_fsid(eb), BTRFS_FSID_SIZE);
while (fs_devices) {
if (!memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE)) {
ret = 0;
@@ -1097,7 +1105,8 @@ 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);
+ eb = find_extent_buffer(&BTRFS_I(btree_inode)->io_tree,
+ bytenr, blocksize);
return eb;
}
@@ -1220,18 +1229,14 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
atomic_set(&root->refs, 1);
root->log_transid = 0;
root->last_log_commit = 0;
- if (fs_info)
- extent_io_tree_init(&root->dirty_log_pages,
- fs_info->btree_inode->i_mapping);
+ extent_io_tree_init(&root->dirty_log_pages,
+ fs_info->btree_inode->i_mapping);
memset(&root->root_key, 0, sizeof(root->root_key));
memset(&root->root_item, 0, sizeof(root->root_item));
memset(&root->defrag_progress, 0, sizeof(root->defrag_progress));
memset(&root->root_kobj, 0, sizeof(root->root_kobj));
- if (fs_info)
- root->defrag_trans_start = fs_info->generation;
- else
- root->defrag_trans_start = 0;
+ root->defrag_trans_start = fs_info->generation;
init_completion(&root->kobj_unregister);
root->defrag_running = 0;
root->root_key.objectid = objectid;
@@ -1248,22 +1253,6 @@ static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info)
return root;
}
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-/* Should only be used by the testing infrastructure */
-struct btrfs_root *btrfs_alloc_dummy_root(void)
-{
- struct btrfs_root *root;
-
- root = btrfs_alloc_root(NULL);
- if (!root)
- return ERR_PTR(-ENOMEM);
- __setup_root(4096, 4096, 4096, 4096, root, NULL, 1);
- root->dummy_root = 1;
-
- return root;
-}
-#endif
-
struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info,
u64 objectid)
@@ -1303,7 +1292,7 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
btrfs_set_header_owner(leaf, objectid);
root->node = leaf;
- write_extent_buffer(leaf, fs_info->fsid, btrfs_header_fsid(),
+ write_extent_buffer(leaf, fs_info->fsid, btrfs_header_fsid(leaf),
BTRFS_FSID_SIZE);
write_extent_buffer(leaf, fs_info->chunk_tree_uuid,
btrfs_header_chunk_tree_uuid(leaf),
@@ -1390,7 +1379,7 @@ static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
root->node = leaf;
write_extent_buffer(root->node, root->fs_info->fsid,
- btrfs_header_fsid(), BTRFS_FSID_SIZE);
+ btrfs_header_fsid(root->node), BTRFS_FSID_SIZE);
btrfs_mark_buffer_dirty(root->node);
btrfs_tree_unlock(root->node);
return root;
@@ -1791,9 +1780,6 @@ sleep:
wake_up_process(root->fs_info->cleaner_kthread);
mutex_unlock(&root->fs_info->transaction_kthread_mutex);
- if (unlikely(test_bit(BTRFS_FS_STATE_ERROR,
- &root->fs_info->fs_state)))
- btrfs_cleanup_transaction(root);
if (!try_to_freeze()) {
set_current_state(TASK_INTERRUPTIBLE);
if (!kthread_should_stop() &&
@@ -2027,28 +2013,50 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info)
btrfs_stop_workers(&fs_info->qgroup_rescan_workers);
}
-static void free_root_extent_buffers(struct btrfs_root *root)
-{
- if (root) {
- free_extent_buffer(root->node);
- free_extent_buffer(root->commit_root);
- root->node = NULL;
- root->commit_root = NULL;
- }
-}
-
/* helper to cleanup tree roots */
static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
{
- free_root_extent_buffers(info->tree_root);
-
- free_root_extent_buffers(info->dev_root);
- free_root_extent_buffers(info->extent_root);
- free_root_extent_buffers(info->csum_root);
- free_root_extent_buffers(info->quota_root);
- free_root_extent_buffers(info->uuid_root);
- if (chunk_root)
- free_root_extent_buffers(info->chunk_root);
+ free_extent_buffer(info->tree_root->node);
+ free_extent_buffer(info->tree_root->commit_root);
+ info->tree_root->node = NULL;
+ info->tree_root->commit_root = NULL;
+
+ if (info->dev_root) {
+ free_extent_buffer(info->dev_root->node);
+ free_extent_buffer(info->dev_root->commit_root);
+ info->dev_root->node = NULL;
+ info->dev_root->commit_root = NULL;
+ }
+ if (info->extent_root) {
+ free_extent_buffer(info->extent_root->node);
+ free_extent_buffer(info->extent_root->commit_root);
+ info->extent_root->node = NULL;
+ info->extent_root->commit_root = NULL;
+ }
+ if (info->csum_root) {
+ free_extent_buffer(info->csum_root->node);
+ free_extent_buffer(info->csum_root->commit_root);
+ info->csum_root->node = NULL;
+ info->csum_root->commit_root = NULL;
+ }
+ if (info->quota_root) {
+ free_extent_buffer(info->quota_root->node);
+ free_extent_buffer(info->quota_root->commit_root);
+ info->quota_root->node = NULL;
+ info->quota_root->commit_root = NULL;
+ }
+ if (info->uuid_root) {
+ free_extent_buffer(info->uuid_root->node);
+ free_extent_buffer(info->uuid_root->commit_root);
+ info->uuid_root->node = NULL;
+ info->uuid_root->commit_root = NULL;
+ }
+ if (chunk_root) {
+ free_extent_buffer(info->chunk_root->node);
+ free_extent_buffer(info->chunk_root->commit_root);
+ info->chunk_root->node = NULL;
+ info->chunk_root->commit_root = NULL;
+ }
}
static void del_fs_roots(struct btrfs_fs_info *fs_info)
@@ -2222,6 +2230,7 @@ int open_ctree(struct super_block *sb,
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;
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
fs_info->check_integrity_print_mask = 0;
@@ -2263,7 +2272,7 @@ int open_ctree(struct super_block *sb,
sizeof(struct btrfs_key));
set_bit(BTRFS_INODE_DUMMY,
&BTRFS_I(fs_info->btree_inode)->runtime_flags);
- btrfs_insert_inode_hash(fs_info->btree_inode);
+ insert_inode_hash(fs_info->btree_inode);
spin_lock_init(&fs_info->block_group_cache_lock);
fs_info->block_group_cache_tree = RB_ROOT;
@@ -2661,7 +2670,6 @@ retry_root_backup:
btrfs_set_root_node(&tree_root->root_item, tree_root->node);
tree_root->commit_root = btrfs_root_node(tree_root);
- btrfs_set_root_refs(&tree_root->root_item, 1);
location.objectid = BTRFS_EXTENT_TREE_OBJECTID;
location.type = BTRFS_ROOT_ITEM_KEY;
@@ -3440,7 +3448,10 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
int write_ctree_super(struct btrfs_trans_handle *trans,
struct btrfs_root *root, int max_mirrors)
{
- return write_all_supers(root, max_mirrors);
+ int ret;
+
+ ret = write_all_supers(root, max_mirrors);
+ return ret;
}
/* Drop a fs root from the radix tree and free it. */
@@ -3517,6 +3528,7 @@ int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
int btrfs_commit_super(struct btrfs_root *root)
{
struct btrfs_trans_handle *trans;
+ int ret;
mutex_lock(&root->fs_info->cleaner_mutex);
btrfs_run_delayed_iputs(root);
@@ -3530,7 +3542,25 @@ int btrfs_commit_super(struct btrfs_root *root)
trans = btrfs_join_transaction(root);
if (IS_ERR(trans))
return PTR_ERR(trans);
- return btrfs_commit_transaction(trans, root);
+ ret = btrfs_commit_transaction(trans, root);
+ if (ret)
+ return ret;
+ /* run commit again to drop the original snapshot */
+ trans = btrfs_join_transaction(root);
+ if (IS_ERR(trans))
+ return PTR_ERR(trans);
+ ret = btrfs_commit_transaction(trans, root);
+ if (ret)
+ return ret;
+ ret = btrfs_write_and_wait_transaction(NULL, root);
+ if (ret) {
+ btrfs_error(root->fs_info, ret,
+ "Failed to sync btree inode to disk.");
+ return ret;
+ }
+
+ ret = write_ctree_super(NULL, root, 0);
+ return ret;
}
int close_ctree(struct btrfs_root *root)
@@ -3584,12 +3614,12 @@ int close_ctree(struct btrfs_root *root)
percpu_counter_sum(&fs_info->delalloc_bytes));
}
- del_fs_roots(fs_info);
-
btrfs_free_block_groups(fs_info);
btrfs_stop_all_workers(fs_info);
+ del_fs_roots(fs_info);
+
free_root_pointers(fs_info, 1);
iput(fs_info->btree_inode);
@@ -3639,20 +3669,10 @@ int btrfs_set_buffer_uptodate(struct extent_buffer *buf)
void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
{
- struct btrfs_root *root;
+ struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
u64 transid = btrfs_header_generation(buf);
int was_dirty;
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
- /*
- * This is a fast path so only do this check if we have sanity tests
- * enabled. Normal people shouldn't be marking dummy buffers as dirty
- * outside of the sanity tests.
- */
- if (unlikely(test_bit(EXTENT_BUFFER_DUMMY, &buf->bflags)))
- return;
-#endif
- root = BTRFS_I(buf->pages[0]->mapping->host)->root;
btrfs_assert_tree_locked(buf);
if (transid != root->fs_info->generation)
WARN(1, KERN_CRIT "btrfs transid mismatch buffer %llu, "
@@ -3782,8 +3802,7 @@ static void btrfs_destroy_all_ordered_extents(struct btrfs_fs_info *fs_info)
while (!list_empty(&splice)) {
root = list_first_entry(&splice, struct btrfs_root,
ordered_root);
- list_move_tail(&root->ordered_root,
- &fs_info->ordered_roots);
+ list_del_init(&root->ordered_root);
btrfs_destroy_ordered_extents(root);
@@ -3861,6 +3880,24 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
return ret;
}
+static void btrfs_evict_pending_snapshots(struct btrfs_transaction *t)
+{
+ struct btrfs_pending_snapshot *snapshot;
+ struct list_head splice;
+
+ INIT_LIST_HEAD(&splice);
+
+ list_splice_init(&t->pending_snapshots, &splice);
+
+ while (!list_empty(&splice)) {
+ snapshot = list_entry(splice.next,
+ struct btrfs_pending_snapshot,
+ list);
+ snapshot->error = -ECANCELED;
+ list_del_init(&snapshot->list);
+ }
+}
+
static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
{
struct btrfs_inode *btrfs_inode;
@@ -3990,13 +4027,15 @@ again:
void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
struct btrfs_root *root)
{
- btrfs_destroy_ordered_operations(cur_trans, root);
-
btrfs_destroy_delayed_refs(cur_trans, root);
+ btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv,
+ cur_trans->dirty_pages.dirty_bytes);
cur_trans->state = TRANS_STATE_COMMIT_START;
wake_up(&root->fs_info->transaction_blocked_wait);
+ btrfs_evict_pending_snapshots(cur_trans);
+
cur_trans->state = TRANS_STATE_UNBLOCKED;
wake_up(&root->fs_info->transaction_wait);
@@ -4020,51 +4059,63 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
static int btrfs_cleanup_transaction(struct btrfs_root *root)
{
struct btrfs_transaction *t;
+ LIST_HEAD(list);
mutex_lock(&root->fs_info->transaction_kthread_mutex);
spin_lock(&root->fs_info->trans_lock);
- while (!list_empty(&root->fs_info->trans_list)) {
- t = list_first_entry(&root->fs_info->trans_list,
- struct btrfs_transaction, list);
- if (t->state >= TRANS_STATE_COMMIT_START) {
- atomic_inc(&t->use_count);
- spin_unlock(&root->fs_info->trans_lock);
- btrfs_wait_for_commit(root, t->transid);
- btrfs_put_transaction(t);
- spin_lock(&root->fs_info->trans_lock);
- continue;
- }
- if (t == root->fs_info->running_transaction) {
- t->state = TRANS_STATE_COMMIT_DOING;
- spin_unlock(&root->fs_info->trans_lock);
- /*
- * We wait for 0 num_writers since we don't hold a trans
- * handle open currently for this transaction.
- */
- wait_event(t->writer_wait,
- atomic_read(&t->num_writers) == 0);
- } else {
- spin_unlock(&root->fs_info->trans_lock);
- }
- btrfs_cleanup_one_transaction(t, root);
+ list_splice_init(&root->fs_info->trans_list, &list);
+ root->fs_info->running_transaction = NULL;
+ spin_unlock(&root->fs_info->trans_lock);
- spin_lock(&root->fs_info->trans_lock);
- if (t == root->fs_info->running_transaction)
- root->fs_info->running_transaction = NULL;
- list_del_init(&t->list);
- spin_unlock(&root->fs_info->trans_lock);
+ while (!list_empty(&list)) {
+ t = list_entry(list.next, struct btrfs_transaction, list);
- btrfs_put_transaction(t);
- trace_btrfs_transaction_commit(root);
- spin_lock(&root->fs_info->trans_lock);
+ btrfs_destroy_ordered_operations(t, root);
+
+ btrfs_destroy_all_ordered_extents(root->fs_info);
+
+ btrfs_destroy_delayed_refs(t, root);
+
+ /*
+ * FIXME: cleanup wait for commit
+ * We needn't acquire the lock here, because we are during
+ * the umount, there is no other task which will change it.
+ */
+ t->state = TRANS_STATE_COMMIT_START;
+ smp_mb();
+ if (waitqueue_active(&root->fs_info->transaction_blocked_wait))
+ wake_up(&root->fs_info->transaction_blocked_wait);
+
+ btrfs_evict_pending_snapshots(t);
+
+ t->state = TRANS_STATE_UNBLOCKED;
+ smp_mb();
+ if (waitqueue_active(&root->fs_info->transaction_wait))
+ wake_up(&root->fs_info->transaction_wait);
+
+ btrfs_destroy_delayed_inodes(root);
+ btrfs_assert_delayed_root_empty(root);
+
+ btrfs_destroy_all_delalloc_inodes(root->fs_info);
+
+ btrfs_destroy_marked_extents(root, &t->dirty_pages,
+ EXTENT_DIRTY);
+
+ btrfs_destroy_pinned_extent(root,
+ root->fs_info->pinned_extents);
+
+ t->state = TRANS_STATE_COMPLETED;
+ smp_mb();
+ if (waitqueue_active(&t->commit_wait))
+ wake_up(&t->commit_wait);
+
+ atomic_set(&t->use_count, 0);
+ list_del_init(&t->list);
+ memset(t, 0, sizeof(*t));
+ kmem_cache_free(btrfs_transaction_cachep, t);
}
- spin_unlock(&root->fs_info->trans_lock);
- btrfs_destroy_all_ordered_extents(root->fs_info);
- btrfs_destroy_delayed_inodes(root);
- btrfs_assert_delayed_root_empty(root);
- btrfs_destroy_pinned_extent(root, root->fs_info->pinned_extents);
- btrfs_destroy_all_delalloc_inodes(root->fs_info);
+
mutex_unlock(&root->fs_info->transaction_kthread_mutex);
return 0;
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index 53059df..5ce2a7d 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -86,10 +86,6 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_root *root);
void btrfs_free_fs_root(struct btrfs_root *root);
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-struct btrfs_root *btrfs_alloc_dummy_root(void);
-#endif
-
/*
* This function is used to grab the root, and avoid it is freed when we
* access it. But it doesn't ensure that the tree is not dropped.
diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c
index 41422a3..4b86916 100644
--- a/fs/btrfs/export.c
+++ b/fs/btrfs/export.c
@@ -5,6 +5,7 @@
#include "btrfs_inode.h"
#include "print-tree.h"
#include "export.h"
+#include "compat.h"
#define BTRFS_FID_SIZE_NON_CONNECTABLE (offsetof(struct btrfs_fid, \
parent_objectid) / 4)
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 45d98d0..d58bef1 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/ratelimit.h>
#include <linux/percpu_counter.h>
+#include "compat.h"
#include "hash.h"
#include "ctree.h"
#include "disk-io.h"
@@ -1550,8 +1551,9 @@ again:
if (ret && !insert) {
err = -ENOENT;
goto out;
- } else if (WARN_ON(ret)) {
+ } else if (ret) {
err = -EIO;
+ WARN_ON(1);
goto out;
}
@@ -1977,6 +1979,7 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
struct btrfs_extent_item *item;
u64 refs;
int ret;
+ int err = 0;
path = btrfs_alloc_path();
if (!path)
@@ -1989,9 +1992,14 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
path, bytenr, num_bytes, parent,
root_objectid, owner, offset,
refs_to_add, extent_op);
- if (ret != -EAGAIN)
+ if (ret == 0)
goto out;
+ if (ret != -EAGAIN) {
+ err = ret;
+ goto out;
+ }
+
leaf = path->nodes[0];
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
refs = btrfs_extent_refs(leaf, item);
@@ -2013,7 +2021,7 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
btrfs_abort_transaction(trans, root, ret);
out:
btrfs_free_path(path);
- return ret;
+ return err;
}
static int run_delayed_data_ref(struct btrfs_trans_handle *trans,
@@ -2129,28 +2137,15 @@ again:
}
if (ret > 0) {
if (metadata) {
- if (path->slots[0] > 0) {
- path->slots[0]--;
- btrfs_item_key_to_cpu(path->nodes[0], &key,
- path->slots[0]);
- if (key.objectid == node->bytenr &&
- key.type == BTRFS_EXTENT_ITEM_KEY &&
- key.offset == node->num_bytes)
- ret = 0;
- }
- if (ret > 0) {
- btrfs_release_path(path);
- metadata = 0;
+ btrfs_release_path(path);
+ metadata = 0;
- key.objectid = node->bytenr;
- key.offset = node->num_bytes;
- key.type = BTRFS_EXTENT_ITEM_KEY;
- goto again;
- }
- } else {
- err = -EIO;
- goto out;
+ key.offset = node->num_bytes;
+ key.type = BTRFS_EXTENT_ITEM_KEY;
+ goto again;
}
+ err = -EIO;
+ goto out;
}
leaf = path->nodes[0];
@@ -2239,12 +2234,8 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
{
int ret = 0;
- if (trans->aborted) {
- if (insert_reserved)
- btrfs_pin_extent(root, node->bytenr,
- node->num_bytes, 1);
+ if (trans->aborted)
return 0;
- }
if (btrfs_delayed_ref_is_head(node)) {
struct btrfs_delayed_ref_head *head;
@@ -2420,14 +2411,6 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
btrfs_free_delayed_extent_op(extent_op);
if (ret) {
- /*
- * Need to reset must_insert_reserved if
- * there was an error so the abort stuff
- * can cleanup the reserved space
- * properly.
- */
- if (must_insert_reserved)
- locked_ref->must_insert_reserved = 1;
btrfs_debug(fs_info, "run_delayed_extent_op returned %d", ret);
spin_lock(&delayed_refs->lock);
btrfs_delayed_ref_unlock(locked_ref);
@@ -3214,7 +3197,8 @@ again:
if (ret)
goto out_put;
- ret = btrfs_truncate_free_space_cache(root, trans, inode);
+ ret = btrfs_truncate_free_space_cache(root, trans, path,
+ inode);
if (ret)
goto out_put;
}
@@ -3334,9 +3318,10 @@ again:
last = cache->key.objectid + cache->key.offset;
err = write_one_cache_group(trans, root, path, cache);
- btrfs_put_block_group(cache);
if (err) /* File system offline */
goto out;
+
+ btrfs_put_block_group(cache);
}
while (1) {
@@ -3620,9 +3605,10 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes)
/* make sure bytes are sectorsize aligned */
bytes = ALIGN(bytes, root->sectorsize);
- if (btrfs_is_free_space_inode(inode)) {
+ if (root == root->fs_info->tree_root ||
+ BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID) {
+ alloc_chunk = 0;
committed = 1;
- ASSERT(current->journal_info);
}
data_sinfo = fs_info->data_sinfo;
@@ -3650,16 +3636,6 @@ again:
spin_unlock(&data_sinfo->lock);
alloc:
alloc_target = btrfs_get_alloc_profile(root, 1);
- /*
- * It is ugly that we don't call nolock join
- * transaction for the free space inode case here.
- * But it is safe because we only do the data space
- * reservation for the free space cache in the
- * transaction context, the common join transaction
- * just increase the counter of the current transaction
- * handler, doesn't try to acquire the trans_lock of
- * the fs.
- */
trans = btrfs_join_transaction(root);
if (IS_ERR(trans))
return PTR_ERR(trans);
@@ -3705,9 +3681,6 @@ commit_trans:
goto again;
}
- trace_btrfs_space_reservation(root->fs_info,
- "space_info:enospc",
- data_sinfo->flags, bytes, 1);
return -ENOSPC;
}
data_sinfo->bytes_may_use += bytes;
@@ -4016,26 +3989,12 @@ static void btrfs_writeback_inodes_sb_nr(struct btrfs_root *root,
* the filesystem is readonly(all dirty pages are written to
* the disk).
*/
- btrfs_start_delalloc_roots(root->fs_info, 0);
+ btrfs_start_all_delalloc_inodes(root->fs_info, 0);
if (!current->journal_info)
- btrfs_wait_ordered_roots(root->fs_info, -1);
+ btrfs_wait_all_ordered_extents(root->fs_info);
}
}
-static inline int calc_reclaim_items_nr(struct btrfs_root *root, u64 to_reclaim)
-{
- u64 bytes;
- int nr;
-
- bytes = btrfs_calc_trans_metadata_size(root, 1);
- nr = (int)div64_u64(to_reclaim, bytes);
- if (!nr)
- nr = 1;
- return nr;
-}
-
-#define EXTENT_SIZE_PER_ITEM (256 * 1024)
-
/*
* shrink metadata reservation for delalloc
*/
@@ -4048,30 +4007,24 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
u64 delalloc_bytes;
u64 max_reclaim;
long time_left;
- unsigned long nr_pages;
- int loops;
- int items;
+ unsigned long nr_pages = (2 * 1024 * 1024) >> PAGE_CACHE_SHIFT;
+ int loops = 0;
enum btrfs_reserve_flush_enum flush;
- /* Calc the number of the pages we need flush for space reservation */
- items = calc_reclaim_items_nr(root, to_reclaim);
- to_reclaim = items * EXTENT_SIZE_PER_ITEM;
-
trans = (struct btrfs_trans_handle *)current->journal_info;
block_rsv = &root->fs_info->delalloc_block_rsv;
space_info = block_rsv->space_info;
+ smp_mb();
delalloc_bytes = percpu_counter_sum_positive(
&root->fs_info->delalloc_bytes);
if (delalloc_bytes == 0) {
if (trans)
return;
- if (wait_ordered)
- btrfs_wait_ordered_roots(root->fs_info, items);
+ btrfs_wait_all_ordered_extents(root->fs_info);
return;
}
- loops = 0;
while (delalloc_bytes && loops < 3) {
max_reclaim = min(delalloc_bytes, to_reclaim);
nr_pages = max_reclaim >> PAGE_CACHE_SHIFT;
@@ -4080,19 +4033,9 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
* We need to wait for the async pages to actually start before
* we do anything.
*/
- max_reclaim = atomic_read(&root->fs_info->async_delalloc_pages);
- if (!max_reclaim)
- goto skip_async;
-
- if (max_reclaim <= nr_pages)
- max_reclaim = 0;
- else
- max_reclaim -= nr_pages;
-
wait_event(root->fs_info->async_submit_wait,
- atomic_read(&root->fs_info->async_delalloc_pages) <=
- (int)max_reclaim);
-skip_async:
+ !atomic_read(&root->fs_info->async_delalloc_pages));
+
if (!trans)
flush = BTRFS_RESERVE_FLUSH_ALL;
else
@@ -4106,12 +4049,13 @@ skip_async:
loops++;
if (wait_ordered && !trans) {
- btrfs_wait_ordered_roots(root->fs_info, items);
+ btrfs_wait_all_ordered_extents(root->fs_info);
} else {
time_left = schedule_timeout_killable(1);
if (time_left)
break;
}
+ smp_mb();
delalloc_bytes = percpu_counter_sum_positive(
&root->fs_info->delalloc_bytes);
}
@@ -4196,11 +4140,16 @@ static int flush_space(struct btrfs_root *root,
switch (state) {
case FLUSH_DELAYED_ITEMS_NR:
case FLUSH_DELAYED_ITEMS:
- if (state == FLUSH_DELAYED_ITEMS_NR)
- nr = calc_reclaim_items_nr(root, num_bytes) * 2;
- else
- nr = -1;
+ if (state == FLUSH_DELAYED_ITEMS_NR) {
+ u64 bytes = btrfs_calc_trans_metadata_size(root, 1);
+ nr = (int)div64_u64(num_bytes, bytes);
+ if (!nr)
+ nr = 1;
+ nr *= 2;
+ } else {
+ nr = -1;
+ }
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
@@ -4383,10 +4332,6 @@ out:
!block_rsv_use_bytes(global_rsv, orig_bytes))
ret = 0;
}
- if (ret == -ENOSPC)
- trace_btrfs_space_reservation(root->fs_info,
- "space_info:enospc",
- space_info->flags, orig_bytes, 1);
if (flushing) {
spin_lock(&space_info->lock);
space_info->flush = 0;
@@ -5041,7 +4986,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
if (to_reserve)
- trace_btrfs_space_reservation(root->fs_info, "delalloc",
+ trace_btrfs_space_reservation(root->fs_info,"delalloc",
btrfs_ino(inode), to_reserve, 1);
block_rsv_add_bytes(block_rsv, to_reserve, 1);
@@ -5319,8 +5264,6 @@ static int pin_down_extent(struct btrfs_root *root,
set_extent_dirty(root->fs_info->pinned_extents, bytenr,
bytenr + num_bytes - 1, GFP_NOFS | __GFP_NOFAIL);
- if (reserved)
- trace_btrfs_reserved_extent_free(root, bytenr, num_bytes);
return 0;
}
@@ -5775,8 +5718,9 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
}
extent_slot = path->slots[0];
}
- } else if (WARN_ON(ret == -ENOENT)) {
+ } else if (ret == -ENOENT) {
btrfs_print_leaf(extent_root, path->nodes[0]);
+ WARN_ON(1);
btrfs_err(info,
"unable to find ref byte nr %llu parent %llu root %llu owner %llu offset %llu",
bytenr, parent, root_objectid, owner_objectid,
@@ -6023,7 +5967,6 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
btrfs_add_free_space(cache, buf->start, buf->len);
btrfs_update_reserved_bytes(cache, buf->len, RESERVE_FREE);
- trace_btrfs_reserved_extent_free(root, buf->start, buf->len);
pin = 0;
}
out:
@@ -6651,6 +6594,8 @@ again:
}
}
+ trace_btrfs_reserved_extent_alloc(root, ins->objectid, ins->offset);
+
return ret;
}
@@ -6762,7 +6707,6 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
ins->objectid, ins->offset);
BUG();
}
- trace_btrfs_reserved_extent_alloc(root, ins->objectid, ins->offset);
return ret;
}
@@ -6787,18 +6731,13 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
size += sizeof(*block_info);
path = btrfs_alloc_path();
- if (!path) {
- btrfs_free_and_pin_reserved_extent(root, ins->objectid,
- root->leafsize);
+ if (!path)
return -ENOMEM;
- }
path->leave_spinning = 1;
ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
ins, size);
if (ret) {
- btrfs_free_and_pin_reserved_extent(root, ins->objectid,
- root->leafsize);
btrfs_free_path(path);
return ret;
}
@@ -6840,8 +6779,6 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
ins->objectid, ins->offset);
BUG();
}
-
- trace_btrfs_reserved_extent_alloc(root, ins->objectid, root->leafsize);
return ret;
}
@@ -8046,7 +7983,7 @@ u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo)
spin_lock(&sinfo->lock);
- for (i = 0; i < BTRFS_NR_RAID_TYPES; i++)
+ for(i = 0; i < BTRFS_NR_RAID_TYPES; i++)
if (!list_empty(&sinfo->block_groups[i]))
free_bytes += __btrfs_get_ro_block_group_free_space(
&sinfo->block_groups[i]);
@@ -8334,14 +8271,15 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
release_global_block_rsv(info);
- while (!list_empty(&info->space_info)) {
+ while(!list_empty(&info->space_info)) {
space_info = list_entry(info->space_info.next,
struct btrfs_space_info,
list);
if (btrfs_test_opt(info->tree_root, ENOSPC_DEBUG)) {
- if (WARN_ON(space_info->bytes_pinned > 0 ||
+ if (space_info->bytes_pinned > 0 ||
space_info->bytes_reserved > 0 ||
- space_info->bytes_may_use > 0)) {
+ space_info->bytes_may_use > 0) {
+ WARN_ON(1);
dump_space_info(space_info, 0, 0);
}
}
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index ff43802..51731b7 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -13,13 +13,13 @@
#include <linux/cleancache.h>
#include "extent_io.h"
#include "extent_map.h"
+#include "compat.h"
#include "ctree.h"
#include "btrfs_inode.h"
#include "volumes.h"
#include "check-integrity.h"
#include "locking.h"
#include "rcu-string.h"
-#include "backref.h"
static struct kmem_cache *extent_state_cache;
static struct kmem_cache *extent_buffer_cache;
@@ -1597,10 +1597,11 @@ done:
*
* 1 is returned if we find something, 0 if nothing was in the tree
*/
-STATIC u64 find_lock_delalloc_range(struct inode *inode,
- struct extent_io_tree *tree,
- struct page *locked_page, u64 *start,
- u64 *end, u64 max_bytes)
+static noinline u64 find_lock_delalloc_range(struct inode *inode,
+ struct extent_io_tree *tree,
+ struct page *locked_page,
+ u64 *start, u64 *end,
+ u64 max_bytes)
{
u64 delalloc_start;
u64 delalloc_end;
@@ -1739,8 +1740,10 @@ u64 count_range_bits(struct extent_io_tree *tree,
u64 last = 0;
int found = 0;
- if (WARN_ON(search_end <= cur_start))
+ if (search_end <= cur_start) {
+ WARN_ON(1);
return 0;
+ }
spin_lock(&tree->lock);
if (cur_start == 0 && bits == EXTENT_DIRTY) {
@@ -1952,6 +1955,11 @@ static int free_io_failure(struct inode *inode, struct io_failure_record *rec,
return err;
}
+static void repair_io_failure_callback(struct bio *bio, int err)
+{
+ complete(bio->bi_private);
+}
+
/*
* this bypasses the standard btrfs submit functions deliberately, as
* the standard behavior is to write all copies in a raid setup. here we only
@@ -1968,13 +1976,13 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
{
struct bio *bio;
struct btrfs_device *dev;
+ DECLARE_COMPLETION_ONSTACK(compl);
u64 map_length = 0;
u64 sector;
struct btrfs_bio *bbio = NULL;
struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
int ret;
- ASSERT(!(fs_info->sb->s_flags & MS_RDONLY));
BUG_ON(!mirror_num);
/* we can't repair anything in raid56 yet */
@@ -1984,6 +1992,8 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
bio = btrfs_io_bio_alloc(GFP_NOFS, 1);
if (!bio)
return -EIO;
+ bio->bi_private = &compl;
+ bio->bi_end_io = repair_io_failure_callback;
bio->bi_size = 0;
map_length = length;
@@ -2004,8 +2014,10 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
}
bio->bi_bdev = dev->bdev;
bio_add_page(bio, page, length, start - page_offset(page));
+ btrfsic_submit_bio(WRITE_SYNC, bio);
+ wait_for_completion(&compl);
- if (btrfsic_submit_bio_wait(WRITE_SYNC, bio)) {
+ if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
/* try to remap that extent elsewhere? */
bio_put(bio);
btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS);
@@ -2027,9 +2039,6 @@ int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,
unsigned long i, num_pages = num_extent_pages(eb->start, eb->len);
int ret = 0;
- if (root->fs_info->sb->s_flags & MS_RDONLY)
- return -EROFS;
-
for (i = 0; i < num_pages; i++) {
struct page *p = extent_buffer_page(eb, i);
ret = repair_io_failure(root->fs_info, start, PAGE_CACHE_SIZE,
@@ -2051,12 +2060,12 @@ static int clean_io_failure(u64 start, struct page *page)
u64 private;
u64 private_failure;
struct io_failure_record *failrec;
- struct inode *inode = page->mapping->host;
- struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
+ struct btrfs_fs_info *fs_info;
struct extent_state *state;
int num_copies;
int did_repair = 0;
int ret;
+ struct inode *inode = page->mapping->host;
private = 0;
ret = count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private,
@@ -2079,8 +2088,6 @@ static int clean_io_failure(u64 start, struct page *page)
did_repair = 1;
goto out;
}
- if (fs_info->sb->s_flags & MS_RDONLY)
- goto out;
spin_lock(&BTRFS_I(inode)->io_tree.lock);
state = find_first_extent_bit_state(&BTRFS_I(inode)->io_tree,
@@ -2090,6 +2097,7 @@ static int clean_io_failure(u64 start, struct page *page)
if (state && state->start <= failrec->start &&
state->end >= failrec->start + failrec->len - 1) {
+ fs_info = BTRFS_I(inode)->root->fs_info;
num_copies = btrfs_num_copies(fs_info, failrec->logical,
failrec->len);
if (num_copies > 1) {
@@ -3561,8 +3569,9 @@ retry:
* but no sense in crashing the users box for something
* we can survive anyway.
*/
- if (WARN_ON(!eb)) {
+ if (!eb) {
spin_unlock(&mapping->private_lock);
+ WARN_ON(1);
continue;
}
@@ -4029,7 +4038,7 @@ static struct extent_map *get_extent_skip_holes(struct inode *inode,
if (offset >= last)
return NULL;
- while (1) {
+ while(1) {
len = last - offset;
if (len == 0)
break;
@@ -4053,19 +4062,6 @@ static struct extent_map *get_extent_skip_holes(struct inode *inode,
return NULL;
}
-static noinline int count_ext_ref(u64 inum, u64 offset, u64 root_id, void *ctx)
-{
- unsigned long cnt = *((unsigned long *)ctx);
-
- cnt++;
- *((unsigned long *)ctx) = cnt;
-
- /* Now we're sure that the extent is shared. */
- if (cnt > 1)
- return 1;
- return 0;
-}
-
int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
__u64 start, __u64 len, get_extent_t *get_extent)
{
@@ -4132,7 +4128,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
last = found_key.offset;
last_for_get_extent = last + 1;
}
- btrfs_release_path(path);
+ btrfs_free_path(path);
/*
* we might have some extents allocated but more delalloc past those
@@ -4202,24 +4198,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
flags |= (FIEMAP_EXTENT_DELALLOC |
FIEMAP_EXTENT_UNKNOWN);
} else {
- unsigned long ref_cnt = 0;
-
disko = em->block_start + offset_in_extent;
-
- /*
- * As btrfs supports shared space, this information
- * can be exported to userspace tools via
- * flag FIEMAP_EXTENT_SHARED.
- */
- ret = iterate_inodes_from_logical(
- em->block_start,
- BTRFS_I(inode)->root->fs_info,
- path, count_ext_ref, &ref_cnt);
- if (ret < 0 && ret != -ENOENT)
- goto out_free;
-
- if (ref_cnt > 1)
- flags |= FIEMAP_EXTENT_SHARED;
}
if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
flags |= FIEMAP_EXTENT_ENCODED;
@@ -4251,7 +4230,6 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
out_free:
free_extent_map(em);
out:
- btrfs_free_path(path);
unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, start + len - 1,
&cached_state, GFP_NOFS);
return ret;
@@ -4477,23 +4455,6 @@ static void mark_extent_buffer_accessed(struct extent_buffer *eb)
}
}
-struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
- u64 start)
-{
- struct extent_buffer *eb;
-
- rcu_read_lock();
- eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
- if (eb && atomic_inc_not_zero(&eb->refs)) {
- rcu_read_unlock();
- mark_extent_buffer_accessed(eb);
- return eb;
- }
- rcu_read_unlock();
-
- return NULL;
-}
-
struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
u64 start, unsigned long len)
{
@@ -4507,10 +4468,14 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
int uptodate = 1;
int ret;
-
- eb = find_extent_buffer(tree, start);
- if (eb)
+ rcu_read_lock();
+ eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
+ if (eb && atomic_inc_not_zero(&eb->refs)) {
+ rcu_read_unlock();
+ mark_extent_buffer_accessed(eb);
return eb;
+ }
+ rcu_read_unlock();
eb = __alloc_extent_buffer(tree, start, len, GFP_NOFS);
if (!eb)
@@ -4569,17 +4534,24 @@ again:
spin_lock(&tree->buffer_lock);
ret = radix_tree_insert(&tree->buffer, start >> PAGE_CACHE_SHIFT, eb);
- spin_unlock(&tree->buffer_lock);
- radix_tree_preload_end();
if (ret == -EEXIST) {
- exists = find_extent_buffer(tree, start);
- if (exists)
- goto free_eb;
- else
+ exists = radix_tree_lookup(&tree->buffer,
+ start >> PAGE_CACHE_SHIFT);
+ if (!atomic_inc_not_zero(&exists->refs)) {
+ spin_unlock(&tree->buffer_lock);
+ radix_tree_preload_end();
+ exists = NULL;
goto again;
+ }
+ spin_unlock(&tree->buffer_lock);
+ radix_tree_preload_end();
+ mark_extent_buffer_accessed(exists);
+ goto free_eb;
}
/* add one reference for the tree */
check_buffer_tree_ref(eb);
+ spin_unlock(&tree->buffer_lock);
+ radix_tree_preload_end();
/*
* there is a race where release page may have
@@ -4610,6 +4582,23 @@ free_eb:
return exists;
}
+struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
+ u64 start, unsigned long len)
+{
+ struct extent_buffer *eb;
+
+ rcu_read_lock();
+ eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
+ if (eb && atomic_inc_not_zero(&eb->refs)) {
+ rcu_read_unlock();
+ mark_extent_buffer_accessed(eb);
+ return eb;
+ }
+ rcu_read_unlock();
+
+ return NULL;
+}
+
static inline void btrfs_release_extent_buffer_rcu(struct rcu_head *head)
{
struct extent_buffer *eb =
@@ -5073,6 +5062,23 @@ void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src,
}
}
+static void move_pages(struct page *dst_page, struct page *src_page,
+ unsigned long dst_off, unsigned long src_off,
+ unsigned long len)
+{
+ char *dst_kaddr = page_address(dst_page);
+ if (dst_page == src_page) {
+ memmove(dst_kaddr + dst_off, dst_kaddr + src_off, len);
+ } else {
+ char *src_kaddr = page_address(src_page);
+ char *p = dst_kaddr + dst_off + len;
+ char *s = src_kaddr + src_off + len;
+
+ while (len--)
+ *--p = *--s;
+ }
+}
+
static inline bool areas_overlap(unsigned long src, unsigned long dst, unsigned long len)
{
unsigned long distance = (src > dst) ? src - dst : dst - src;
@@ -5183,7 +5189,7 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
cur = min_t(unsigned long, len, src_off_in_page + 1);
cur = min(cur, dst_off_in_page + 1);
- copy_pages(extent_buffer_page(dst, dst_i),
+ move_pages(extent_buffer_page(dst, dst_i),
extent_buffer_page(dst, src_i),
dst_off_in_page - cur + 1,
src_off_in_page - cur + 1, cur);
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index 19620c5..6dbc645 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -271,7 +271,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
struct extent_buffer *alloc_dummy_extent_buffer(u64 start, unsigned long len);
struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src);
struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
- u64 start);
+ u64 start, unsigned long len);
void free_extent_buffer(struct extent_buffer *eb);
void free_extent_buffer_stale(struct extent_buffer *eb);
#define WAIT_NONE 0
@@ -345,10 +345,4 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
int end_extent_writepage(struct page *page, int err, u64 start, u64 end);
int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,
int mirror_num);
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-noinline u64 find_lock_delalloc_range(struct inode *inode,
- struct extent_io_tree *tree,
- struct page *locked_page, u64 *start,
- u64 *end, u64 max_bytes);
-#endif
#endif
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
index 93fba71..61adc44 100644
--- a/fs/btrfs/extent_map.h
+++ b/fs/btrfs/extent_map.h
@@ -3,10 +3,10 @@
#include <linux/rbtree.h>
-#define EXTENT_MAP_LAST_BYTE ((u64)-4)
-#define EXTENT_MAP_HOLE ((u64)-3)
-#define EXTENT_MAP_INLINE ((u64)-2)
-#define EXTENT_MAP_DELALLOC ((u64)-1)
+#define EXTENT_MAP_LAST_BYTE (u64)-4
+#define EXTENT_MAP_HOLE (u64)-3
+#define EXTENT_MAP_INLINE (u64)-2
+#define EXTENT_MAP_DELALLOC (u64)-1
/* bits for the flags field */
#define EXTENT_FLAG_PINNED 0 /* this entry not yet on disk, don't free it */
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index 6f38488..4f53159 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -329,9 +329,6 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
u64 csum_end;
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
- ASSERT(start == ALIGN(start, root->sectorsize) &&
- (end + 1) == ALIGN(end + 1, root->sectorsize));
-
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
@@ -849,8 +846,10 @@ insert:
path->leave_spinning = 0;
if (ret < 0)
goto fail_unlock;
- if (WARN_ON(ret != 0))
+ if (ret != 0) {
+ WARN_ON(1);
goto fail_unlock;
+ }
leaf = path->nodes[0];
csum:
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 82d0342..72da4df 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -39,6 +39,7 @@
#include "print-tree.h"
#include "tree-log.h"
#include "locking.h"
+#include "compat.h"
#include "volumes.h"
static struct kmem_cache *btrfs_inode_defrag_cachep;
@@ -369,7 +370,7 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)
u64 root_objectid = 0;
atomic_inc(&fs_info->defrag_running);
- while (1) {
+ while(1) {
/* Pause the auto defragger. */
if (test_bit(BTRFS_FS_STATE_REMOUNTING,
&fs_info->fs_state))
@@ -1280,7 +1281,6 @@ again:
}
wait_on_page_writeback(pages[i]);
}
- faili = num_pages - 1;
err = 0;
if (start_pos < inode->i_size) {
struct btrfs_ordered_extent *ordered;
@@ -1299,10 +1299,8 @@ again:
unlock_page(pages[i]);
page_cache_release(pages[i]);
}
- err = btrfs_wait_ordered_range(inode, start_pos,
- last_pos - start_pos);
- if (err)
- goto fail;
+ btrfs_wait_ordered_range(inode, start_pos,
+ last_pos - start_pos);
goto again;
}
if (ordered)
@@ -1811,13 +1809,8 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
atomic_inc(&root->log_batch);
full_sync = test_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
&BTRFS_I(inode)->runtime_flags);
- if (full_sync) {
- ret = btrfs_wait_ordered_range(inode, start, end - start + 1);
- if (ret) {
- mutex_unlock(&inode->i_mutex);
- goto out;
- }
- }
+ if (full_sync)
+ btrfs_wait_ordered_range(inode, start, end - start + 1);
atomic_inc(&root->log_batch);
/*
@@ -1883,20 +1876,27 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
mutex_unlock(&inode->i_mutex);
if (ret != BTRFS_NO_LOG_SYNC) {
- if (!ret) {
+ if (ret > 0) {
+ /*
+ * If we didn't already wait for ordered extents we need
+ * to do that now.
+ */
+ if (!full_sync)
+ btrfs_wait_ordered_range(inode, start,
+ end - start + 1);
+ ret = btrfs_commit_transaction(trans, root);
+ } else {
ret = btrfs_sync_log(trans, root);
- if (!ret) {
+ if (ret == 0) {
ret = btrfs_end_transaction(trans, root);
- goto out;
+ } else {
+ if (!full_sync)
+ btrfs_wait_ordered_range(inode, start,
+ end -
+ start + 1);
+ ret = btrfs_commit_transaction(trans, root);
}
}
- if (!full_sync) {
- ret = btrfs_wait_ordered_range(inode, start,
- end - start + 1);
- if (ret)
- goto out;
- }
- ret = btrfs_commit_transaction(trans, root);
} else {
ret = btrfs_end_transaction(trans, root);
}
@@ -2067,9 +2067,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
bool same_page = ((offset >> PAGE_CACHE_SHIFT) ==
((offset + len - 1) >> PAGE_CACHE_SHIFT));
- ret = btrfs_wait_ordered_range(inode, offset, len);
- if (ret)
- return ret;
+ btrfs_wait_ordered_range(inode, offset, len);
mutex_lock(&inode->i_mutex);
/*
@@ -2138,12 +2136,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
btrfs_put_ordered_extent(ordered);
unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart,
lockend, &cached_state, GFP_NOFS);
- ret = btrfs_wait_ordered_range(inode, lockstart,
- lockend - lockstart + 1);
- if (ret) {
- mutex_unlock(&inode->i_mutex);
- return ret;
- }
+ btrfs_wait_ordered_range(inode, lockstart,
+ lockend - lockstart + 1);
}
path = btrfs_alloc_path();
@@ -2314,10 +2308,7 @@ static long btrfs_fallocate(struct file *file, int mode,
* wait for ordered IO before we have any locks. We'll loop again
* below with the locks held.
*/
- ret = btrfs_wait_ordered_range(inode, alloc_start,
- alloc_end - alloc_start);
- if (ret)
- goto out;
+ btrfs_wait_ordered_range(inode, alloc_start, alloc_end - alloc_start);
locked_end = alloc_end - 1;
while (1) {
@@ -2341,10 +2332,8 @@ static long btrfs_fallocate(struct file *file, int mode,
* we can't wait on the range with the transaction
* running or with the extent lock held
*/
- ret = btrfs_wait_ordered_range(inode, alloc_start,
- alloc_end - alloc_start);
- if (ret)
- goto out;
+ btrfs_wait_ordered_range(inode, alloc_start,
+ alloc_end - alloc_start);
} else {
if (ordered)
btrfs_put_ordered_extent(ordered);
@@ -2416,12 +2405,14 @@ out_reserve_fail:
static int find_desired_extent(struct inode *inode, loff_t *offset, int whence)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
- struct extent_map *em = NULL;
+ struct extent_map *em;
struct extent_state *cached_state = NULL;
u64 lockstart = *offset;
u64 lockend = i_size_read(inode);
u64 start = *offset;
+ u64 orig_start = *offset;
u64 len = i_size_read(inode);
+ u64 last_end = 0;
int ret = 0;
lockend = max_t(u64, root->sectorsize, lockend);
@@ -2438,35 +2429,89 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int whence)
lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, 0,
&cached_state);
- while (start < inode->i_size) {
+ /*
+ * Delalloc is such a pain. If we have a hole and we have pending
+ * delalloc for a portion of the hole we will get back a hole that
+ * exists for the entire range since it hasn't been actually written
+ * yet. So to take care of this case we need to look for an extent just
+ * before the position we want in case there is outstanding delalloc
+ * going on here.
+ */
+ if (whence == SEEK_HOLE && start != 0) {
+ if (start <= root->sectorsize)
+ em = btrfs_get_extent_fiemap(inode, NULL, 0, 0,
+ root->sectorsize, 0);
+ else
+ em = btrfs_get_extent_fiemap(inode, NULL, 0,
+ start - root->sectorsize,
+ root->sectorsize, 0);
+ if (IS_ERR(em)) {
+ ret = PTR_ERR(em);
+ goto out;
+ }
+ last_end = em->start + em->len;
+ if (em->block_start == EXTENT_MAP_DELALLOC)
+ last_end = min_t(u64, last_end, inode->i_size);
+ free_extent_map(em);
+ }
+
+ while (1) {
em = btrfs_get_extent_fiemap(inode, NULL, 0, start, len, 0);
if (IS_ERR(em)) {
ret = PTR_ERR(em);
- em = NULL;
break;
}
- if (whence == SEEK_HOLE &&
- (em->block_start == EXTENT_MAP_HOLE ||
- test_bit(EXTENT_FLAG_PREALLOC, &em->flags)))
- break;
- else if (whence == SEEK_DATA &&
- (em->block_start != EXTENT_MAP_HOLE &&
- !test_bit(EXTENT_FLAG_PREALLOC, &em->flags)))
- break;
+ if (em->block_start == EXTENT_MAP_HOLE) {
+ if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) {
+ if (last_end <= orig_start) {
+ free_extent_map(em);
+ ret = -ENXIO;
+ break;
+ }
+ }
+
+ if (whence == SEEK_HOLE) {
+ *offset = start;
+ free_extent_map(em);
+ break;
+ }
+ } else {
+ if (whence == SEEK_DATA) {
+ if (em->block_start == EXTENT_MAP_DELALLOC) {
+ if (start >= inode->i_size) {
+ free_extent_map(em);
+ ret = -ENXIO;
+ break;
+ }
+ }
+
+ if (!test_bit(EXTENT_FLAG_PREALLOC,
+ &em->flags)) {
+ *offset = start;
+ free_extent_map(em);
+ break;
+ }
+ }
+ }
start = em->start + em->len;
+ last_end = em->start + em->len;
+
+ if (em->block_start == EXTENT_MAP_DELALLOC)
+ last_end = min_t(u64, last_end, inode->i_size);
+
+ if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) {
+ free_extent_map(em);
+ ret = -ENXIO;
+ break;
+ }
free_extent_map(em);
- em = NULL;
cond_resched();
}
- free_extent_map(em);
- if (!ret) {
- if (whence == SEEK_DATA && start >= inode->i_size)
- ret = -ENXIO;
- else
- *offset = min_t(loff_t, start, inode->i_size);
- }
+ if (!ret)
+ *offset = min(*offset, inode->i_size);
+out:
unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
&cached_state, GFP_NOFS);
return ret;
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 057be95..b4f9904 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -218,6 +218,7 @@ int btrfs_check_trunc_cache_free_space(struct btrfs_root *root,
int btrfs_truncate_free_space_cache(struct btrfs_root *root,
struct btrfs_trans_handle *trans,
+ struct btrfs_path *path,
struct inode *inode)
{
int ret = 0;
@@ -1008,13 +1009,8 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
if (ret)
goto out;
- ret = btrfs_wait_ordered_range(inode, 0, (u64)-1);
- if (ret) {
- clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,
- EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL,
- GFP_NOFS);
- goto out;
- }
+
+ btrfs_wait_ordered_range(inode, 0, (u64)-1);
key.objectid = BTRFS_FREE_SPACE_OBJECTID;
key.offset = offset;
@@ -2280,7 +2276,7 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
goto out;
entry = rb_entry(node, struct btrfs_free_space, offset_index);
- while (1) {
+ while(1) {
if (entry->bytes < bytes && entry->bytes > *max_extent_size)
*max_extent_size = entry->bytes;
@@ -2971,15 +2967,19 @@ out:
int btrfs_write_out_ino_cache(struct btrfs_root *root,
struct btrfs_trans_handle *trans,
- struct btrfs_path *path,
- struct inode *inode)
+ struct btrfs_path *path)
{
struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
+ struct inode *inode;
int ret;
if (!btrfs_test_opt(root, INODE_MAP_CACHE))
return 0;
+ inode = lookup_free_ino_inode(root, path);
+ if (IS_ERR(inode))
+ return 0;
+
ret = __btrfs_write_out_cache(root, inode, ctl, NULL, trans, path, 0);
if (ret) {
btrfs_delalloc_release_metadata(inode, inode->i_size);
@@ -2990,6 +2990,7 @@ int btrfs_write_out_ino_cache(struct btrfs_root *root,
#endif
}
+ iput(inode);
return ret;
}
diff --git a/fs/btrfs/free-space-cache.h b/fs/btrfs/free-space-cache.h
index 0cf4977..e737f92 100644
--- a/fs/btrfs/free-space-cache.h
+++ b/fs/btrfs/free-space-cache.h
@@ -58,6 +58,7 @@ int btrfs_check_trunc_cache_free_space(struct btrfs_root *root,
struct btrfs_block_rsv *rsv);
int btrfs_truncate_free_space_cache(struct btrfs_root *root,
struct btrfs_trans_handle *trans,
+ struct btrfs_path *path,
struct inode *inode);
int load_free_space_cache(struct btrfs_fs_info *fs_info,
struct btrfs_block_group_cache *block_group);
@@ -75,8 +76,7 @@ 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,
- struct inode *inode);
+ 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,
diff --git a/fs/btrfs/inode-item.c b/fs/btrfs/inode-item.c
index ec82fae..e0b7034 100644
--- a/fs/btrfs/inode-item.c
+++ b/fs/btrfs/inode-item.c
@@ -369,7 +369,7 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
goto out;
leaf = path->nodes[0];
- item = btrfs_item_nr(path->slots[0]);
+ item = btrfs_item_nr(leaf, path->slots[0]);
ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char);
ptr += btrfs_item_size(leaf, item) - ins_len;
extref = (struct btrfs_inode_extref *)ptr;
diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c
index ab485e5..2c66ddb 100644
--- a/fs/btrfs/inode-map.c
+++ b/fs/btrfs/inode-map.c
@@ -78,8 +78,10 @@ again:
btrfs_transaction_in_commit(fs_info)) {
leaf = path->nodes[0];
- if (WARN_ON(btrfs_header_nritems(leaf) == 0))
+ if (btrfs_header_nritems(leaf) == 0) {
+ WARN_ON(1);
break;
+ }
/*
* Save the key so we can advances forward
@@ -235,7 +237,7 @@ again:
start_caching(root);
if (objectid <= root->cache_progress ||
- objectid >= root->highest_objectid)
+ objectid > root->highest_objectid)
__btrfs_add_free_space(ctl, objectid, 1);
else
__btrfs_add_free_space(pinned, objectid, 1);
@@ -410,7 +412,8 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
return 0;
/* Don't save inode cache if we are deleting this root */
- if (btrfs_root_refs(&root->root_item) == 0)
+ if (btrfs_root_refs(&root->root_item) == 0 &&
+ root != root->fs_info->tree_root)
return 0;
if (!btrfs_test_opt(root, INODE_MAP_CACHE))
@@ -464,7 +467,7 @@ again:
}
if (i_size_read(inode) > 0) {
- ret = btrfs_truncate_free_space_cache(root, trans, inode);
+ ret = btrfs_truncate_free_space_cache(root, trans, path, inode);
if (ret) {
if (ret != -ENOSPC)
btrfs_abort_transaction(trans, root, ret);
@@ -501,7 +504,7 @@ again:
}
btrfs_free_reserved_data_space(inode, prealloc);
- ret = btrfs_write_out_ino_cache(root, trans, path, inode);
+ ret = btrfs_write_out_ino_cache(root, trans, path);
out_put:
iput(inode);
out_release:
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index f1a7744..51e3afa 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -43,6 +43,7 @@
#include <linux/btrfs.h>
#include <linux/blkdev.h>
#include <linux/posix_acl_xattr.h>
+#include "compat.h"
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
@@ -843,10 +844,7 @@ static noinline int cow_file_range(struct inode *inode,
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
int ret = 0;
- if (btrfs_is_free_space_inode(inode)) {
- WARN_ON_ONCE(1);
- return -EINVAL;
- }
+ BUG_ON(btrfs_is_free_space_inode(inode));
num_bytes = ALIGN(end - start + 1, blocksize);
num_bytes = max(blocksize, num_bytes);
@@ -1180,8 +1178,10 @@ static noinline int run_delalloc_nocow(struct inode *inode,
while (1) {
ret = btrfs_lookup_file_extent(trans, root, path, ino,
cur_offset, 0);
- if (ret < 0)
+ if (ret < 0) {
+ btrfs_abort_transaction(trans, root, ret);
goto error;
+ }
if (ret > 0 && path->slots[0] > 0 && check_prev) {
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &found_key,
@@ -1195,8 +1195,10 @@ next_slot:
leaf = path->nodes[0];
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
ret = btrfs_next_leaf(root, path);
- if (ret < 0)
+ if (ret < 0) {
+ btrfs_abort_transaction(trans, root, ret);
goto error;
+ }
if (ret > 0)
break;
leaf = path->nodes[0];
@@ -1287,8 +1289,10 @@ out_check:
ret = cow_file_range(inode, locked_page,
cow_start, found_key.offset - 1,
page_started, nr_written, 1);
- if (ret)
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
goto error;
+ }
cow_start = (u64)-1;
}
@@ -1335,8 +1339,10 @@ out_check:
BTRFS_DATA_RELOC_TREE_OBJECTID) {
ret = btrfs_reloc_clone_csums(inode, cur_offset,
num_bytes);
- if (ret)
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
goto error;
+ }
}
extent_clear_unlock_delalloc(inode, cur_offset,
@@ -1358,8 +1364,10 @@ out_check:
if (cow_start != (u64)-1) {
ret = cow_file_range(inode, locked_page, cow_start, end,
page_started, nr_written, 1);
- if (ret)
+ if (ret) {
+ btrfs_abort_transaction(trans, root, ret);
goto error;
+ }
}
error:
@@ -1543,13 +1551,7 @@ static void btrfs_clear_bit_hook(struct inode *inode,
spin_unlock(&BTRFS_I(inode)->lock);
}
- /*
- * We don't reserve metadata space for space cache inodes so we
- * don't need to call dellalloc_release_metadata if there is an
- * error.
- */
- if (*bits & EXTENT_DO_ACCOUNTING &&
- root != root->fs_info->tree_root)
+ if (*bits & EXTENT_DO_ACCOUNTING)
btrfs_delalloc_release_metadata(inode, len);
if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID
@@ -2039,8 +2041,10 @@ static noinline int record_one_backref(u64 inum, u64 offset, u64 root_id,
key.offset = offset;
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
- if (WARN_ON(ret < 0))
+ if (ret < 0) {
+ WARN_ON(1);
return ret;
+ }
ret = 0;
while (1) {
@@ -2129,8 +2133,7 @@ static noinline bool record_extent_backrefs(struct btrfs_path *path,
old->extent_offset, fs_info,
path, record_one_backref,
old);
- if (ret < 0 && ret != -ENOENT)
- return false;
+ BUG_ON(ret < 0 && ret != -ENOENT);
/* no backref to be processed for this extent */
if (!old->count) {
@@ -2364,23 +2367,10 @@ out_unlock:
return ret;
}
-static void free_sa_defrag_extent(struct new_sa_defrag_extent *new)
-{
- struct old_sa_defrag_extent *old, *tmp;
-
- if (!new)
- return;
-
- list_for_each_entry_safe(old, tmp, &new->head, list) {
- list_del(&old->list);
- kfree(old);
- }
- kfree(new);
-}
-
static void relink_file_extents(struct new_sa_defrag_extent *new)
{
struct btrfs_path *path;
+ struct old_sa_defrag_extent *old, *tmp;
struct sa_defrag_extent_backref *backref;
struct sa_defrag_extent_backref *prev = NULL;
struct inode *inode;
@@ -2423,11 +2413,16 @@ static void relink_file_extents(struct new_sa_defrag_extent *new)
kfree(prev);
btrfs_free_path(path);
-out:
- free_sa_defrag_extent(new);
+ list_for_each_entry_safe(old, tmp, &new->head, list) {
+ list_del(&old->list);
+ kfree(old);
+ }
+out:
atomic_dec(&root->fs_info->defrag_running);
wake_up(&root->fs_info->transaction_wait);
+
+ kfree(new);
}
static struct new_sa_defrag_extent *
@@ -2437,7 +2432,7 @@ record_old_file_extents(struct inode *inode,
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_path *path;
struct btrfs_key key;
- struct old_sa_defrag_extent *old;
+ struct old_sa_defrag_extent *old, *tmp;
struct new_sa_defrag_extent *new;
int ret;
@@ -2485,7 +2480,7 @@ record_old_file_extents(struct inode *inode,
if (slot >= btrfs_header_nritems(l)) {
ret = btrfs_next_leaf(root, path);
if (ret < 0)
- goto out_free_path;
+ goto out_free_list;
else if (ret > 0)
break;
continue;
@@ -2514,7 +2509,7 @@ record_old_file_extents(struct inode *inode,
old = kmalloc(sizeof(*old), GFP_NOFS);
if (!old)
- goto out_free_path;
+ goto out_free_list;
offset = max(new->file_pos, key.offset);
end = min(new->file_pos + new->len, key.offset + num_bytes);
@@ -2536,10 +2531,15 @@ next:
return new;
+out_free_list:
+ list_for_each_entry_safe(old, tmp, &new->head, list) {
+ list_del(&old->list);
+ kfree(old);
+ }
out_free_path:
btrfs_free_path(path);
out_kfree:
- free_sa_defrag_extent(new);
+ kfree(new);
return NULL;
}
@@ -2710,14 +2710,8 @@ out:
btrfs_remove_ordered_extent(inode, ordered_extent);
/* for snapshot-aware defrag */
- if (new) {
- if (ret) {
- free_sa_defrag_extent(new);
- atomic_dec(&root->fs_info->defrag_running);
- } else {
- relink_file_extents(new);
- }
- }
+ if (new)
+ relink_file_extents(new);
/* once for us */
btrfs_put_ordered_extent(ordered_extent);
@@ -2975,7 +2969,6 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
if (insert >= 1) {
ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
if (ret) {
- atomic_dec(&root->orphan_inodes);
if (reserve) {
clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
&BTRFS_I(inode)->runtime_flags);
@@ -3025,15 +3018,13 @@ static int btrfs_orphan_del(struct btrfs_trans_handle *trans,
release_rsv = 1;
spin_unlock(&root->orphan_lock);
- if (delete_item) {
- atomic_dec(&root->orphan_inodes);
- if (trans)
- ret = btrfs_del_orphan_item(trans, root,
- btrfs_ino(inode));
- }
+ if (trans && delete_item)
+ ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode));
- if (release_rsv)
+ if (release_rsv) {
btrfs_orphan_release_metadata(inode);
+ atomic_dec(&root->orphan_inodes);
+ }
return ret;
}
@@ -3181,7 +3172,8 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
/* if we have links, this was a truncate, lets do that */
if (inode->i_nlink) {
- if (WARN_ON(!S_ISREG(inode->i_mode))) {
+ if (!S_ISREG(inode->i_mode)) {
+ WARN_ON(1);
iput(inode);
continue;
}
@@ -3644,7 +3636,7 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
int ret;
ret = __btrfs_unlink_inode(trans, root, dir, inode, name, name_len);
if (!ret) {
- drop_nlink(inode);
+ btrfs_drop_nlink(inode);
ret = btrfs_update_inode(trans, root, inode);
}
return ret;
@@ -4238,16 +4230,15 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
while (1) {
struct btrfs_ordered_extent *ordered;
-
+ btrfs_wait_ordered_range(inode, hole_start,
+ block_end - hole_start);
lock_extent_bits(io_tree, hole_start, block_end - 1, 0,
&cached_state);
- ordered = btrfs_lookup_ordered_range(inode, hole_start,
- block_end - hole_start);
+ ordered = btrfs_lookup_ordered_extent(inode, hole_start);
if (!ordered)
break;
unlock_extent_cached(io_tree, hole_start, block_end - 1,
&cached_state, GFP_NOFS);
- btrfs_start_ordered_extent(inode, ordered, 1);
btrfs_put_ordered_extent(ordered);
}
@@ -4481,10 +4472,8 @@ void btrfs_evict_inode(struct inode *inode)
trace_btrfs_inode_evict(inode);
truncate_inode_pages(&inode->i_data, 0);
- if (inode->i_nlink &&
- ((btrfs_root_refs(&root->root_item) != 0 &&
- root->root_key.objectid != BTRFS_ROOT_TREE_OBJECTID) ||
- btrfs_is_free_space_inode(inode)))
+ if (inode->i_nlink && (btrfs_root_refs(&root->root_item) != 0 ||
+ btrfs_is_free_space_inode(inode)))
goto no_delete;
if (is_bad_inode(inode)) {
@@ -4501,8 +4490,7 @@ void btrfs_evict_inode(struct inode *inode)
}
if (inode->i_nlink > 0) {
- BUG_ON(btrfs_root_refs(&root->root_item) != 0 &&
- root->root_key.objectid != BTRFS_ROOT_TREE_OBJECTID);
+ BUG_ON(btrfs_root_refs(&root->root_item) != 0);
goto no_delete;
}
@@ -4743,7 +4731,14 @@ static void inode_tree_del(struct inode *inode)
}
spin_unlock(&root->inode_lock);
- if (empty && btrfs_root_refs(&root->root_item) == 0) {
+ /*
+ * Free space cache has inodes in the tree root, but the tree root has a
+ * root_refs of 0, so this could end up dropping the tree root as a
+ * snapshot, so we need the extra !root->fs_info->tree_root check to
+ * make sure we don't drop it.
+ */
+ if (empty && btrfs_root_refs(&root->root_item) == 0 &&
+ root != root->fs_info->tree_root) {
synchronize_srcu(&root->fs_info->subvol_srcu);
spin_lock(&root->inode_lock);
empty = RB_EMPTY_ROOT(&root->inode_tree);
@@ -4836,12 +4831,10 @@ static struct inode *btrfs_iget_locked(struct super_block *s,
{
struct inode *inode;
struct btrfs_iget_args args;
- unsigned long hashval = btrfs_inode_hash(objectid, root);
-
args.ino = objectid;
args.root = root;
- inode = iget5_locked(s, hashval, btrfs_find_actor,
+ inode = iget5_locked(s, objectid, btrfs_find_actor,
btrfs_init_locked_inode,
(void *)&args);
return inode;
@@ -5055,7 +5048,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
continue;
}
- item = btrfs_item_nr(slot);
+ item = btrfs_item_nr(leaf, slot);
btrfs_item_key_to_cpu(leaf, &found_key, slot);
if (found_key.objectid != key.objectid)
@@ -5461,7 +5454,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
BTRFS_INODE_NODATASUM;
}
- btrfs_insert_inode_hash(inode);
+ insert_inode_hash(inode);
inode_tree_add(inode);
trace_btrfs_inode_new(inode);
@@ -5737,7 +5730,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
goto fail;
}
- inc_nlink(inode);
+ btrfs_inc_nlink(inode);
inode_inc_iversion(inode);
inode->i_ctime = CURRENT_TIME;
ihold(inode);
@@ -5867,7 +5860,7 @@ static noinline int uncompress_inline(struct btrfs_path *path,
compress_type = btrfs_file_extent_compression(leaf, item);
max_size = btrfs_file_extent_ram_bytes(leaf, item);
inline_size = btrfs_file_extent_inline_item_len(leaf,
- btrfs_item_nr(path->slots[0]));
+ btrfs_item_nr(leaf, path->slots[0]));
tmp = kmalloc(inline_size, GFP_NOFS);
if (!tmp)
return -ENOMEM;
@@ -5981,14 +5974,7 @@ again:
found_type = btrfs_key_type(&found_key);
if (found_key.objectid != objectid ||
found_type != BTRFS_EXTENT_DATA_KEY) {
- /*
- * If we backup past the first extent we want to move forward
- * and see if there is an extent in front of us, otherwise we'll
- * say there is a hole for our whole search range which can
- * cause problems.
- */
- extent_end = start;
- goto next;
+ goto not_found;
}
found_type = btrfs_file_extent_type(leaf, item);
@@ -6003,7 +5989,7 @@ again:
size = btrfs_file_extent_inline_len(leaf, item);
extent_end = ALIGN(extent_start + size, root->sectorsize);
}
-next:
+
if (start >= extent_end) {
path->slots[0]++;
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
@@ -6187,7 +6173,8 @@ insert:
write_unlock(&em_tree->lock);
out:
- trace_btrfs_get_extent(root, em);
+ if (em)
+ trace_btrfs_get_extent(root, em);
if (path)
btrfs_free_path(path);
@@ -6262,7 +6249,7 @@ struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *pag
/* adjust the range_start to make sure it doesn't
* go backwards from the start they passed in
*/
- range_start = max(start, range_start);
+ range_start = max(start,range_start);
found = found_end - range_start;
if (found > 0) {
@@ -7066,7 +7053,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
}
} else {
submit_len += bvec->bv_len;
- nr_pages++;
+ nr_pages ++;
bvec++;
}
}
@@ -7235,9 +7222,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
* outstanding dirty pages are on disk.
*/
count = iov_length(iov, nr_segs);
- ret = btrfs_wait_ordered_range(inode, offset, count);
- if (ret)
- return ret;
+ btrfs_wait_ordered_range(inode, offset, count);
if (rw & WRITE) {
/*
@@ -7578,10 +7563,7 @@ static int btrfs_truncate(struct inode *inode)
u64 mask = root->sectorsize - 1;
u64 min_size = btrfs_calc_trunc_metadata_size(root, 1);
- ret = btrfs_wait_ordered_range(inode, inode->i_size & (~mask),
- (u64)-1);
- if (ret)
- return ret;
+ btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
/*
* Yes ladies and gentelment, this is indeed ugly. The fact is we have
@@ -7805,14 +7787,6 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
return inode;
}
-#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-void btrfs_test_destroy_inode(struct inode *inode)
-{
- btrfs_drop_extent_cache(inode, 0, (u64)-1, 0);
- kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode));
-}
-#endif
-
static void btrfs_i_callback(struct rcu_head *head)
{
struct inode *inode = container_of(head, struct inode, i_rcu);
@@ -7883,7 +7857,8 @@ int btrfs_drop_inode(struct inode *inode)
return 1;
/* the snap/subvol tree is on deleting */
- if (btrfs_root_refs(&root->root_item) == 0)
+ if (btrfs_root_refs(&root->root_item) == 0 &&
+ root != root->fs_info->tree_root)
return 1;
else
return generic_drop_inode(inode);
@@ -8020,7 +7995,8 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (ret == -EEXIST) {
/* we shouldn't get
* eexist without a new_inode */
- if (WARN_ON(!new_inode)) {
+ if (!new_inode) {
+ WARN_ON(1);
return ret;
}
} else {
@@ -8168,24 +8144,18 @@ out_notrans:
static void btrfs_run_delalloc_work(struct btrfs_work *work)
{
struct btrfs_delalloc_work *delalloc_work;
- struct inode *inode;
delalloc_work = container_of(work, struct btrfs_delalloc_work,
work);
- inode = delalloc_work->inode;
- if (delalloc_work->wait) {
- btrfs_wait_ordered_range(inode, 0, (u64)-1);
- } else {
- filemap_flush(inode->i_mapping);
- if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
- &BTRFS_I(inode)->runtime_flags))
- filemap_flush(inode->i_mapping);
- }
+ if (delalloc_work->wait)
+ btrfs_wait_ordered_range(delalloc_work->inode, 0, (u64)-1);
+ else
+ filemap_flush(delalloc_work->inode->i_mapping);
if (delalloc_work->delay_iput)
- btrfs_add_delayed_iput(inode);
+ btrfs_add_delayed_iput(delalloc_work->inode);
else
- iput(inode);
+ iput(delalloc_work->inode);
complete(&delalloc_work->completion);
}
@@ -8306,7 +8276,8 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput)
return ret;
}
-int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput)
+int btrfs_start_all_delalloc_inodes(struct btrfs_fs_info *fs_info,
+ int delay_iput)
{
struct btrfs_root *root;
struct list_head splice;
@@ -8366,14 +8337,14 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
int err;
int drop_inode = 0;
u64 objectid;
- u64 index = 0;
+ u64 index = 0 ;
int name_len;
int datasize;
unsigned long ptr;
struct btrfs_file_extent_item *ei;
struct extent_buffer *leaf;
- name_len = strlen(symname);
+ name_len = strlen(symname) + 1;
if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root))
return -ENAMETOOLONG;
@@ -8461,7 +8432,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
inode->i_mapping->a_ops = &btrfs_symlink_aops;
inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
inode_set_bytes(inode, name_len);
- btrfs_i_size_write(inode, name_len);
+ btrfs_i_size_write(inode, name_len - 1);
err = btrfs_update_inode(trans, root, inode);
if (err)
drop_inode = 1;
@@ -8520,8 +8491,6 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
ins.offset, 0, 0, 0,
BTRFS_FILE_EXTENT_PREALLOC);
if (ret) {
- btrfs_free_reserved_extent(root, ins.objectid,
- ins.offset);
btrfs_abort_transaction(trans, root, ret);
if (own_trans)
btrfs_end_transaction(trans, root);
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index a111622..9d46f60 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -44,6 +44,7 @@
#include <linux/uuid.h>
#include <linux/btrfs.h>
#include <linux/uaccess.h>
+#include "compat.h"
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
@@ -320,7 +321,7 @@ static int btrfs_ioctl_getversion(struct file *file, int __user *arg)
static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(file_inode(file)->i_sb);
+ struct btrfs_fs_info *fs_info = btrfs_sb(fdentry(file)->d_sb);
struct btrfs_device *device;
struct request_queue *q;
struct fstrim_range range;
@@ -368,13 +369,9 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
int btrfs_is_empty_uuid(u8 *uuid)
{
- int i;
+ static char empty_uuid[BTRFS_UUID_SIZE] = {0};
- for (i = 0; i < BTRFS_UUID_SIZE; i++) {
- if (uuid[i])
- return 0;
- }
- return 1;
+ return !memcmp(uuid, empty_uuid, BTRFS_UUID_SIZE);
}
static noinline int create_subvol(struct inode *dir,
@@ -439,7 +436,7 @@ static noinline int create_subvol(struct inode *dir,
btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV);
btrfs_set_header_owner(leaf, objectid);
- write_extent_buffer(leaf, root->fs_info->fsid, btrfs_header_fsid(),
+ write_extent_buffer(leaf, root->fs_info->fsid, btrfs_header_fsid(leaf),
BTRFS_FSID_SIZE);
write_extent_buffer(leaf, root->fs_info->chunk_tree_uuid,
btrfs_header_chunk_tree_uuid(leaf),
@@ -577,7 +574,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
if (ret)
return ret;
- btrfs_wait_ordered_extents(root, -1);
+ btrfs_wait_ordered_extents(root);
pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS);
if (!pending_snapshot)
@@ -691,7 +688,7 @@ static inline int btrfs_check_sticky(struct inode *dir, struct inode *inode)
* nfs_async_unlink().
*/
-static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir)
+static int btrfs_may_delete(struct inode *dir,struct dentry *victim,int isdir)
{
int error;
@@ -845,6 +842,7 @@ static int find_new_extents(struct btrfs_root *root,
{
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;
@@ -859,10 +857,15 @@ static int find_new_extents(struct btrfs_root *root,
min_key.type = BTRFS_EXTENT_DATA_KEY;
min_key.offset = *off;
+ max_key.objectid = ino;
+ max_key.type = (u8)-1;
+ max_key.offset = (u64)-1;
+
path->keep_locks = 1;
- while (1) {
- ret = btrfs_search_forward(root, &min_key, path, newer_than);
+ while(1) {
+ ret = btrfs_search_forward(root, &min_key, &max_key,
+ path, newer_than);
if (ret != 0)
goto none;
if (min_key.objectid != ino)
@@ -1203,7 +1206,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
ra = &file->f_ra;
}
- pages = kmalloc_array(max_cluster, sizeof(struct page *),
+ pages = kmalloc(sizeof(struct page *) * max_cluster,
GFP_NOFS);
if (!pages) {
ret = -ENOMEM;
@@ -1890,6 +1893,7 @@ static noinline int search_ioctl(struct inode *inode,
{
struct btrfs_root *root;
struct btrfs_key key;
+ struct btrfs_key max_key;
struct btrfs_path *path;
struct btrfs_ioctl_search_key *sk = &args->key;
struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info;
@@ -1921,10 +1925,15 @@ static noinline int search_ioctl(struct inode *inode,
key.type = sk->min_type;
key.offset = sk->min_offset;
+ max_key.objectid = sk->max_objectid;
+ max_key.type = sk->max_type;
+ max_key.offset = sk->max_offset;
+
path->keep_locks = 1;
- while (1) {
- ret = btrfs_search_forward(root, &key, path, sk->min_transid);
+ while(1) {
+ ret = btrfs_search_forward(root, &key, &max_key, path,
+ sk->min_transid);
if (ret != 0) {
if (ret > 0)
ret = 0;
@@ -2009,7 +2018,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
key.type = BTRFS_INODE_REF_KEY;
key.offset = (u64)-1;
- while (1) {
+ while(1) {
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0)
goto out;
@@ -2038,7 +2047,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
}
*(ptr + len) = '/';
- read_extent_buffer(l, ptr, (unsigned long)(iref + 1), len);
+ read_extent_buffer(l, ptr,(unsigned long)(iref + 1), len);
if (key.offset == BTRFS_FIRST_FREE_OBJECTID)
break;
@@ -2049,7 +2058,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
dirid = key.objectid;
}
memmove(name, ptr, total_len);
- name[total_len] = '\0';
+ name[total_len]='\0';
ret = 0;
out:
btrfs_free_path(path);
@@ -2089,7 +2098,7 @@ static noinline int btrfs_ioctl_ino_lookup(struct file *file,
static noinline int btrfs_ioctl_snap_destroy(struct file *file,
void __user *arg)
{
- struct dentry *parent = file->f_path.dentry;
+ struct dentry *parent = fdentry(file);
struct dentry *dentry;
struct inode *dir = parent->d_inode;
struct inode *inode;
@@ -2135,7 +2144,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
inode = dentry->d_inode;
dest = BTRFS_I(inode)->root;
- if (!capable(CAP_SYS_ADMIN)) {
+ if (!capable(CAP_SYS_ADMIN)){
/*
* Regular user. Only allow this with a special mount
* option, when the user has write+exec access to the
@@ -2718,10 +2727,15 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
size = sizeof(tmp) +
tmp.dest_count * sizeof(struct btrfs_ioctl_same_extent_info);
- same = memdup_user((struct btrfs_ioctl_same_args __user *)argp, size);
+ same = kmalloc(size, GFP_NOFS);
+ if (!same) {
+ ret = -EFAULT;
+ goto out;
+ }
- if (IS_ERR(same)) {
- ret = PTR_ERR(same);
+ if (copy_from_user(same,
+ (struct btrfs_ioctl_same_args __user *)argp, size)) {
+ ret = -EFAULT;
goto out;
}
@@ -3105,7 +3119,7 @@ out:
static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
u64 off, u64 olen, u64 destoff)
{
- struct inode *inode = file_inode(file);
+ struct inode *inode = fdentry(file)->d_inode;
struct btrfs_root *root = BTRFS_I(inode)->root;
struct fd src_file;
struct inode *src;
@@ -3665,10 +3679,9 @@ static long btrfs_ioctl_dev_replace(struct btrfs_root *root, void __user *arg)
switch (p->cmd) {
case BTRFS_IOCTL_DEV_REPLACE_CMD_START:
- if (root->fs_info->sb->s_flags & MS_RDONLY) {
- ret = -EROFS;
- goto out;
- }
+ if (root->fs_info->sb->s_flags & MS_RDONLY)
+ return -EROFS;
+
if (atomic_xchg(
&root->fs_info->mutually_exclusive_operation_running,
1)) {
@@ -3694,7 +3707,7 @@ static long btrfs_ioctl_dev_replace(struct btrfs_root *root, void __user *arg)
if (copy_to_user(arg, p, sizeof(*p)))
ret = -EFAULT;
-out:
+
kfree(p);
return ret;
}
@@ -4304,7 +4317,7 @@ static long btrfs_ioctl_quota_rescan_status(struct file *file, void __user *arg)
static long btrfs_ioctl_quota_rescan_wait(struct file *file, void __user *arg)
{
- struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
+ struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -4544,15 +4557,9 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_logical_to_ino(root, argp);
case BTRFS_IOC_SPACE_INFO:
return btrfs_ioctl_space_info(root, argp);
- case BTRFS_IOC_SYNC: {
- int ret;
-
- ret = btrfs_start_delalloc_roots(root->fs_info, 0);
- if (ret)
- return ret;
- ret = btrfs_sync_fs(file->f_dentry->d_sb, 1);
- return ret;
- }
+ case BTRFS_IOC_SYNC:
+ btrfs_sync_fs(file->f_dentry->d_sb, 1);
+ return 0;
case BTRFS_IOC_START_SYNC:
return btrfs_ioctl_start_sync(root, argp);
case BTRFS_IOC_WAIT_SYNC:
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index 69582d5..c702cb6 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -537,9 +537,7 @@ void btrfs_remove_ordered_extent(struct inode *inode,
*/
if (RB_EMPTY_ROOT(&tree->tree) &&
!mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) {
- spin_lock(&root->fs_info->ordered_root_lock);
list_del_init(&BTRFS_I(inode)->ordered_operations);
- spin_unlock(&root->fs_info->ordered_root_lock);
}
if (!root->nr_ordered_extents) {
@@ -565,11 +563,10 @@ static void btrfs_run_ordered_extent_work(struct btrfs_work *work)
* wait for all the ordered extents in a root. This is done when balancing
* space between drives.
*/
-int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr)
+void btrfs_wait_ordered_extents(struct btrfs_root *root)
{
struct list_head splice, works;
struct btrfs_ordered_extent *ordered, *next;
- int count = 0;
INIT_LIST_HEAD(&splice);
INIT_LIST_HEAD(&works);
@@ -577,7 +574,7 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr)
mutex_lock(&root->fs_info->ordered_operations_mutex);
spin_lock(&root->ordered_extent_lock);
list_splice_init(&root->ordered_extents, &splice);
- while (!list_empty(&splice) && nr) {
+ while (!list_empty(&splice)) {
ordered = list_first_entry(&splice, struct btrfs_ordered_extent,
root_extent_list);
list_move_tail(&ordered->root_extent_list,
@@ -592,11 +589,7 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr)
cond_resched();
spin_lock(&root->ordered_extent_lock);
- if (nr != -1)
- nr--;
- count++;
}
- list_splice_tail(&splice, &root->ordered_extents);
spin_unlock(&root->ordered_extent_lock);
list_for_each_entry_safe(ordered, next, &works, work_list) {
@@ -606,21 +599,18 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr)
cond_resched();
}
mutex_unlock(&root->fs_info->ordered_operations_mutex);
-
- return count;
}
-void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr)
+void btrfs_wait_all_ordered_extents(struct btrfs_fs_info *fs_info)
{
struct btrfs_root *root;
struct list_head splice;
- int done;
INIT_LIST_HEAD(&splice);
spin_lock(&fs_info->ordered_root_lock);
list_splice_init(&fs_info->ordered_roots, &splice);
- while (!list_empty(&splice) && nr) {
+ while (!list_empty(&splice)) {
root = list_first_entry(&splice, struct btrfs_root,
ordered_root);
root = btrfs_grab_fs_root(root);
@@ -629,16 +619,11 @@ void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr)
&fs_info->ordered_roots);
spin_unlock(&fs_info->ordered_root_lock);
- done = btrfs_wait_ordered_extents(root, nr);
+ btrfs_wait_ordered_extents(root);
btrfs_put_fs_root(root);
spin_lock(&fs_info->ordered_root_lock);
- if (nr != -1) {
- nr -= done;
- WARN_ON(nr < 0);
- }
}
- list_splice_tail(&splice, &fs_info->ordered_roots);
spin_unlock(&fs_info->ordered_root_lock);
}
@@ -749,9 +734,8 @@ void btrfs_start_ordered_extent(struct inode *inode,
/*
* Used to wait on ordered extents across a large range of bytes.
*/
-int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
+void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
{
- int ret = 0;
u64 end;
u64 orig_end;
struct btrfs_ordered_extent *ordered;
@@ -767,9 +751,8 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
/* start IO across the range first to instantiate any delalloc
* extents
*/
- ret = filemap_fdatawrite_range(inode->i_mapping, start, orig_end);
- if (ret)
- return ret;
+ filemap_fdatawrite_range(inode->i_mapping, start, orig_end);
+
/*
* So with compression we will find and lock a dirty page and clear the
* first one as dirty, setup an async extent, and immediately return
@@ -785,15 +768,10 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
* right and you are wrong.
*/
if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
- &BTRFS_I(inode)->runtime_flags)) {
- ret = filemap_fdatawrite_range(inode->i_mapping, start,
- orig_end);
- if (ret)
- return ret;
- }
- ret = filemap_fdatawait_range(inode->i_mapping, start, orig_end);
- if (ret)
- return ret;
+ &BTRFS_I(inode)->runtime_flags))
+ filemap_fdatawrite_range(inode->i_mapping, start, orig_end);
+
+ filemap_fdatawait_range(inode->i_mapping, start, orig_end);
end = orig_end;
while (1) {
@@ -804,20 +782,17 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
btrfs_put_ordered_extent(ordered);
break;
}
- if (ordered->file_offset + ordered->len <= start) {
+ if (ordered->file_offset + ordered->len < start) {
btrfs_put_ordered_extent(ordered);
break;
}
btrfs_start_ordered_extent(inode, ordered, 1);
end = ordered->file_offset;
- if (test_bit(BTRFS_ORDERED_IOERR, &ordered->flags))
- ret = -EIO;
btrfs_put_ordered_extent(ordered);
- if (ret || end == 0 || end == start)
+ if (end == 0 || end == start)
break;
end--;
}
- return ret;
}
/*
@@ -1101,7 +1076,7 @@ void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
* if this file hasn't been changed since the last transaction
* commit, we can safely return without doing anything
*/
- if (last_mod <= root->fs_info->last_trans_committed)
+ if (last_mod < root->fs_info->last_trans_committed)
return;
spin_lock(&root->fs_info->ordered_root_lock);
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
index 9b0450f..0c0b356 100644
--- a/fs/btrfs/ordered-data.h
+++ b/fs/btrfs/ordered-data.h
@@ -180,7 +180,7 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode,
u64 file_offset);
void btrfs_start_ordered_extent(struct inode *inode,
struct btrfs_ordered_extent *entry, int wait);
-int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len);
+void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len);
struct btrfs_ordered_extent *
btrfs_lookup_first_ordered_extent(struct inode * inode, u64 file_offset);
struct btrfs_ordered_extent *btrfs_lookup_ordered_range(struct inode *inode,
@@ -195,8 +195,8 @@ int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans,
void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct inode *inode);
-int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr);
-void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr);
+void btrfs_wait_ordered_extents(struct btrfs_root *root);
+void btrfs_wait_all_ordered_extents(struct btrfs_fs_info *fs_info);
void btrfs_get_logged_extents(struct btrfs_root *log, struct inode *inode);
void btrfs_wait_logged_extents(struct btrfs_root *log, u64 transid);
void btrfs_free_logged_extents(struct btrfs_root *log, u64 transid);
diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c
index 417053b..0088bed 100644
--- a/fs/btrfs/print-tree.c
+++ b/fs/btrfs/print-tree.c
@@ -193,7 +193,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
btrfs_info(root->fs_info, "leaf %llu total ptrs %d free space %d",
btrfs_header_bytenr(l), nr, btrfs_leaf_free_space(root, l));
for (i = 0 ; i < nr ; i++) {
- item = btrfs_item_nr(i);
+ item = btrfs_item_nr(l, i);
btrfs_item_key_to_cpu(l, &key, i);
type = btrfs_key_type(&key);
printk(KERN_INFO "\titem %d key (%llu %u %llu) itemoff %d "
diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
index 24ac218..d0ecfbd 100644
--- a/fs/btrfs/raid56.c
+++ b/fs/btrfs/raid56.c
@@ -33,6 +33,7 @@
#include <linux/raid/xor.h>
#include <linux/vmalloc.h>
#include <asm/div64.h>
+#include "compat.h"
#include "ctree.h"
#include "extent_map.h"
#include "disk-io.h"
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index ce459a7..4a35572 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -1383,7 +1383,6 @@ int btrfs_init_reloc_root(struct btrfs_trans_handle *trans,
{
struct btrfs_root *reloc_root;
struct reloc_control *rc = root->fs_info->reloc_ctl;
- struct btrfs_block_rsv *rsv;
int clear_rsv = 0;
int ret;
@@ -1397,14 +1396,13 @@ int btrfs_init_reloc_root(struct btrfs_trans_handle *trans,
root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID)
return 0;
- if (!trans->reloc_reserved) {
- rsv = trans->block_rsv;
+ if (!trans->block_rsv) {
trans->block_rsv = rc->block_rsv;
clear_rsv = 1;
}
reloc_root = create_reloc_root(trans, root, root->root_key.objectid);
if (clear_rsv)
- trans->block_rsv = rsv;
+ trans->block_rsv = NULL;
ret = __add_reloc_root(reloc_root);
BUG_ON(ret < 0);
@@ -1777,7 +1775,8 @@ again:
new_ptr_gen = 0;
}
- if (WARN_ON(new_bytenr > 0 && new_bytenr == old_bytenr)) {
+ if (new_bytenr > 0 && new_bytenr == old_bytenr) {
+ WARN_ON(1);
ret = level;
break;
}
@@ -2059,7 +2058,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
LIST_HEAD(inode_list);
struct btrfs_key key;
struct btrfs_key next_key;
- struct btrfs_trans_handle *trans = NULL;
+ struct btrfs_trans_handle *trans;
struct btrfs_root *reloc_root;
struct btrfs_root_item *root_item;
struct btrfs_path *path;
@@ -2108,19 +2107,18 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
memset(&next_key, 0, sizeof(next_key));
while (1) {
+ trans = btrfs_start_transaction(root, 0);
+ BUG_ON(IS_ERR(trans));
+ trans->block_rsv = rc->block_rsv;
+
ret = btrfs_block_rsv_refill(root, rc->block_rsv, min_reserved,
BTRFS_RESERVE_FLUSH_ALL);
if (ret) {
- err = ret;
- goto out;
- }
- trans = btrfs_start_transaction(root, 0);
- if (IS_ERR(trans)) {
- err = PTR_ERR(trans);
- trans = NULL;
- goto out;
+ BUG_ON(ret != -EAGAIN);
+ ret = btrfs_commit_transaction(trans, root);
+ BUG_ON(ret);
+ continue;
}
- trans->block_rsv = rc->block_rsv;
replaced = 0;
max_level = level;
@@ -2166,7 +2164,6 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
root_item->drop_level = level;
btrfs_end_transaction_throttle(trans, root);
- trans = NULL;
btrfs_btree_balance_dirty(root);
@@ -2195,8 +2192,7 @@ out:
btrfs_update_reloc_root(trans, root);
}
- if (trans)
- btrfs_end_transaction_throttle(trans, root);
+ btrfs_end_transaction_throttle(trans, root);
btrfs_btree_balance_dirty(root);
@@ -3262,7 +3258,7 @@ static int add_tree_block(struct reloc_control *rc,
struct rb_node *rb_node;
u32 item_size;
int level = -1;
- u64 generation;
+ int generation;
eb = path->nodes[0];
item_size = btrfs_item_size_nr(eb, path->slots[0]);
@@ -3411,6 +3407,7 @@ static int delete_block_group_cache(struct btrfs_fs_info *fs_info,
struct inode *inode, u64 ino)
{
struct btrfs_key key;
+ struct btrfs_path *path;
struct btrfs_root *root = fs_info->tree_root;
struct btrfs_trans_handle *trans;
int ret = 0;
@@ -3435,14 +3432,22 @@ truncate:
if (ret)
goto out;
+ path = btrfs_alloc_path();
+ if (!path) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
+ btrfs_free_path(path);
ret = PTR_ERR(trans);
goto out;
}
- ret = btrfs_truncate_free_space_cache(root, trans, inode);
+ ret = btrfs_truncate_free_space_cache(root, trans, path, inode);
+ btrfs_free_path(path);
btrfs_end_transaction(trans, root);
btrfs_btree_balance_dirty(root);
out:
@@ -3544,8 +3549,10 @@ static int find_data_references(struct reloc_control *rc,
err = ret;
goto out;
}
- if (WARN_ON(ret > 0))
+ if (ret > 0) {
+ WARN_ON(1);
goto out;
+ }
leaf = path->nodes[0];
nritems = btrfs_header_nritems(leaf);
@@ -3565,9 +3572,11 @@ static int find_data_references(struct reloc_control *rc,
}
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
- if (WARN_ON(key.objectid != ref_objectid ||
- key.type != BTRFS_EXTENT_DATA_KEY))
+ if (key.objectid != ref_objectid ||
+ key.type != BTRFS_EXTENT_DATA_KEY) {
+ WARN_ON(1);
break;
+ }
fi = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
@@ -3992,6 +4001,16 @@ restart:
}
}
+ ret = btrfs_block_rsv_check(rc->extent_root, rc->block_rsv, 5);
+ if (ret < 0) {
+ if (ret != -ENOSPC) {
+ err = ret;
+ WARN_ON(1);
+ break;
+ }
+ rc->commit_transaction = 1;
+ }
+
if (rc->commit_transaction) {
rc->commit_transaction = 0;
ret = btrfs_commit_transaction(trans, rc->extent_root);
@@ -4222,12 +4241,12 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
printk(KERN_INFO "btrfs: relocating block group %llu flags %llu\n",
rc->block_group->key.objectid, rc->block_group->flags);
- ret = btrfs_start_delalloc_roots(fs_info, 0);
+ ret = btrfs_start_all_delalloc_inodes(fs_info, 0);
if (ret < 0) {
err = ret;
goto out;
}
- btrfs_wait_ordered_roots(fs_info, -1);
+ btrfs_wait_all_ordered_extents(fs_info);
while (1) {
mutex_lock(&fs_info->cleaner_mutex);
@@ -4245,12 +4264,7 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
rc->extents_found);
if (rc->stage == MOVE_DATA_EXTENTS && rc->found_file_extent) {
- ret = btrfs_wait_ordered_range(rc->data_inode, 0,
- (u64)-1);
- if (ret) {
- err = ret;
- goto out;
- }
+ btrfs_wait_ordered_range(rc->data_inode, 0, (u64)-1);
invalidate_mapping_pages(rc->data_inode->i_mapping,
0, -1);
rc->stage = UPDATE_DATA_PTRS;
@@ -4467,7 +4481,6 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
struct btrfs_root *root = BTRFS_I(inode)->root;
int ret;
u64 disk_bytenr;
- u64 new_bytenr;
LIST_HEAD(list);
ordered = btrfs_lookup_ordered_extent(inode, file_pos);
@@ -4479,24 +4492,13 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
if (ret)
goto out;
+ disk_bytenr = ordered->start;
while (!list_empty(&list)) {
sums = list_entry(list.next, struct btrfs_ordered_sum, list);
list_del_init(&sums->list);
- /*
- * We need to offset the new_bytenr based on where the csum is.
- * We need to do this because we will read in entire prealloc
- * extents but we may have written to say the middle of the
- * prealloc extent, so we need to make sure the csum goes with
- * the right disk offset.
- *
- * We can do this because the data reloc inode refers strictly
- * to the on disk bytes, so we don't have to worry about
- * disk_len vs real len like with real inodes since it's all
- * disk length.
- */
- new_bytenr = ordered->start + (sums->bytenr - disk_bytenr);
- sums->bytenr = new_bytenr;
+ sums->bytenr = disk_bytenr;
+ disk_bytenr += sums->len;
btrfs_add_ordered_sum(inode, ordered, sums);
}
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 1fd3f33..a18e0e2 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -208,6 +208,7 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
int is_metadata, int have_csum,
const u8 *csum, u64 generation,
u16 csum_size);
+static void scrub_complete_bio_end_io(struct bio *bio, int err);
static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad,
struct scrub_block *sblock_good,
int force_write);
@@ -937,10 +938,8 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
BTRFS_DEV_STAT_CORRUPTION_ERRS);
}
- if (sctx->readonly) {
- ASSERT(!sctx->is_dev_replace);
- goto out;
- }
+ if (sctx->readonly && !sctx->is_dev_replace)
+ goto did_not_correct_error;
if (!is_metadata && !have_csum) {
struct scrub_fixup_nodatasum *fixup_nodatasum;
@@ -1293,6 +1292,7 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
for (page_num = 0; page_num < sblock->page_count; page_num++) {
struct bio *bio;
struct scrub_page *page = sblock->pagev[page_num];
+ DECLARE_COMPLETION_ONSTACK(complete);
if (page->dev->bdev == NULL) {
page->io_error = 1;
@@ -1309,11 +1309,18 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
}
bio->bi_bdev = page->dev->bdev;
bio->bi_sector = page->physical >> 9;
+ bio->bi_end_io = scrub_complete_bio_end_io;
+ bio->bi_private = &complete;
bio_add_page(bio, page->page, PAGE_SIZE, 0);
- if (btrfsic_submit_bio_wait(READ, bio))
- sblock->no_io_error_seen = 0;
+ btrfsic_submit_bio(READ, bio);
+
+ /* this will also unplug the queue */
+ wait_for_completion(&complete);
+ page->io_error = !test_bit(BIO_UPTODATE, &bio->bi_flags);
+ if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
+ sblock->no_io_error_seen = 0;
bio_put(bio);
}
@@ -1382,6 +1389,11 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
sblock->checksum_error = 1;
}
+static void scrub_complete_bio_end_io(struct bio *bio, int err)
+{
+ complete((struct completion *)bio->bi_private);
+}
+
static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad,
struct scrub_block *sblock_good,
int force_write)
@@ -1416,6 +1428,7 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
sblock_bad->checksum_error || page_bad->io_error) {
struct bio *bio;
int ret;
+ DECLARE_COMPLETION_ONSTACK(complete);
if (!page_bad->dev->bdev) {
printk_ratelimited(KERN_WARNING
@@ -1428,14 +1441,19 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
return -EIO;
bio->bi_bdev = page_bad->dev->bdev;
bio->bi_sector = page_bad->physical >> 9;
+ bio->bi_end_io = scrub_complete_bio_end_io;
+ bio->bi_private = &complete;
ret = bio_add_page(bio, page_good->page, PAGE_SIZE, 0);
if (PAGE_SIZE != ret) {
bio_put(bio);
return -EIO;
}
+ btrfsic_submit_bio(WRITE, bio);
- if (btrfsic_submit_bio_wait(WRITE, bio)) {
+ /* this will also unplug the queue */
+ wait_for_completion(&complete);
+ if (!bio_flagged(bio, BIO_UPTODATE)) {
btrfs_dev_stat_inc_and_print(page_bad->dev,
BTRFS_DEV_STAT_WRITE_ERRS);
btrfs_dev_replace_stats_inc(
@@ -2699,6 +2717,8 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
mutex_unlock(&fs_info->scrub_lock);
wake_up(&fs_info->scrub_pause_wait);
+ dev_replace->cursor_left = dev_replace->cursor_right;
+ dev_replace->item_needs_writeback = 1;
btrfs_put_block_group(cache);
if (ret)
break;
@@ -2712,9 +2732,6 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
break;
}
- dev_replace->cursor_left = dev_replace->cursor_right;
- dev_replace->item_needs_writeback = 1;
-
key.offset = found_key.offset + length;
btrfs_release_path(path);
}
@@ -2766,6 +2783,7 @@ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
{
int ret = 0;
+ mutex_lock(&fs_info->scrub_lock);
if (fs_info->scrub_workers_refcnt == 0) {
if (is_dev_replace)
btrfs_init_workers(&fs_info->scrub_workers, "scrub", 1,
@@ -2795,17 +2813,21 @@ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
}
++fs_info->scrub_workers_refcnt;
out:
+ mutex_unlock(&fs_info->scrub_lock);
+
return ret;
}
static noinline_for_stack void scrub_workers_put(struct btrfs_fs_info *fs_info)
{
+ mutex_lock(&fs_info->scrub_lock);
if (--fs_info->scrub_workers_refcnt == 0) {
btrfs_stop_workers(&fs_info->scrub_workers);
btrfs_stop_workers(&fs_info->scrub_wr_completion_workers);
btrfs_stop_workers(&fs_info->scrub_nocow_workers);
}
WARN_ON(fs_info->scrub_workers_refcnt < 0);
+ mutex_unlock(&fs_info->scrub_lock);
}
int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
@@ -2866,18 +2888,23 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
return -EINVAL;
}
+ ret = scrub_workers_get(fs_info, is_dev_replace);
+ if (ret)
+ return ret;
mutex_lock(&fs_info->fs_devices->device_list_mutex);
dev = btrfs_find_device(fs_info, devid, NULL, NULL);
if (!dev || (dev->missing && !is_dev_replace)) {
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+ scrub_workers_put(fs_info);
return -ENODEV;
}
-
mutex_lock(&fs_info->scrub_lock);
+
if (!dev->in_fs_metadata || dev->is_tgtdev_for_dev_replace) {
mutex_unlock(&fs_info->scrub_lock);
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+ scrub_workers_put(fs_info);
return -EIO;
}
@@ -2888,17 +2915,10 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
btrfs_dev_replace_unlock(&fs_info->dev_replace);
mutex_unlock(&fs_info->scrub_lock);
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+ scrub_workers_put(fs_info);
return -EINPROGRESS;
}
btrfs_dev_replace_unlock(&fs_info->dev_replace);
-
- ret = scrub_workers_get(fs_info, is_dev_replace);
- if (ret) {
- mutex_unlock(&fs_info->scrub_lock);
- mutex_unlock(&fs_info->fs_devices->device_list_mutex);
- return ret;
- }
-
sctx = scrub_setup_ctx(dev, is_dev_replace);
if (IS_ERR(sctx)) {
mutex_unlock(&fs_info->scrub_lock);
@@ -2911,15 +2931,13 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
atomic_inc(&fs_info->scrubs_running);
mutex_unlock(&fs_info->scrub_lock);
+ mutex_unlock(&fs_info->fs_devices->device_list_mutex);
if (!is_dev_replace) {
- /*
- * by holding device list mutex, we can
- * kick off writing super in log tree sync.
- */
+ down_read(&fs_info->scrub_super_lock);
ret = scrub_supers(sctx, dev);
+ up_read(&fs_info->scrub_super_lock);
}
- mutex_unlock(&fs_info->fs_devices->device_list_mutex);
if (!ret)
ret = scrub_enumerate_chunks(sctx, dev, start, end,
@@ -2936,10 +2954,10 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
mutex_lock(&fs_info->scrub_lock);
dev->scrub_device = NULL;
- scrub_workers_put(fs_info);
mutex_unlock(&fs_info->scrub_lock);
scrub_free_ctx(sctx);
+ scrub_workers_put(fs_info);
return ret;
}
@@ -2969,6 +2987,16 @@ void btrfs_scrub_continue(struct btrfs_root *root)
wake_up(&fs_info->scrub_pause_wait);
}
+void btrfs_scrub_pause_super(struct btrfs_root *root)
+{
+ down_write(&root->fs_info->scrub_super_lock);
+}
+
+void btrfs_scrub_continue_super(struct btrfs_root *root)
+{
+ up_write(&root->fs_info->scrub_super_lock);
+}
+
int btrfs_scrub_cancel(struct btrfs_fs_info *fs_info)
{
mutex_lock(&fs_info->scrub_lock);
@@ -3355,6 +3383,7 @@ static int write_page_nocow(struct scrub_ctx *sctx,
struct bio *bio;
struct btrfs_device *dev;
int ret;
+ DECLARE_COMPLETION_ONSTACK(compl);
dev = sctx->wr_ctx.tgtdev;
if (!dev)
@@ -3371,6 +3400,8 @@ static int write_page_nocow(struct scrub_ctx *sctx,
spin_unlock(&sctx->stat_lock);
return -ENOMEM;
}
+ bio->bi_private = &compl;
+ bio->bi_end_io = scrub_complete_bio_end_io;
bio->bi_size = 0;
bio->bi_sector = physical_for_dev_replace >> 9;
bio->bi_bdev = dev->bdev;
@@ -3381,8 +3412,10 @@ leave_with_eio:
btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS);
return -EIO;
}
+ btrfsic_submit_bio(WRITE_SYNC, bio);
+ wait_for_completion(&compl);
- if (btrfsic_submit_bio_wait(WRITE_SYNC, bio))
+ if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
goto leave_with_eio;
bio_put(bio);
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 6837fe8..e46e0ed 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -121,6 +121,7 @@ struct send_ctx {
struct list_head name_cache_list;
int name_cache_size;
+ struct file *cur_inode_filp;
char *read_buf;
};
@@ -564,8 +565,10 @@ static int begin_cmd(struct send_ctx *sctx, int cmd)
{
struct btrfs_cmd_header *hdr;
- if (WARN_ON(!sctx->send_buf))
+ if (!sctx->send_buf) {
+ WARN_ON(1);
return -EINVAL;
+ }
BUG_ON(sctx->send_size);
@@ -788,7 +791,7 @@ static int iterate_inode_ref(struct btrfs_root *root, struct btrfs_path *path,
if (found_key->type == BTRFS_INODE_REF_KEY) {
ptr = (unsigned long)btrfs_item_ptr(eb, slot,
struct btrfs_inode_ref);
- item = btrfs_item_nr(slot);
+ item = btrfs_item_nr(eb, slot);
total = btrfs_item_size(eb, item);
elem_size = sizeof(*iref);
} else {
@@ -902,7 +905,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
eb = path->nodes[0];
slot = path->slots[0];
- item = btrfs_item_nr(slot);
+ item = btrfs_item_nr(eb, slot);
di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item);
cur = 0;
len = 0;
@@ -2117,6 +2120,77 @@ out:
}
/*
+ * Called for regular files when sending extents data. Opens a struct file
+ * to read from the file.
+ */
+static int open_cur_inode_file(struct send_ctx *sctx)
+{
+ int ret = 0;
+ struct btrfs_key key;
+ struct path path;
+ struct inode *inode;
+ struct dentry *dentry;
+ struct file *filp;
+ int new = 0;
+
+ if (sctx->cur_inode_filp)
+ goto out;
+
+ key.objectid = sctx->cur_ino;
+ key.type = BTRFS_INODE_ITEM_KEY;
+ key.offset = 0;
+
+ inode = btrfs_iget(sctx->send_root->fs_info->sb, &key, sctx->send_root,
+ &new);
+ if (IS_ERR(inode)) {
+ ret = PTR_ERR(inode);
+ goto out;
+ }
+
+ dentry = d_obtain_alias(inode);
+ inode = NULL;
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+ goto out;
+ }
+
+ path.mnt = sctx->mnt;
+ path.dentry = dentry;
+ filp = dentry_open(&path, O_RDONLY | O_LARGEFILE, current_cred());
+ dput(dentry);
+ dentry = NULL;
+ if (IS_ERR(filp)) {
+ ret = PTR_ERR(filp);
+ goto out;
+ }
+ sctx->cur_inode_filp = filp;
+
+out:
+ /*
+ * no xxxput required here as every vfs op
+ * does it by itself on failure
+ */
+ return ret;
+}
+
+/*
+ * Closes the struct file that was created in open_cur_inode_file
+ */
+static int close_cur_inode_file(struct send_ctx *sctx)
+{
+ int ret = 0;
+
+ if (!sctx->cur_inode_filp)
+ goto out;
+
+ ret = filp_close(sctx->cur_inode_filp, NULL);
+ sctx->cur_inode_filp = NULL;
+
+out:
+ return ret;
+}
+
+/*
* Sends a BTRFS_SEND_C_SUBVOL command/item to userspace
*/
static int send_subvol_begin(struct send_ctx *sctx)
@@ -3548,72 +3622,6 @@ out:
return ret;
}
-static ssize_t fill_read_buf(struct send_ctx *sctx, u64 offset, u32 len)
-{
- struct btrfs_root *root = sctx->send_root;
- struct btrfs_fs_info *fs_info = root->fs_info;
- struct inode *inode;
- struct page *page;
- char *addr;
- struct btrfs_key key;
- pgoff_t index = offset >> PAGE_CACHE_SHIFT;
- pgoff_t last_index;
- unsigned pg_offset = offset & ~PAGE_CACHE_MASK;
- ssize_t ret = 0;
-
- key.objectid = sctx->cur_ino;
- key.type = BTRFS_INODE_ITEM_KEY;
- key.offset = 0;
-
- inode = btrfs_iget(fs_info->sb, &key, root, NULL);
- if (IS_ERR(inode))
- return PTR_ERR(inode);
-
- if (offset + len > i_size_read(inode)) {
- if (offset > i_size_read(inode))
- len = 0;
- else
- len = offset - i_size_read(inode);
- }
- if (len == 0)
- goto out;
-
- last_index = (offset + len - 1) >> PAGE_CACHE_SHIFT;
- while (index <= last_index) {
- unsigned cur_len = min_t(unsigned, len,
- PAGE_CACHE_SIZE - pg_offset);
- page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
- if (!page) {
- ret = -ENOMEM;
- break;
- }
-
- if (!PageUptodate(page)) {
- btrfs_readpage(NULL, page);
- lock_page(page);
- if (!PageUptodate(page)) {
- unlock_page(page);
- page_cache_release(page);
- ret = -EIO;
- break;
- }
- }
-
- addr = kmap(page);
- memcpy(sctx->read_buf + ret, addr + pg_offset, cur_len);
- kunmap(page);
- unlock_page(page);
- page_cache_release(page);
- index++;
- pg_offset = 0;
- len -= cur_len;
- ret += cur_len;
- }
-out:
- iput(inode);
- return ret;
-}
-
/*
* Read some bytes from the current inode/file and send a write command to
* user space.
@@ -3622,20 +3630,35 @@ static int send_write(struct send_ctx *sctx, u64 offset, u32 len)
{
int ret = 0;
struct fs_path *p;
- ssize_t num_read = 0;
+ loff_t pos = offset;
+ int num_read = 0;
+ mm_segment_t old_fs;
p = fs_path_alloc();
if (!p)
return -ENOMEM;
+ /*
+ * vfs normally only accepts user space buffers for security reasons.
+ * we only read from the file and also only provide the read_buf buffer
+ * to vfs. As this buffer does not come from a user space call, it's
+ * ok to temporary allow kernel space buffers.
+ */
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
verbose_printk("btrfs: send_write offset=%llu, len=%d\n", offset, len);
- num_read = fill_read_buf(sctx, offset, len);
- if (num_read <= 0) {
- if (num_read < 0)
- ret = num_read;
+ ret = open_cur_inode_file(sctx);
+ if (ret < 0)
+ goto out;
+
+ ret = vfs_read(sctx->cur_inode_filp, sctx->read_buf, len, &pos);
+ if (ret < 0)
+ goto out;
+ num_read = ret;
+ if (!num_read)
goto out;
- }
ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE);
if (ret < 0)
@@ -3654,6 +3677,7 @@ verbose_printk("btrfs: send_write offset=%llu, len=%d\n", offset, len);
tlv_put_failure:
out:
fs_path_free(p);
+ set_fs(old_fs);
if (ret < 0)
return ret;
return num_read;
@@ -3902,16 +3926,16 @@ static int is_extent_unchanged(struct send_ctx *sctx,
while (key.offset < ekey->offset + left_len) {
ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
right_type = btrfs_file_extent_type(eb, ei);
- if (right_type != BTRFS_FILE_EXTENT_REG) {
- ret = 0;
- goto out;
- }
-
right_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
right_len = btrfs_file_extent_num_bytes(eb, ei);
right_offset = btrfs_file_extent_offset(eb, ei);
right_gen = btrfs_file_extent_generation(eb, ei);
+ if (right_type != BTRFS_FILE_EXTENT_REG) {
+ ret = 0;
+ goto out;
+ }
+
/*
* Are we at extent 8? If yes, we know the extent is changed.
* This may only happen on the first iteration.
@@ -4198,6 +4222,10 @@ static int changed_inode(struct send_ctx *sctx,
u64 left_gen = 0;
u64 right_gen = 0;
+ ret = close_cur_inode_file(sctx);
+ if (ret < 0)
+ goto out;
+
sctx->cur_ino = key->objectid;
sctx->cur_inode_new_gen = 0;
@@ -4658,6 +4686,11 @@ static int send_subvol(struct send_ctx *sctx)
}
out:
+ if (!ret)
+ ret = close_cur_inode_file(sctx);
+ else
+ close_cur_inode_file(sctx);
+
free_recorded_refs(sctx);
return ret;
}
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 2d8ac1b..e913328 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -42,6 +42,7 @@
#include <linux/cleancache.h>
#include <linux/ratelimit.h>
#include <linux/btrfs.h>
+#include "compat.h"
#include "delayed-inode.h"
#include "ctree.h"
#include "disk-io.h"
@@ -920,7 +921,7 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
return 0;
}
- btrfs_wait_ordered_roots(fs_info, -1);
+ btrfs_wait_all_ordered_extents(fs_info);
trans = btrfs_attach_transaction_barrier(root);
if (IS_ERR(trans)) {
@@ -1329,12 +1330,6 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
* this also happens on 'umount -rf' or on shutdown, when
* the filesystem is busy.
*/
-
- /* wait for the uuid_scan task to finish */
- down(&fs_info->uuid_tree_rescan_sem);
- /* avoid complains from lockdep et al. */
- up(&fs_info->uuid_tree_rescan_sem);
-
sb->s_flags |= MS_RDONLY;
btrfs_dev_replace_suspend_for_unmount(fs_info);
@@ -1470,7 +1465,7 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
nr_devices = fs_info->fs_devices->open_devices;
BUG_ON(!nr_devices);
- devices_info = kmalloc_array(nr_devices, sizeof(*devices_info),
+ devices_info = kmalloc(sizeof(*devices_info) * nr_devices,
GFP_NOFS);
if (!devices_info)
return -ENOMEM;
@@ -1794,25 +1789,7 @@ static void btrfs_print_info(void)
static int btrfs_run_sanity_tests(void)
{
- int ret;
-
- ret = btrfs_init_test_fs();
- if (ret)
- return ret;
-
- ret = btrfs_test_free_space_cache();
- if (ret)
- goto out;
- ret = btrfs_test_extent_buffer_operations();
- if (ret)
- goto out;
- ret = btrfs_test_extent_io();
- if (ret)
- goto out;
- ret = btrfs_test_inodes();
-out:
- btrfs_destroy_test_fs();
- return ret;
+ return btrfs_test_free_space_cache();
}
static int __init init_btrfs_fs(void)
diff --git a/fs/btrfs/tests/btrfs-tests.c b/fs/btrfs/tests/btrfs-tests.c
deleted file mode 100644
index 757ef00..0000000
--- a/fs/btrfs/tests/btrfs-tests.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 Fusion IO. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License v2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- */
-
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/magic.h>
-#include "btrfs-tests.h"
-#include "../ctree.h"
-
-static struct vfsmount *test_mnt = NULL;
-
-static const struct super_operations btrfs_test_super_ops = {
- .alloc_inode = btrfs_alloc_inode,
- .destroy_inode = btrfs_test_destroy_inode,
-};
-
-static struct dentry *btrfs_test_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
-{
- return mount_pseudo(fs_type, "btrfs_test:", &btrfs_test_super_ops,
- NULL, BTRFS_TEST_MAGIC);
-}
-
-static struct file_system_type test_type = {
- .name = "btrfs_test_fs",
- .mount = btrfs_test_mount,
- .kill_sb = kill_anon_super,
-};
-
-struct inode *btrfs_new_test_inode(void)
-{
- return new_inode(test_mnt->mnt_sb);
-}
-
-int btrfs_init_test_fs(void)
-{
- int ret;
-
- ret = register_filesystem(&test_type);
- if (ret) {
- printk(KERN_ERR "btrfs: cannot register test file system\n");
- return ret;
- }
-
- test_mnt = kern_mount(&test_type);
- if (IS_ERR(test_mnt)) {
- printk(KERN_ERR "btrfs: cannot mount test file system\n");
- unregister_filesystem(&test_type);
- return ret;
- }
- return 0;
-}
-
-void btrfs_destroy_test_fs(void)
-{
- kern_unmount(test_mnt);
- unregister_filesystem(&test_type);
-}
diff --git a/fs/btrfs/tests/btrfs-tests.h b/fs/btrfs/tests/btrfs-tests.h
index b353bc8..5808776 100644
--- a/fs/btrfs/tests/btrfs-tests.h
+++ b/fs/btrfs/tests/btrfs-tests.h
@@ -24,36 +24,11 @@
#define test_msg(fmt, ...) pr_info("btrfs: selftest: " fmt, ##__VA_ARGS__)
int btrfs_test_free_space_cache(void);
-int btrfs_test_extent_buffer_operations(void);
-int btrfs_test_extent_io(void);
-int btrfs_test_inodes(void);
-int btrfs_init_test_fs(void);
-void btrfs_destroy_test_fs(void);
-struct inode *btrfs_new_test_inode(void);
#else
static inline int btrfs_test_free_space_cache(void)
{
return 0;
}
-static inline int btrfs_test_extent_buffer_operations(void)
-{
- return 0;
-}
-static inline int btrfs_init_test_fs(void)
-{
- return 0;
-}
-static inline void btrfs_destroy_test_fs(void)
-{
-}
-static inline int btrfs_test_extent_io(void)
-{
- return 0;
-}
-static inline int btrfs_test_inodes(void)
-{
- return 0;
-}
#endif
#endif
diff --git a/fs/btrfs/tests/extent-buffer-tests.c b/fs/btrfs/tests/extent-buffer-tests.c
deleted file mode 100644
index cc286ce..0000000
--- a/fs/btrfs/tests/extent-buffer-tests.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2013 Fusion IO. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License v2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- */
-
-#include <linux/slab.h>
-#include "btrfs-tests.h"
-#include "../ctree.h"
-#include "../extent_io.h"
-#include "../disk-io.h"
-
-static int test_btrfs_split_item(void)
-{
- struct btrfs_path *path;
- struct btrfs_root *root;
- struct extent_buffer *eb;
- struct btrfs_item *item;
- char *value = "mary had a little lamb";
- char *split1 = "mary had a little";
- char *split2 = " lamb";
- char *split3 = "mary";
- char *split4 = " had a little";
- char buf[32];
- struct btrfs_key key;
- u32 value_len = strlen(value);
- int ret = 0;
-
- test_msg("Running btrfs_split_item tests\n");
-
- root = btrfs_alloc_dummy_root();
- if (IS_ERR(root)) {
- test_msg("Could not allocate root\n");
- return PTR_ERR(root);
- }
-
- path = btrfs_alloc_path();
- if (!path) {
- test_msg("Could not allocate path\n");
- kfree(root);
- return -ENOMEM;
- }
-
- path->nodes[0] = eb = alloc_dummy_extent_buffer(0, 4096);
- if (!eb) {
- test_msg("Could not allocate dummy buffer\n");
- ret = -ENOMEM;
- goto out;
- }
- path->slots[0] = 0;
-
- key.objectid = 0;
- key.type = BTRFS_EXTENT_CSUM_KEY;
- key.offset = 0;
-
- setup_items_for_insert(root, path, &key, &value_len, value_len,
- value_len + sizeof(struct btrfs_item), 1);
- item = btrfs_item_nr(0);
- write_extent_buffer(eb, value, btrfs_item_ptr_offset(eb, 0),
- value_len);
-
- key.offset = 3;
-
- /*
- * Passing NULL trans here should be safe because we have plenty of
- * space in this leaf to split the item without having to split the
- * leaf.
- */
- ret = btrfs_split_item(NULL, root, path, &key, 17);
- if (ret) {
- test_msg("Split item failed %d\n", ret);
- goto out;
- }
-
- /*
- * Read the first slot, it should have the original key and contain only
- * 'mary had a little'
- */
- btrfs_item_key_to_cpu(eb, &key, 0);
- if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
- key.offset != 0) {
- test_msg("Invalid key at slot 0\n");
- ret = -EINVAL;
- goto out;
- }
-
- item = btrfs_item_nr(0);
- if (btrfs_item_size(eb, item) != strlen(split1)) {
- test_msg("Invalid len in the first split\n");
- ret = -EINVAL;
- goto out;
- }
-
- read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 0),
- strlen(split1));
- if (memcmp(buf, split1, strlen(split1))) {
- test_msg("Data in the buffer doesn't match what it should "
- "in the first split have='%.*s' want '%s'\n",
- (int)strlen(split1), buf, split1);
- ret = -EINVAL;
- goto out;
- }
-
- btrfs_item_key_to_cpu(eb, &key, 1);
- if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
- key.offset != 3) {
- test_msg("Invalid key at slot 1\n");
- ret = -EINVAL;
- goto out;
- }
-
- item = btrfs_item_nr(1);
- if (btrfs_item_size(eb, item) != strlen(split2)) {
- test_msg("Invalid len in the second split\n");
- ret = -EINVAL;
- goto out;
- }
-
- read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 1),
- strlen(split2));
- if (memcmp(buf, split2, strlen(split2))) {
- test_msg("Data in the buffer doesn't match what it should "
- "in the second split\n");
- ret = -EINVAL;
- goto out;
- }
-
- key.offset = 1;
- /* Do it again so we test memmoving the other items in the leaf */
- ret = btrfs_split_item(NULL, root, path, &key, 4);
- if (ret) {
- test_msg("Second split item failed %d\n", ret);
- goto out;
- }
-
- btrfs_item_key_to_cpu(eb, &key, 0);
- if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
- key.offset != 0) {
- test_msg("Invalid key at slot 0\n");
- ret = -EINVAL;
- goto out;
- }
-
- item = btrfs_item_nr(0);
- if (btrfs_item_size(eb, item) != strlen(split3)) {
- test_msg("Invalid len in the first split\n");
- ret = -EINVAL;
- goto out;
- }
-
- read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 0),
- strlen(split3));
- if (memcmp(buf, split3, strlen(split3))) {
- test_msg("Data in the buffer doesn't match what it should "
- "in the third split");
- ret = -EINVAL;
- goto out;
- }
-
- btrfs_item_key_to_cpu(eb, &key, 1);
- if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
- key.offset != 1) {
- test_msg("Invalid key at slot 1\n");
- ret = -EINVAL;
- goto out;
- }
-
- item = btrfs_item_nr(1);
- if (btrfs_item_size(eb, item) != strlen(split4)) {
- test_msg("Invalid len in the second split\n");
- ret = -EINVAL;
- goto out;
- }
-
- read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 1),
- strlen(split4));
- if (memcmp(buf, split4, strlen(split4))) {
- test_msg("Data in the buffer doesn't match what it should "
- "in the fourth split\n");
- ret = -EINVAL;
- goto out;
- }
-
- btrfs_item_key_to_cpu(eb, &key, 2);
- if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
- key.offset != 3) {
- test_msg("Invalid key at slot 2\n");
- ret = -EINVAL;
- goto out;
- }
-
- item = btrfs_item_nr(2);
- if (btrfs_item_size(eb, item) != strlen(split2)) {
- test_msg("Invalid len in the second split\n");
- ret = -EINVAL;
- goto out;
- }
-
- read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 2),
- strlen(split2));
- if (memcmp(buf, split2, strlen(split2))) {
- test_msg("Data in the buffer doesn't match what it should "
- "in the last chunk\n");
- ret = -EINVAL;
- goto out;
- }
-out:
- btrfs_free_path(path);
- kfree(root);
- return ret;
-}
-
-int btrfs_test_extent_buffer_operations(void)
-{
- test_msg("Running extent buffer operation tests");
- return test_btrfs_split_item();
-}
diff --git a/fs/btrfs/tests/extent-io-tests.c b/fs/btrfs/tests/extent-io-tests.c
deleted file mode 100644
index 7e99c2f..0000000
--- a/fs/btrfs/tests/extent-io-tests.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2013 Fusion IO. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License v2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- */
-
-#include <linux/pagemap.h>
-#include <linux/sched.h>
-#include "btrfs-tests.h"
-#include "../extent_io.h"
-
-#define PROCESS_UNLOCK (1 << 0)
-#define PROCESS_RELEASE (1 << 1)
-#define PROCESS_TEST_LOCKED (1 << 2)
-
-static noinline int process_page_range(struct inode *inode, u64 start, u64 end,
- unsigned long flags)
-{
- int ret;
- struct page *pages[16];
- unsigned long index = start >> PAGE_CACHE_SHIFT;
- unsigned long end_index = end >> PAGE_CACHE_SHIFT;
- unsigned long nr_pages = end_index - index + 1;
- int i;
- int count = 0;
- int loops = 0;
-
- while (nr_pages > 0) {
- ret = find_get_pages_contig(inode->i_mapping, index,
- min_t(unsigned long, nr_pages,
- ARRAY_SIZE(pages)), pages);
- for (i = 0; i < ret; i++) {
- if (flags & PROCESS_TEST_LOCKED &&
- !PageLocked(pages[i]))
- count++;
- if (flags & PROCESS_UNLOCK && PageLocked(pages[i]))
- unlock_page(pages[i]);
- page_cache_release(pages[i]);
- if (flags & PROCESS_RELEASE)
- page_cache_release(pages[i]);
- }
- nr_pages -= ret;
- index += ret;
- cond_resched();
- loops++;
- if (loops > 100000) {
- printk(KERN_ERR "stuck in a loop, start %Lu, end %Lu, nr_pages %lu, ret %d\n", start, end, nr_pages, ret);
- break;
- }
- }
- return count;
-}
-
-static int test_find_delalloc(void)
-{
- struct inode *inode;
- struct extent_io_tree tmp;
- struct page *page;
- struct page *locked_page = NULL;
- unsigned long index = 0;
- u64 total_dirty = 256 * 1024 * 1024;
- u64 max_bytes = 128 * 1024 * 1024;
- u64 start, end, test_start;
- u64 found;
- int ret = -EINVAL;
-
- inode = btrfs_new_test_inode();
- if (!inode) {
- test_msg("Failed to allocate test inode\n");
- return -ENOMEM;
- }
-
- extent_io_tree_init(&tmp, &inode->i_data);
-
- /*
- * First go through and create and mark all of our pages dirty, we pin
- * everything to make sure our pages don't get evicted and screw up our
- * test.
- */
- for (index = 0; index < (total_dirty >> PAGE_CACHE_SHIFT); index++) {
- page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
- if (!page) {
- test_msg("Failed to allocate test page\n");
- ret = -ENOMEM;
- goto out;
- }
- SetPageDirty(page);
- if (index) {
- unlock_page(page);
- } else {
- page_cache_get(page);
- locked_page = page;
- }
- }
-
- /* Test this scenario
- * |--- delalloc ---|
- * |--- search ---|
- */
- set_extent_delalloc(&tmp, 0, 4095, NULL, GFP_NOFS);
- start = 0;
- end = 0;
- found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
- &end, max_bytes);
- if (!found) {
- test_msg("Should have found at least one delalloc\n");
- goto out_bits;
- }
- if (start != 0 || end != 4095) {
- test_msg("Expected start 0 end 4095, got start %Lu end %Lu\n",
- start, end);
- goto out_bits;
- }
- unlock_extent(&tmp, start, end);
- unlock_page(locked_page);
- page_cache_release(locked_page);
-
- /*
- * Test this scenario
- *
- * |--- delalloc ---|
- * |--- search ---|
- */
- test_start = 64 * 1024 * 1024;
- locked_page = find_lock_page(inode->i_mapping,
- test_start >> PAGE_CACHE_SHIFT);
- if (!locked_page) {
- test_msg("Couldn't find the locked page\n");
- goto out_bits;
- }
- set_extent_delalloc(&tmp, 4096, max_bytes - 1, NULL, GFP_NOFS);
- start = test_start;
- end = 0;
- found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
- &end, max_bytes);
- if (!found) {
- test_msg("Couldn't find delalloc in our range\n");
- goto out_bits;
- }
- if (start != test_start || end != max_bytes - 1) {
- test_msg("Expected start %Lu end %Lu, got start %Lu, end "
- "%Lu\n", test_start, max_bytes - 1, start, end);
- goto out_bits;
- }
- if (process_page_range(inode, start, end,
- PROCESS_TEST_LOCKED | PROCESS_UNLOCK)) {
- test_msg("There were unlocked pages in the range\n");
- goto out_bits;
- }
- unlock_extent(&tmp, start, end);
- /* locked_page was unlocked above */
- page_cache_release(locked_page);
-
- /*
- * Test this scenario
- * |--- delalloc ---|
- * |--- search ---|
- */
- test_start = max_bytes + 4096;
- locked_page = find_lock_page(inode->i_mapping, test_start >>
- PAGE_CACHE_SHIFT);
- if (!locked_page) {
- test_msg("Could'nt find the locked page\n");
- goto out_bits;
- }
- start = test_start;
- end = 0;
- found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
- &end, max_bytes);
- if (found) {
- test_msg("Found range when we shouldn't have\n");
- goto out_bits;
- }
- if (end != (u64)-1) {
- test_msg("Did not return the proper end offset\n");
- goto out_bits;
- }
-
- /*
- * Test this scenario
- * [------- delalloc -------|
- * [max_bytes]|-- search--|
- *
- * We are re-using our test_start from above since it works out well.
- */
- set_extent_delalloc(&tmp, max_bytes, total_dirty - 1, NULL, GFP_NOFS);
- start = test_start;
- end = 0;
- found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
- &end, max_bytes);
- if (!found) {
- test_msg("Didn't find our range\n");
- goto out_bits;
- }
- if (start != test_start || end != total_dirty - 1) {
- test_msg("Expected start %Lu end %Lu, got start %Lu end %Lu\n",
- test_start, total_dirty - 1, start, end);
- goto out_bits;
- }
- if (process_page_range(inode, start, end,
- PROCESS_TEST_LOCKED | PROCESS_UNLOCK)) {
- test_msg("Pages in range were not all locked\n");
- goto out_bits;
- }
- unlock_extent(&tmp, start, end);
-
- /*
- * Now to test where we run into a page that is no longer dirty in the
- * range we want to find.
- */
- page = find_get_page(inode->i_mapping, (max_bytes + (1 * 1024 * 1024))
- >> PAGE_CACHE_SHIFT);
- if (!page) {
- test_msg("Couldn't find our page\n");
- goto out_bits;
- }
- ClearPageDirty(page);
- page_cache_release(page);
-
- /* We unlocked it in the previous test */
- lock_page(locked_page);
- start = test_start;
- end = 0;
- /*
- * Currently if we fail to find dirty pages in the delalloc range we
- * will adjust max_bytes down to PAGE_CACHE_SIZE and then re-search. If
- * this changes at any point in the future we will need to fix this
- * tests expected behavior.
- */
- found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
- &end, max_bytes);
- if (!found) {
- test_msg("Didn't find our range\n");
- goto out_bits;
- }
- if (start != test_start && end != test_start + PAGE_CACHE_SIZE - 1) {
- test_msg("Expected start %Lu end %Lu, got start %Lu end %Lu\n",
- test_start, test_start + PAGE_CACHE_SIZE - 1, start,
- end);
- goto out_bits;
- }
- if (process_page_range(inode, start, end, PROCESS_TEST_LOCKED |
- PROCESS_UNLOCK)) {
- test_msg("Pages in range were not all locked\n");
- goto out_bits;
- }
- ret = 0;
-out_bits:
- clear_extent_bits(&tmp, 0, total_dirty - 1,
- (unsigned long)-1, GFP_NOFS);
-out:
- if (locked_page)
- page_cache_release(locked_page);
- process_page_range(inode, 0, total_dirty - 1,
- PROCESS_UNLOCK | PROCESS_RELEASE);
- iput(inode);
- return ret;
-}
-
-int btrfs_test_extent_io(void)
-{
- test_msg("Running find delalloc tests\n");
- return test_find_delalloc();
-}
diff --git a/fs/btrfs/tests/inode-tests.c b/fs/btrfs/tests/inode-tests.c
deleted file mode 100644
index 397d1f9..0000000
--- a/fs/btrfs/tests/inode-tests.c
+++ /dev/null
@@ -1,955 +0,0 @@
-/*
- * Copyright (C) 2013 Fusion IO. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License v2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- */
-
-#include "btrfs-tests.h"
-#include "../ctree.h"
-#include "../btrfs_inode.h"
-#include "../disk-io.h"
-#include "../extent_io.h"
-#include "../volumes.h"
-
-static struct btrfs_fs_info *alloc_dummy_fs_info(void)
-{
- struct btrfs_fs_info *fs_info = kzalloc(sizeof(struct btrfs_fs_info),
- GFP_NOFS);
- if (!fs_info)
- return fs_info;
- fs_info->fs_devices = kzalloc(sizeof(struct btrfs_fs_devices),
- GFP_NOFS);
- if (!fs_info->fs_devices) {
- kfree(fs_info);
- return NULL;
- }
- return fs_info;
-}
-static void free_dummy_root(struct btrfs_root *root)
-{
- if (!root)
- return;
- if (root->fs_info) {
- kfree(root->fs_info->fs_devices);
- kfree(root->fs_info);
- }
- if (root->node)
- free_extent_buffer(root->node);
- kfree(root);
-}
-
-static void insert_extent(struct btrfs_root *root, u64 start, u64 len,
- u64 ram_bytes, u64 offset, u64 disk_bytenr,
- u64 disk_len, u32 type, u8 compression, int slot)
-{
- struct btrfs_path path;
- struct btrfs_file_extent_item *fi;
- struct extent_buffer *leaf = root->node;
- struct btrfs_key key;
- u32 value_len = sizeof(struct btrfs_file_extent_item);
-
- if (type == BTRFS_FILE_EXTENT_INLINE)
- value_len += len;
- memset(&path, 0, sizeof(path));
-
- path.nodes[0] = leaf;
- path.slots[0] = slot;
-
- key.objectid = BTRFS_FIRST_FREE_OBJECTID;
- key.type = BTRFS_EXTENT_DATA_KEY;
- key.offset = start;
-
- setup_items_for_insert(root, &path, &key, &value_len, value_len,
- value_len + sizeof(struct btrfs_item), 1);
- fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
- btrfs_set_file_extent_generation(leaf, fi, 1);
- btrfs_set_file_extent_type(leaf, fi, type);
- btrfs_set_file_extent_disk_bytenr(leaf, fi, disk_bytenr);
- btrfs_set_file_extent_disk_num_bytes(leaf, fi, disk_len);
- btrfs_set_file_extent_offset(leaf, fi, offset);
- btrfs_set_file_extent_num_bytes(leaf, fi, len);
- btrfs_set_file_extent_ram_bytes(leaf, fi, ram_bytes);
- btrfs_set_file_extent_compression(leaf, fi, compression);
- btrfs_set_file_extent_encryption(leaf, fi, 0);
- btrfs_set_file_extent_other_encoding(leaf, fi, 0);
-}
-
-static void insert_inode_item_key(struct btrfs_root *root)
-{
- struct btrfs_path path;
- struct extent_buffer *leaf = root->node;
- struct btrfs_key key;
- u32 value_len = 0;
-
- memset(&path, 0, sizeof(path));
-
- path.nodes[0] = leaf;
- path.slots[0] = 0;
-
- key.objectid = BTRFS_INODE_ITEM_KEY;
- key.type = BTRFS_INODE_ITEM_KEY;
- key.offset = 0;
-
- setup_items_for_insert(root, &path, &key, &value_len, value_len,
- value_len + sizeof(struct btrfs_item), 1);
-}
-
-/*
- * Build the most complicated map of extents the earth has ever seen. We want
- * this so we can test all of the corner cases of btrfs_get_extent. Here is a
- * diagram of how the extents will look though this may not be possible we still
- * want to make sure everything acts normally (the last number is not inclusive)
- *
- * [0 - 5][5 - 6][6 - 10][10 - 4096][ 4096 - 8192 ][8192 - 12288]
- * [hole ][inline][ hole ][ regular ][regular1 split][ hole ]
- *
- * [ 12288 - 20480][20480 - 24576][ 24576 - 28672 ][28672 - 36864][36864 - 45056]
- * [regular1 split][ prealloc1 ][prealloc1 written][ prealloc1 ][ compressed ]
- *
- * [45056 - 49152][49152-53248][53248-61440][61440-65536][ 65536+81920 ]
- * [ compressed1 ][ regular ][compressed1][ regular ][ hole but no extent]
- *
- * [81920-86016]
- * [ regular ]
- */
-static void setup_file_extents(struct btrfs_root *root)
-{
- int slot = 0;
- u64 disk_bytenr = 1 * 1024 * 1024;
- u64 offset = 0;
-
- /* First we want a hole */
- insert_extent(root, offset, 5, 5, 0, 0, 0, BTRFS_FILE_EXTENT_REG, 0,
- slot);
- slot++;
- offset += 5;
-
- /*
- * Now we want an inline extent, I don't think this is possible but hey
- * why not? Also keep in mind if we have an inline extent it counts as
- * the whole first page. If we were to expand it we would have to cow
- * and we wouldn't have an inline extent anymore.
- */
- insert_extent(root, offset, 1, 1, 0, 0, 0, BTRFS_FILE_EXTENT_INLINE, 0,
- slot);
- slot++;
- offset = 4096;
-
- /* Now another hole */
- insert_extent(root, offset, 4, 4, 0, 0, 0, BTRFS_FILE_EXTENT_REG, 0,
- slot);
- slot++;
- offset += 4;
-
- /* Now for a regular extent */
- insert_extent(root, offset, 4095, 4095, 0, disk_bytenr, 4096,
- BTRFS_FILE_EXTENT_REG, 0, slot);
- slot++;
- disk_bytenr += 4096;
- offset += 4095;
-
- /*
- * Now for 3 extents that were split from a hole punch so we test
- * offsets properly.
- */
- insert_extent(root, offset, 4096, 16384, 0, disk_bytenr, 16384,
- BTRFS_FILE_EXTENT_REG, 0, slot);
- slot++;
- offset += 4096;
- insert_extent(root, offset, 4096, 4096, 0, 0, 0, BTRFS_FILE_EXTENT_REG,
- 0, slot);
- slot++;
- offset += 4096;
- insert_extent(root, offset, 8192, 16384, 8192, disk_bytenr, 16384,
- BTRFS_FILE_EXTENT_REG, 0, slot);
- slot++;
- offset += 8192;
- disk_bytenr += 16384;
-
- /* Now for a unwritten prealloc extent */
- insert_extent(root, offset, 4096, 4096, 0, disk_bytenr, 4096,
- BTRFS_FILE_EXTENT_PREALLOC, 0, slot);
- slot++;
- offset += 4096;
-
- /*
- * We want to jack up disk_bytenr a little more so the em stuff doesn't
- * merge our records.
- */
- disk_bytenr += 8192;
-
- /*
- * Now for a partially written prealloc extent, basically the same as
- * the hole punch example above. Ram_bytes never changes when you mark
- * extents written btw.
- */
- insert_extent(root, offset, 4096, 16384, 0, disk_bytenr, 16384,
- BTRFS_FILE_EXTENT_PREALLOC, 0, slot);
- slot++;
- offset += 4096;
- insert_extent(root, offset, 4096, 16384, 4096, disk_bytenr, 16384,
- BTRFS_FILE_EXTENT_REG, 0, slot);
- slot++;
- offset += 4096;
- insert_extent(root, offset, 8192, 16384, 8192, disk_bytenr, 16384,
- BTRFS_FILE_EXTENT_PREALLOC, 0, slot);
- slot++;
- offset += 8192;
- disk_bytenr += 16384;
-
- /* Now a normal compressed extent */
- insert_extent(root, offset, 8192, 8192, 0, disk_bytenr, 4096,
- BTRFS_FILE_EXTENT_REG, BTRFS_COMPRESS_ZLIB, slot);
- slot++;
- offset += 8192;
- /* No merges */
- disk_bytenr += 8192;
-
- /* Now a split compressed extent */
- insert_extent(root, offset, 4096, 16384, 0, disk_bytenr, 4096,
- BTRFS_FILE_EXTENT_REG, BTRFS_COMPRESS_ZLIB, slot);
- slot++;
- offset += 4096;
- insert_extent(root, offset, 4096, 4096, 0, disk_bytenr + 4096, 4096,
- BTRFS_FILE_EXTENT_REG, 0, slot);
- slot++;
- offset += 4096;
- insert_extent(root, offset, 8192, 16384, 8192, disk_bytenr, 4096,
- BTRFS_FILE_EXTENT_REG, BTRFS_COMPRESS_ZLIB, slot);
- slot++;
- offset += 8192;
- disk_bytenr += 8192;
-
- /* Now extents that have a hole but no hole extent */
- insert_extent(root, offset, 4096, 4096, 0, disk_bytenr, 4096,
- BTRFS_FILE_EXTENT_REG, 0, slot);
- slot++;
- offset += 16384;
- disk_bytenr += 4096;
- insert_extent(root, offset, 4096, 4096, 0, disk_bytenr, 4096,
- BTRFS_FILE_EXTENT_REG, 0, slot);
-}
-
-static unsigned long prealloc_only = 0;
-static unsigned long compressed_only = 0;
-static unsigned long vacancy_only = 0;
-
-static noinline int test_btrfs_get_extent(void)
-{
- struct inode *inode = NULL;
- struct btrfs_root *root = NULL;
- struct extent_map *em = NULL;
- u64 orig_start;
- u64 disk_bytenr;
- u64 offset;
- int ret = -ENOMEM;
-
- inode = btrfs_new_test_inode();
- if (!inode) {
- test_msg("Couldn't allocate inode\n");
- return ret;
- }
-
- BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY;
- BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID;
- BTRFS_I(inode)->location.offset = 0;
-
- root = btrfs_alloc_dummy_root();
- if (IS_ERR(root)) {
- test_msg("Couldn't allocate root\n");
- goto out;
- }
-
- /*
- * We do this since btrfs_get_extent wants to assign em->bdev to
- * root->fs_info->fs_devices->latest_bdev.
- */
- root->fs_info = alloc_dummy_fs_info();
- if (!root->fs_info) {
- test_msg("Couldn't allocate dummy fs info\n");
- goto out;
- }
-
- root->node = alloc_dummy_extent_buffer(0, 4096);
- if (!root->node) {
- test_msg("Couldn't allocate dummy buffer\n");
- goto out;
- }
-
- /*
- * We will just free a dummy node if it's ref count is 2 so we need an
- * extra ref so our searches don't accidently release our page.
- */
- extent_buffer_get(root->node);
- btrfs_set_header_nritems(root->node, 0);
- btrfs_set_header_level(root->node, 0);
- ret = -EINVAL;
-
- /* First with no extents */
- BTRFS_I(inode)->root = root;
- em = btrfs_get_extent(inode, NULL, 0, 0, 4096, 0);
- if (IS_ERR(em)) {
- em = NULL;
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start != EXTENT_MAP_HOLE) {
- test_msg("Expected a hole, got %llu\n", em->block_start);
- goto out;
- }
- if (!test_bit(EXTENT_FLAG_VACANCY, &em->flags)) {
- test_msg("Vacancy flag wasn't set properly\n");
- goto out;
- }
- free_extent_map(em);
- btrfs_drop_extent_cache(inode, 0, (u64)-1, 0);
-
- /*
- * All of the magic numbers are based on the mapping setup in
- * setup_file_extents, so if you change anything there you need to
- * update the comment and update the expected values below.
- */
- setup_file_extents(root);
-
- em = btrfs_get_extent(inode, NULL, 0, 0, (u64)-1, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start != EXTENT_MAP_HOLE) {
- test_msg("Expected a hole, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != 0 || em->len != 5) {
- test_msg("Unexpected extent wanted start 0 len 5, got start "
- "%llu len %llu\n", em->start, em->len);
- goto out;
- }
- if (em->flags != 0) {
- test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
- goto out;
- }
- offset = em->start + em->len;
- free_extent_map(em);
-
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start != EXTENT_MAP_INLINE) {
- test_msg("Expected an inline, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 4091) {
- test_msg("Unexpected extent wanted start %llu len 1, got start "
- "%llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != 0) {
- test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
- goto out;
- }
- /*
- * We don't test anything else for inline since it doesn't get set
- * unless we have a page for it to write into. Maybe we should change
- * this?
- */
- offset = em->start + em->len;
- free_extent_map(em);
-
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start != EXTENT_MAP_HOLE) {
- test_msg("Expected a hole, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 4) {
- test_msg("Unexpected extent wanted start %llu len 4, got start "
- "%llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != 0) {
- test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
- goto out;
- }
- offset = em->start + em->len;
- free_extent_map(em);
-
- /* Regular extent */
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
- test_msg("Expected a real extent, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 4095) {
- test_msg("Unexpected extent wanted start %llu len 4095, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != 0) {
- test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
- goto out;
- }
- if (em->orig_start != em->start) {
- test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
- em->orig_start);
- goto out;
- }
- offset = em->start + em->len;
- free_extent_map(em);
-
- /* The next 3 are split extents */
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
- test_msg("Expected a real extent, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 4096) {
- test_msg("Unexpected extent wanted start %llu len 4096, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != 0) {
- test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
- goto out;
- }
- if (em->orig_start != em->start) {
- test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
- em->orig_start);
- goto out;
- }
- disk_bytenr = em->block_start;
- orig_start = em->start;
- offset = em->start + em->len;
- free_extent_map(em);
-
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start != EXTENT_MAP_HOLE) {
- test_msg("Expected a hole, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 4096) {
- test_msg("Unexpected extent wanted start %llu len 4096, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != 0) {
- test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
- goto out;
- }
- offset = em->start + em->len;
- free_extent_map(em);
-
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
- test_msg("Expected a real extent, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 8192) {
- test_msg("Unexpected extent wanted start %llu len 8192, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != 0) {
- test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
- goto out;
- }
- if (em->orig_start != orig_start) {
- test_msg("Wrong orig offset, want %llu, have %llu\n",
- orig_start, em->orig_start);
- goto out;
- }
- disk_bytenr += (em->start - orig_start);
- if (em->block_start != disk_bytenr) {
- test_msg("Wrong block start, want %llu, have %llu\n",
- disk_bytenr, em->block_start);
- goto out;
- }
- offset = em->start + em->len;
- free_extent_map(em);
-
- /* Prealloc extent */
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
- test_msg("Expected a real extent, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 4096) {
- test_msg("Unexpected extent wanted start %llu len 4096, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != prealloc_only) {
- test_msg("Unexpected flags set, want %lu have %lu\n",
- prealloc_only, em->flags);
- goto out;
- }
- if (em->orig_start != em->start) {
- test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
- em->orig_start);
- goto out;
- }
- offset = em->start + em->len;
- free_extent_map(em);
-
- /* The next 3 are a half written prealloc extent */
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
- test_msg("Expected a real extent, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 4096) {
- test_msg("Unexpected extent wanted start %llu len 4096, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != prealloc_only) {
- test_msg("Unexpected flags set, want %lu have %lu\n",
- prealloc_only, em->flags);
- goto out;
- }
- if (em->orig_start != em->start) {
- test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
- em->orig_start);
- goto out;
- }
- disk_bytenr = em->block_start;
- orig_start = em->start;
- offset = em->start + em->len;
- free_extent_map(em);
-
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start >= EXTENT_MAP_HOLE) {
- test_msg("Expected a real extent, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 4096) {
- test_msg("Unexpected extent wanted start %llu len 4096, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != 0) {
- test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
- goto out;
- }
- if (em->orig_start != orig_start) {
- test_msg("Unexpected orig offset, wanted %llu, have %llu\n",
- orig_start, em->orig_start);
- goto out;
- }
- if (em->block_start != (disk_bytenr + (em->start - em->orig_start))) {
- test_msg("Unexpected block start, wanted %llu, have %llu\n",
- disk_bytenr + (em->start - em->orig_start),
- em->block_start);
- goto out;
- }
- offset = em->start + em->len;
- free_extent_map(em);
-
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
- test_msg("Expected a real extent, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 8192) {
- test_msg("Unexpected extent wanted start %llu len 8192, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != prealloc_only) {
- test_msg("Unexpected flags set, want %lu have %lu\n",
- prealloc_only, em->flags);
- goto out;
- }
- if (em->orig_start != orig_start) {
- test_msg("Wrong orig offset, want %llu, have %llu\n", orig_start,
- em->orig_start);
- goto out;
- }
- if (em->block_start != (disk_bytenr + (em->start - em->orig_start))) {
- test_msg("Unexpected block start, wanted %llu, have %llu\n",
- disk_bytenr + (em->start - em->orig_start),
- em->block_start);
- goto out;
- }
- offset = em->start + em->len;
- free_extent_map(em);
-
- /* Now for the compressed extent */
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
- test_msg("Expected a real extent, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 8192) {
- test_msg("Unexpected extent wanted start %llu len 8192, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != compressed_only) {
- test_msg("Unexpected flags set, want %lu have %lu\n",
- compressed_only, em->flags);
- goto out;
- }
- if (em->orig_start != em->start) {
- test_msg("Wrong orig offset, want %llu, have %llu\n",
- em->start, em->orig_start);
- goto out;
- }
- if (em->compress_type != BTRFS_COMPRESS_ZLIB) {
- test_msg("Unexpected compress type, wanted %d, got %d\n",
- BTRFS_COMPRESS_ZLIB, em->compress_type);
- goto out;
- }
- offset = em->start + em->len;
- free_extent_map(em);
-
- /* Split compressed extent */
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
- test_msg("Expected a real extent, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 4096) {
- test_msg("Unexpected extent wanted start %llu len 4096, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != compressed_only) {
- test_msg("Unexpected flags set, want %lu have %lu\n",
- compressed_only, em->flags);
- goto out;
- }
- if (em->orig_start != em->start) {
- test_msg("Wrong orig offset, want %llu, have %llu\n",
- em->start, em->orig_start);
- goto out;
- }
- if (em->compress_type != BTRFS_COMPRESS_ZLIB) {
- test_msg("Unexpected compress type, wanted %d, got %d\n",
- BTRFS_COMPRESS_ZLIB, em->compress_type);
- goto out;
- }
- disk_bytenr = em->block_start;
- orig_start = em->start;
- offset = em->start + em->len;
- free_extent_map(em);
-
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
- test_msg("Expected a real extent, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 4096) {
- test_msg("Unexpected extent wanted start %llu len 4096, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != 0) {
- test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
- goto out;
- }
- if (em->orig_start != em->start) {
- test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
- em->orig_start);
- goto out;
- }
- offset = em->start + em->len;
- free_extent_map(em);
-
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start != disk_bytenr) {
- test_msg("Block start does not match, want %llu got %llu\n",
- disk_bytenr, em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 8192) {
- test_msg("Unexpected extent wanted start %llu len 8192, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != compressed_only) {
- test_msg("Unexpected flags set, want %lu have %lu\n",
- compressed_only, em->flags);
- goto out;
- }
- if (em->orig_start != orig_start) {
- test_msg("Wrong orig offset, want %llu, have %llu\n",
- em->start, orig_start);
- goto out;
- }
- if (em->compress_type != BTRFS_COMPRESS_ZLIB) {
- test_msg("Unexpected compress type, wanted %d, got %d\n",
- BTRFS_COMPRESS_ZLIB, em->compress_type);
- goto out;
- }
- offset = em->start + em->len;
- free_extent_map(em);
-
- /* A hole between regular extents but no hole extent */
- em = btrfs_get_extent(inode, NULL, 0, offset + 6, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
- test_msg("Expected a real extent, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 4096) {
- test_msg("Unexpected extent wanted start %llu len 4096, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != 0) {
- test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
- goto out;
- }
- if (em->orig_start != em->start) {
- test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
- em->orig_start);
- goto out;
- }
- offset = em->start + em->len;
- free_extent_map(em);
-
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096 * 1024, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start != EXTENT_MAP_HOLE) {
- test_msg("Expected a hole extent, got %llu\n", em->block_start);
- goto out;
- }
- /*
- * Currently we just return a length that we requested rather than the
- * length of the actual hole, if this changes we'll have to change this
- * test.
- */
- if (em->start != offset || em->len != 12288) {
- test_msg("Unexpected extent wanted start %llu len 12288, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != vacancy_only) {
- test_msg("Unexpected flags set, want %lu have %lu\n",
- vacancy_only, em->flags);
- goto out;
- }
- if (em->orig_start != em->start) {
- test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
- em->orig_start);
- goto out;
- }
- offset = em->start + em->len;
- free_extent_map(em);
-
- em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
- test_msg("Expected a real extent, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != offset || em->len != 4096) {
- test_msg("Unexpected extent wanted start %llu len 4096, got "
- "start %llu len %llu\n", offset, em->start, em->len);
- goto out;
- }
- if (em->flags != 0) {
- test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
- goto out;
- }
- if (em->orig_start != em->start) {
- test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
- em->orig_start);
- goto out;
- }
- ret = 0;
-out:
- if (!IS_ERR(em))
- free_extent_map(em);
- iput(inode);
- free_dummy_root(root);
- return ret;
-}
-
-static int test_hole_first(void)
-{
- struct inode *inode = NULL;
- struct btrfs_root *root = NULL;
- struct extent_map *em = NULL;
- int ret = -ENOMEM;
-
- inode = btrfs_new_test_inode();
- if (!inode) {
- test_msg("Couldn't allocate inode\n");
- return ret;
- }
-
- BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY;
- BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID;
- BTRFS_I(inode)->location.offset = 0;
-
- root = btrfs_alloc_dummy_root();
- if (IS_ERR(root)) {
- test_msg("Couldn't allocate root\n");
- goto out;
- }
-
- root->fs_info = alloc_dummy_fs_info();
- if (!root->fs_info) {
- test_msg("Couldn't allocate dummy fs info\n");
- goto out;
- }
-
- root->node = alloc_dummy_extent_buffer(0, 4096);
- if (!root->node) {
- test_msg("Couldn't allocate dummy buffer\n");
- goto out;
- }
-
- extent_buffer_get(root->node);
- btrfs_set_header_nritems(root->node, 0);
- btrfs_set_header_level(root->node, 0);
- BTRFS_I(inode)->root = root;
- ret = -EINVAL;
-
- /*
- * Need a blank inode item here just so we don't confuse
- * btrfs_get_extent.
- */
- insert_inode_item_key(root);
- insert_extent(root, 4096, 4096, 4096, 0, 4096, 4096,
- BTRFS_FILE_EXTENT_REG, 0, 1);
- em = btrfs_get_extent(inode, NULL, 0, 0, 8192, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start != EXTENT_MAP_HOLE) {
- test_msg("Expected a hole, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != 0 || em->len != 4096) {
- test_msg("Unexpected extent wanted start 0 len 4096, got start "
- "%llu len %llu\n", em->start, em->len);
- goto out;
- }
- if (em->flags != vacancy_only) {
- test_msg("Wrong flags, wanted %lu, have %lu\n", vacancy_only,
- em->flags);
- goto out;
- }
- free_extent_map(em);
-
- em = btrfs_get_extent(inode, NULL, 0, 4096, 8192, 0);
- if (IS_ERR(em)) {
- test_msg("Got an error when we shouldn't have\n");
- goto out;
- }
- if (em->block_start != 4096) {
- test_msg("Expected a real extent, got %llu\n", em->block_start);
- goto out;
- }
- if (em->start != 4096 || em->len != 4096) {
- test_msg("Unexpected extent wanted start 4096 len 4096, got "
- "start %llu len %llu\n", em->start, em->len);
- goto out;
- }
- if (em->flags != 0) {
- test_msg("Unexpected flags set, wanted 0 got %lu\n",
- em->flags);
- goto out;
- }
- ret = 0;
-out:
- if (!IS_ERR(em))
- free_extent_map(em);
- iput(inode);
- free_dummy_root(root);
- return ret;
-}
-
-int btrfs_test_inodes(void)
-{
- int ret;
-
- set_bit(EXTENT_FLAG_COMPRESSED, &compressed_only);
- set_bit(EXTENT_FLAG_VACANCY, &vacancy_only);
- set_bit(EXTENT_FLAG_PREALLOC, &prealloc_only);
-
- test_msg("Running btrfs_get_extent tests\n");
- ret = test_btrfs_get_extent();
- if (ret)
- return ret;
- test_msg("Running hole first btrfs_get_extent test\n");
- return test_hole_first();
-}
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index c6a872a..8c81bdc 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -57,7 +57,7 @@ static unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = {
__TRANS_JOIN_NOLOCK),
};
-void btrfs_put_transaction(struct btrfs_transaction *transaction)
+static void put_transaction(struct btrfs_transaction *transaction)
{
WARN_ON(atomic_read(&transaction->use_count) == 0);
if (atomic_dec_and_test(&transaction->use_count)) {
@@ -332,7 +332,7 @@ static void wait_current_trans(struct btrfs_root *root)
wait_event(root->fs_info->transaction_wait,
cur_trans->state >= TRANS_STATE_UNBLOCKED ||
cur_trans->aborted);
- btrfs_put_transaction(cur_trans);
+ put_transaction(cur_trans);
} else {
spin_unlock(&root->fs_info->trans_lock);
}
@@ -353,17 +353,6 @@ static int may_wait_transaction(struct btrfs_root *root, int type)
return 0;
}
-static inline bool need_reserve_reloc_root(struct btrfs_root *root)
-{
- if (!root->fs_info->reloc_ctl ||
- !root->ref_cows ||
- root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID ||
- root->reloc_root)
- return false;
-
- return true;
-}
-
static struct btrfs_trans_handle *
start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
enum btrfs_reserve_flush_enum flush)
@@ -371,9 +360,8 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
struct btrfs_trans_handle *h;
struct btrfs_transaction *cur_trans;
u64 num_bytes = 0;
- u64 qgroup_reserved = 0;
- bool reloc_reserved = false;
int ret;
+ u64 qgroup_reserved = 0;
if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
return ERR_PTR(-EROFS);
@@ -402,14 +390,6 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
}
num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
- /*
- * Do the reservation for the relocation root creation
- */
- if (unlikely(need_reserve_reloc_root(root))) {
- num_bytes += root->nodesize;
- reloc_reserved = true;
- }
-
ret = btrfs_block_rsv_add(root,
&root->fs_info->trans_block_rsv,
num_bytes, flush);
@@ -471,7 +451,6 @@ again:
h->delayed_ref_elem.seq = 0;
h->type = type;
h->allocating_chunk = false;
- h->reloc_reserved = false;
INIT_LIST_HEAD(&h->qgroup_ref_list);
INIT_LIST_HEAD(&h->new_bgs);
@@ -487,7 +466,6 @@ again:
h->transid, num_bytes, 1);
h->block_rsv = &root->fs_info->trans_block_rsv;
h->bytes_reserved = num_bytes;
- h->reloc_reserved = reloc_reserved;
}
h->qgroup_reserved = qgroup_reserved;
@@ -632,7 +610,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
}
wait_for_commit(root, cur_trans);
- btrfs_put_transaction(cur_trans);
+ put_transaction(cur_trans);
out:
return ret;
}
@@ -757,7 +735,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
smp_mb();
if (waitqueue_active(&cur_trans->writer_wait))
wake_up(&cur_trans->writer_wait);
- btrfs_put_transaction(cur_trans);
+ put_transaction(cur_trans);
if (current->journal_info == trans)
current->journal_info = NULL;
@@ -766,10 +744,8 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
btrfs_run_delayed_iputs(root);
if (trans->aborted ||
- test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) {
- wake_up_process(info->transaction_kthread);
+ test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
err = -EIO;
- }
assert_qgroups_uptodate(trans);
kmem_cache_free(btrfs_trans_handle_cachep, trans);
@@ -972,19 +948,16 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
return ret;
ret = btrfs_run_dev_stats(trans, root->fs_info);
- if (ret)
- return ret;
+ WARN_ON(ret);
ret = btrfs_run_dev_replace(trans, root->fs_info);
- if (ret)
- return ret;
+ WARN_ON(ret);
+
ret = btrfs_run_qgroups(trans, root->fs_info);
- if (ret)
- return ret;
+ BUG_ON(ret);
/* run_qgroups might have added some more refs */
ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
- if (ret)
- return ret;
+ BUG_ON(ret);
while (!list_empty(&fs_info->dirty_cowonly_roots)) {
next = fs_info->dirty_cowonly_roots.next;
@@ -1480,7 +1453,7 @@ static void do_async_commit(struct work_struct *work)
* We've got freeze protection passed with the transaction.
* Tell lockdep about it.
*/
- if (ac->newtrans->type & __TRANS_FREEZABLE)
+ if (ac->newtrans->type < TRANS_JOIN_NOLOCK)
rwsem_acquire_read(
&ac->root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
0, 1, _THIS_IP_);
@@ -1521,7 +1494,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
* Tell lockdep we've released the freeze rwsem, since the
* async commit thread will be the one to unlock it.
*/
- if (ac->newtrans->type & __TRANS_FREEZABLE)
+ if (trans->type < TRANS_JOIN_NOLOCK)
rwsem_release(
&root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
1, _THIS_IP_);
@@ -1537,7 +1510,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
if (current->journal_info == trans)
current->journal_info = NULL;
- btrfs_put_transaction(cur_trans);
+ put_transaction(cur_trans);
return 0;
}
@@ -1579,10 +1552,8 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans,
root->fs_info->running_transaction = NULL;
spin_unlock(&root->fs_info->trans_lock);
- if (trans->type & __TRANS_FREEZABLE)
- sb_end_intwrite(root->fs_info->sb);
- btrfs_put_transaction(cur_trans);
- btrfs_put_transaction(cur_trans);
+ put_transaction(cur_trans);
+ put_transaction(cur_trans);
trace_btrfs_transaction_commit(root);
@@ -1600,19 +1571,15 @@ static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans,
int ret;
ret = btrfs_run_delayed_items(trans, root);
+ if (ret)
+ return ret;
+
/*
* running the delayed items may have added new refs. account
* them now so that they hinder processing of more delayed refs
* as little as possible.
*/
- if (ret) {
- btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
- return ret;
- }
-
- ret = btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
- if (ret)
- return ret;
+ btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
/*
* rename don't use btrfs_join_transaction, so, once we
@@ -1629,14 +1596,14 @@ static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans,
static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info)
{
if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT))
- return btrfs_start_delalloc_roots(fs_info, 1);
+ return btrfs_start_all_delalloc_inodes(fs_info, 1);
return 0;
}
static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info)
{
if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT))
- btrfs_wait_ordered_roots(fs_info, -1);
+ btrfs_wait_all_ordered_extents(fs_info);
}
int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
@@ -1702,7 +1669,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
wait_for_commit(root, cur_trans);
- btrfs_put_transaction(cur_trans);
+ put_transaction(cur_trans);
return ret;
}
@@ -1719,7 +1686,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
wait_for_commit(root, prev_trans);
- btrfs_put_transaction(prev_trans);
+ put_transaction(prev_trans);
} else {
spin_unlock(&root->fs_info->trans_lock);
}
@@ -1918,8 +1885,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
list_del_init(&cur_trans->list);
spin_unlock(&root->fs_info->trans_lock);
- btrfs_put_transaction(cur_trans);
- btrfs_put_transaction(cur_trans);
+ put_transaction(cur_trans);
+ put_transaction(cur_trans);
if (trans->type & __TRANS_FREEZABLE)
sb_end_intwrite(root->fs_info->sb);
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index 7657d11..5c2af84 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -92,7 +92,6 @@ struct btrfs_trans_handle {
short aborted;
short adding_csums;
bool allocating_chunk;
- bool reloc_reserved;
unsigned int type;
/*
* this root is only needed to validate that the root passed to
@@ -167,5 +166,4 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
struct extent_io_tree *dirty_pages, int mark);
int btrfs_transaction_blocked(struct btrfs_fs_info *info);
int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
-void btrfs_put_transaction(struct btrfs_transaction *transaction);
#endif
diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c
index 76928ca..94e05c1 100644
--- a/fs/btrfs/tree-defrag.c
+++ b/fs/btrfs/tree-defrag.c
@@ -37,6 +37,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
int ret = 0;
int wret;
int level;
+ int is_extent = 0;
int next_key_ret = 0;
u64 last_ret = 0;
u64 min_trans = 0;
@@ -49,7 +50,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
goto out;
}
- if (root->ref_cows == 0)
+ if (root->ref_cows == 0 && !is_extent)
goto out;
if (btrfs_test_opt(root, SSD))
@@ -84,7 +85,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
path->keep_locks = 1;
- ret = btrfs_search_forward(root, &key, path, min_trans);
+ ret = btrfs_search_forward(root, &key, NULL, path, min_trans);
if (ret < 0)
goto out;
if (ret > 0) {
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 9f7fc51..79f057c 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -26,6 +26,7 @@
#include "locking.h"
#include "print-tree.h"
#include "backref.h"
+#include "compat.h"
#include "tree-log.h"
#include "hash.h"
@@ -935,7 +936,7 @@ again:
parent_objectid,
victim_name,
victim_name_len)) {
- inc_nlink(inode);
+ btrfs_inc_nlink(inode);
btrfs_release_path(path);
ret = btrfs_unlink_inode(trans, root, dir,
@@ -1005,7 +1006,7 @@ again:
victim_parent = read_one_inode(root,
parent_objectid);
if (victim_parent) {
- inc_nlink(inode);
+ btrfs_inc_nlink(inode);
btrfs_release_path(path);
ret = btrfs_unlink_inode(trans, root,
@@ -1112,11 +1113,11 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
struct extent_buffer *eb, int slot,
struct btrfs_key *key)
{
- struct inode *dir = NULL;
- struct inode *inode = NULL;
+ struct inode *dir;
+ struct inode *inode;
unsigned long ref_ptr;
unsigned long ref_end;
- char *name = NULL;
+ char *name;
int namelen;
int ret;
int search_done = 0;
@@ -1149,15 +1150,13 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
* care of the rest
*/
dir = read_one_inode(root, parent_objectid);
- if (!dir) {
- ret = -ENOENT;
- goto out;
- }
+ if (!dir)
+ return -ENOENT;
inode = read_one_inode(root, inode_objectid);
if (!inode) {
- ret = -EIO;
- goto out;
+ iput(dir);
+ return -EIO;
}
while (ref_ptr < ref_end) {
@@ -1170,16 +1169,14 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
*/
if (!dir)
dir = read_one_inode(root, parent_objectid);
- if (!dir) {
- ret = -ENOENT;
- goto out;
- }
+ if (!dir)
+ return -ENOENT;
} else {
ret = ref_get_fields(eb, ref_ptr, &namelen, &name,
&ref_index);
}
if (ret)
- goto out;
+ return ret;
/* if we already have a perfect match, we're done */
if (!inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode),
@@ -1199,11 +1196,12 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
parent_objectid,
ref_index, name, namelen,
&search_done);
- if (ret) {
- if (ret == 1)
- ret = 0;
+ if (ret == 1) {
+ ret = 0;
goto out;
}
+ if (ret)
+ goto out;
}
/* insert our name */
@@ -1217,7 +1215,6 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + namelen;
kfree(name);
- name = NULL;
if (log_ref_ver) {
iput(dir);
dir = NULL;
@@ -1228,7 +1225,6 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
ret = overwrite_item(trans, root, path, eb, slot, key);
out:
btrfs_release_path(path);
- kfree(name);
iput(dir);
iput(inode);
return ret;
@@ -1311,7 +1307,6 @@ static int count_inode_refs(struct btrfs_root *root,
break;
path->slots[0]--;
}
-process_slot:
btrfs_item_key_to_cpu(path->nodes[0], &key,
path->slots[0]);
if (key.objectid != ino ||
@@ -1332,10 +1327,6 @@ process_slot:
if (key.offset == 0)
break;
- if (path->slots[0] > 0) {
- path->slots[0]--;
- goto process_slot;
- }
key.offset--;
btrfs_release_path(path);
}
@@ -1489,7 +1480,7 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans,
if (!inode->i_nlink)
set_nlink(inode, 1);
else
- inc_nlink(inode);
+ btrfs_inc_nlink(inode);
ret = btrfs_update_inode(trans, root, inode);
} else if (ret == -EEXIST) {
ret = 0;
@@ -1832,7 +1823,7 @@ again:
dir_key->offset,
name, name_len, 0);
}
- if (!log_di || (IS_ERR(log_di) && PTR_ERR(log_di) == -ENOENT)) {
+ if (IS_ERR_OR_NULL(log_di)) {
btrfs_dir_item_key_to_cpu(eb, di, &location);
btrfs_release_path(path);
btrfs_release_path(log_path);
@@ -1850,7 +1841,7 @@ again:
goto out;
}
- inc_nlink(inode);
+ btrfs_inc_nlink(inode);
ret = btrfs_unlink_inode(trans, root, dir, inode,
name, name_len);
if (!ret)
@@ -1869,9 +1860,6 @@ again:
goto again;
ret = 0;
goto out;
- } else if (IS_ERR(log_di)) {
- kfree(name);
- return PTR_ERR(log_di);
}
btrfs_release_path(log_path);
kfree(name);
@@ -2130,7 +2118,8 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
WARN_ON(*level >= BTRFS_MAX_LEVEL);
cur = path->nodes[*level];
- WARN_ON(btrfs_header_level(cur) != *level);
+ if (btrfs_header_level(cur) != *level)
+ WARN_ON(1);
if (path->slots[*level] >=
btrfs_header_nritems(cur))
@@ -2162,13 +2151,11 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
return ret;
}
- if (trans) {
- btrfs_tree_lock(next);
- btrfs_set_lock_blocking(next);
- clean_tree_block(trans, root, next);
- btrfs_wait_tree_block_writeback(next);
- btrfs_tree_unlock(next);
- }
+ btrfs_tree_lock(next);
+ btrfs_set_lock_blocking(next);
+ clean_tree_block(trans, root, next);
+ btrfs_wait_tree_block_writeback(next);
+ btrfs_tree_unlock(next);
WARN_ON(root_owner !=
BTRFS_TREE_LOG_OBJECTID);
@@ -2240,13 +2227,11 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
next = path->nodes[*level];
- if (trans) {
- btrfs_tree_lock(next);
- btrfs_set_lock_blocking(next);
- clean_tree_block(trans, root, next);
- btrfs_wait_tree_block_writeback(next);
- btrfs_tree_unlock(next);
- }
+ btrfs_tree_lock(next);
+ btrfs_set_lock_blocking(next);
+ clean_tree_block(trans, root, next);
+ btrfs_wait_tree_block_writeback(next);
+ btrfs_tree_unlock(next);
WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID);
ret = btrfs_free_and_pin_reserved_extent(root,
@@ -2316,13 +2301,11 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
next = path->nodes[orig_level];
- if (trans) {
- btrfs_tree_lock(next);
- btrfs_set_lock_blocking(next);
- clean_tree_block(trans, log, next);
- btrfs_wait_tree_block_writeback(next);
- btrfs_tree_unlock(next);
- }
+ btrfs_tree_lock(next);
+ btrfs_set_lock_blocking(next);
+ clean_tree_block(trans, log, next);
+ btrfs_wait_tree_block_writeback(next);
+ btrfs_tree_unlock(next);
WARN_ON(log->root_key.objectid !=
BTRFS_TREE_LOG_OBJECTID);
@@ -2588,7 +2571,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);
ret = write_ctree_super(trans, root->fs_info->tree_root, 1);
+ btrfs_scrub_continue_super(root);
if (ret) {
btrfs_abort_transaction(trans, root, ret);
goto out_wake_log_root;
@@ -2623,10 +2608,13 @@ static void free_log_tree(struct btrfs_trans_handle *trans,
.process_func = process_one_buffer
};
- ret = walk_log_tree(trans, log, &wc);
- /* I don't think this can happen but just in case */
- if (ret)
- btrfs_abort_transaction(trans, log, ret);
+ if (trans) {
+ ret = walk_log_tree(trans, log, &wc);
+
+ /* I don't think this can happen but just in case */
+ if (ret)
+ btrfs_abort_transaction(trans, log, ret);
+ }
while (1) {
ret = find_first_extent_bit(&log->dirty_log_pages,
@@ -2879,6 +2867,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
u64 min_offset, u64 *last_offset_ret)
{
struct btrfs_key min_key;
+ struct btrfs_key max_key;
struct btrfs_root *log = root->log_root;
struct extent_buffer *src;
int err = 0;
@@ -2890,6 +2879,9 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
u64 ino = btrfs_ino(inode);
log = root->log_root;
+ max_key.objectid = ino;
+ max_key.offset = (u64)-1;
+ max_key.type = key_type;
min_key.objectid = ino;
min_key.type = key_type;
@@ -2897,7 +2889,8 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
path->keep_locks = 1;
- ret = btrfs_search_forward(root, &min_key, path, trans->transid);
+ ret = btrfs_search_forward(root, &min_key, &max_key,
+ path, trans->transid);
/*
* we didn't find anything from this transaction, see if there
@@ -2950,8 +2943,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
/* find the first key from this transaction again */
ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0);
- if (WARN_ON(ret != 0))
+ if (ret != 0) {
+ WARN_ON(1);
goto done;
+ }
/*
* we have a block from this transaction, log every item in it
@@ -3177,10 +3172,11 @@ static int log_inode_item(struct btrfs_trans_handle *trans,
struct inode *inode)
{
struct btrfs_inode_item *inode_item;
+ struct btrfs_key key;
int ret;
- ret = btrfs_insert_empty_item(trans, log, path,
- &BTRFS_I(inode)->location,
+ memcpy(&key, &BTRFS_I(inode)->location, sizeof(key));
+ ret = btrfs_insert_empty_item(trans, log, path, &key,
sizeof(*inode_item));
if (ret && ret != -EEXIST)
return ret;
@@ -3379,7 +3375,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
btrfs_set_token_file_extent_type(leaf, fi,
BTRFS_FILE_EXTENT_REG,
&token);
- if (em->block_start == EXTENT_MAP_HOLE)
+ if (em->block_start == 0)
skip_csum = true;
}
@@ -3421,6 +3417,11 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
if (skip_csum)
return 0;
+ if (em->compress_type) {
+ csum_offset = 0;
+ csum_len = block_len;
+ }
+
/*
* First check and see if our csums are on our outstanding ordered
* extents.
@@ -3504,13 +3505,8 @@ unlocked:
if (!mod_len || ret)
return ret;
- if (em->compress_type) {
- csum_offset = 0;
- csum_len = block_len;
- } else {
- csum_offset = mod_start - em->start;
- csum_len = mod_len;
- }
+ csum_offset = mod_start - em->start;
+ csum_len = mod_len;
/* block start is already adjusted for the file extent offset. */
ret = btrfs_lookup_csums_range(log->fs_info->csum_root,
@@ -3697,8 +3693,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
ret = btrfs_truncate_inode_items(trans, log,
inode, 0, 0);
} else if (test_and_clear_bit(BTRFS_INODE_COPY_EVERYTHING,
- &BTRFS_I(inode)->runtime_flags) ||
- inode_only == LOG_INODE_EXISTS) {
+ &BTRFS_I(inode)->runtime_flags)) {
if (inode_only == LOG_INODE_ALL)
fast_search = true;
max_key.type = BTRFS_XATTR_ITEM_KEY;
@@ -3724,7 +3719,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
while (1) {
ins_nr = 0;
- ret = btrfs_search_forward(root, &min_key,
+ ret = btrfs_search_forward(root, &min_key, &max_key,
path, trans->transid);
if (ret != 0)
break;
@@ -3774,14 +3769,14 @@ next_slot:
}
btrfs_release_path(path);
- if (min_key.offset < (u64)-1) {
+ if (min_key.offset < (u64)-1)
min_key.offset++;
- } else if (min_key.type < max_key.type) {
+ else if (min_key.type < (u8)-1)
min_key.type++;
- min_key.offset = 0;
- } else {
+ else if (min_key.objectid < (u64)-1)
+ min_key.objectid++;
+ else
break;
- }
}
if (ins_nr) {
ret = copy_items(trans, inode, dst_path, src, ins_start_slot,
@@ -3802,7 +3797,7 @@ log_extents:
err = ret;
goto out_unlock;
}
- } else if (inode_only == LOG_INODE_ALL) {
+ } else {
struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree;
struct extent_map *em, *n;
diff --git a/fs/btrfs/uuid-tree.c b/fs/btrfs/uuid-tree.c
index fbda900..dd0dea3 100644
--- a/fs/btrfs/uuid-tree.c
+++ b/fs/btrfs/uuid-tree.c
@@ -260,6 +260,7 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info,
{
struct btrfs_root *root = fs_info->uuid_root;
struct btrfs_key key;
+ struct btrfs_key max_key;
struct btrfs_path *path;
int ret = 0;
struct extent_buffer *leaf;
@@ -276,10 +277,13 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info,
key.objectid = 0;
key.type = 0;
key.offset = 0;
+ max_key.objectid = (u64)-1;
+ max_key.type = (u8)-1;
+ max_key.offset = (u64)-1;
again_search_slot:
path->keep_locks = 1;
- ret = btrfs_search_forward(root, &key, path, 0);
+ ret = btrfs_search_forward(root, &key, &max_key, path, 0);
if (ret) {
if (ret > 0)
ret = 0;
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 92303f4..043b215 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -28,6 +28,7 @@
#include <linux/raid/pq.h>
#include <linux/semaphore.h>
#include <asm/div64.h>
+#include "compat.h"
#include "ctree.h"
#include "extent_map.h"
#include "disk-io.h"
@@ -665,8 +666,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
if (device->bdev)
fs_devices->open_devices--;
- if (device->writeable &&
- device->devid != BTRFS_DEV_REPLACE_DEVID) {
+ if (device->writeable && !device->is_tgtdev_for_dev_replace) {
list_del_init(&device->dev_alloc_list);
fs_devices->rw_devices--;
}
@@ -2041,7 +2041,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
device->in_fs_metadata = 1;
device->is_tgtdev_for_dev_replace = 0;
device->mode = FMODE_EXCL;
- device->dev_stats_valid = 1;
set_blocksize(device->bdev, 4096);
if (seeding_dev) {
@@ -2209,7 +2208,6 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
device->in_fs_metadata = 1;
device->is_tgtdev_for_dev_replace = 1;
device->mode = FMODE_EXCL;
- device->dev_stats_valid = 1;
set_blocksize(device->bdev, 4096);
device->fs_devices = fs_info->fs_devices;
list_add(&device->dev_list, &fs_info->fs_devices->devices);
@@ -2552,7 +2550,8 @@ again:
failed = 0;
retried = true;
goto again;
- } else if (WARN_ON(failed && retried)) {
+ } else if (failed && retried) {
+ WARN_ON(1);
ret = -ENOSPC;
}
error:
@@ -3424,9 +3423,6 @@ int btrfs_pause_balance(struct btrfs_fs_info *fs_info)
int btrfs_cancel_balance(struct btrfs_fs_info *fs_info)
{
- if (fs_info->sb->s_flags & MS_RDONLY)
- return -EROFS;
-
mutex_lock(&fs_info->balance_mutex);
if (!fs_info->balance_ctl) {
mutex_unlock(&fs_info->balance_mutex);
@@ -3492,7 +3488,7 @@ static int btrfs_uuid_scan_kthread(void *data)
path->keep_locks = 1;
while (1) {
- ret = btrfs_search_forward(root, &key, path, 0);
+ ret = btrfs_search_forward(root, &key, &max_key, path, 0);
if (ret) {
if (ret > 0)
ret = 0;
@@ -4492,7 +4488,6 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
btrfs_crit(fs_info, "Invalid mapping for %Lu-%Lu, got "
"%Lu-%Lu\n", logical, logical+len, em->start,
em->start + em->len);
- free_extent_map(em);
return 1;
}
@@ -4673,7 +4668,6 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
btrfs_crit(fs_info, "found a bad mapping, wanted %Lu, "
"found %Lu-%Lu\n", logical, em->start,
em->start + em->len);
- free_extent_map(em);
return -EINVAL;
}
@@ -4901,7 +4895,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
num_stripes = map->num_stripes;
max_errors = nr_parity_stripes(map);
- raid_map = kmalloc_array(num_stripes, sizeof(u64),
+ raid_map = kmalloc(sizeof(u64) * num_stripes,
GFP_NOFS);
if (!raid_map) {
ret = -ENOMEM;
@@ -5394,15 +5388,17 @@ static int bio_size_ok(struct block_device *bdev, struct bio *bio,
{
struct bio_vec *prev;
struct request_queue *q = bdev_get_queue(bdev);
- unsigned int max_sectors = queue_max_sectors(q);
+ unsigned short max_sectors = queue_max_sectors(q);
struct bvec_merge_data bvm = {
.bi_bdev = bdev,
.bi_sector = sector,
.bi_rw = bio->bi_rw,
};
- if (WARN_ON(bio->bi_vcnt == 0))
+ if (bio->bi_vcnt == 0) {
+ WARN_ON(1);
return 1;
+ }
prev = &bio->bi_io_vec[bio->bi_vcnt - 1];
if (bio_sectors(bio) > max_sectors)
@@ -5635,8 +5631,10 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
struct btrfs_device *dev;
u64 tmp;
- if (WARN_ON(!devid && !fs_info))
+ if (!devid && !fs_info) {
+ WARN_ON(1);
return ERR_PTR(-EINVAL);
+ }
dev = __alloc_device();
if (IS_ERR(dev))
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 8b3cd14..b72f540 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -43,8 +43,9 @@ struct btrfs_device {
/* WRITE_SYNC bios */
struct btrfs_pending_bios pending_sync_bios;
- u64 generation;
int running_pending;
+ u64 generation;
+
int writeable;
int in_fs_metadata;
int missing;
@@ -52,11 +53,11 @@ struct btrfs_device {
int is_tgtdev_for_dev_replace;
spinlock_t io_lock;
- /* the mode sent to blkdev_get */
- fmode_t mode;
struct block_device *bdev;
+ /* the mode sent to blkdev_get */
+ fmode_t mode;
struct rcu_string *name;
@@ -77,21 +78,16 @@ struct btrfs_device {
/* optimal io width for this device */
u32 io_width;
- /* type and info about this device */
- u64 type;
/* minimal io size for this device */
u32 sector_size;
+ /* type and info about this device */
+ u64 type;
/* physical drive uuid (or lvm uuid) */
u8 uuid[BTRFS_UUID_SIZE];
- /* for sending down flush barriers */
- int nobarriers;
- struct bio *flush_bio;
- struct completion flush_wait;
-
/* per-device scrub information */
struct scrub_ctx *scrub_device;
@@ -107,6 +103,10 @@ struct btrfs_device {
struct radix_tree_root reada_zones;
struct radix_tree_root reada_extents;
+ /* for sending down flush barriers */
+ struct bio *flush_bio;
+ struct completion flush_wait;
+ int nobarriers;
/* disk I/O failure stats. For detailed description refer to
* enum btrfs_dev_stat_values in ioctl.h */
@@ -132,9 +132,7 @@ struct btrfs_fs_devices {
/* all of the devices in the FS, protected by a mutex
* so we can safely walk it to write out the supers without
- * worrying about add/remove by the multi-device code.
- * Scrubbing super can kick off supers writing by holding
- * this mutex lock.
+ * worrying about add/remove by the multi-device code
*/
struct mutex device_list_mutex;
struct list_head devices;