git://ftp.safe.ca
/
safe
/
jmp
/
linux-2.6
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
[safe/jmp/linux-2.6]
/
fs
/
btrfs
/
volumes.c
diff --git
a/fs/btrfs/volumes.c
b/fs/btrfs/volumes.c
index
5dbefd1
..
d6e3af8
100644
(file)
--- a/
fs/btrfs/volumes.c
+++ b/
fs/btrfs/volumes.c
@@
-17,6
+17,7
@@
*/
#include <linux/sched.h>
#include <linux/bio.h>
*/
#include <linux/sched.h>
#include <linux/bio.h>
+#include <linux/slab.h>
#include <linux/buffer_head.h>
#include <linux/blkdev.h>
#include <linux/random.h>
#include <linux/buffer_head.h>
#include <linux/blkdev.h>
#include <linux/random.h>
@@
-256,13
+257,13
@@
loop_lock:
wake_up(&fs_info->async_submit_wait);
BUG_ON(atomic_read(&cur->bi_cnt) == 0);
wake_up(&fs_info->async_submit_wait);
BUG_ON(atomic_read(&cur->bi_cnt) == 0);
- submit_bio(cur->bi_rw, cur);
- num_run++;
- batch_run++;
- if (bio_
sync(cur
))
+ if (bio_
rw_flagged(cur, BIO_RW_SYNCIO
))
num_sync_run++;
num_sync_run++;
+ submit_bio(cur->bi_rw, cur);
+ num_run++;
+ batch_run++;
if (need_resched()) {
if (num_sync_run) {
blk_run_backing_dev(bdi, NULL);
if (need_resched()) {
if (num_sync_run) {
blk_run_backing_dev(bdi, NULL);
@@
-276,7
+277,7
@@
loop_lock:
* is now congested. Back off and let other work structs
* run instead
*/
* is now congested. Back off and let other work structs
* run instead
*/
- if (pending && bdi_write_congested(bdi) && batch_run >
32
&&
+ if (pending && bdi_write_congested(bdi) && batch_run >
8
&&
fs_info->fs_devices->open_devices > 1) {
struct io_context *ioc;
fs_info->fs_devices->open_devices > 1) {
struct io_context *ioc;
@@
-325,16
+326,6
@@
loop_lock:
num_sync_run = 0;
blk_run_backing_dev(bdi, NULL);
}
num_sync_run = 0;
blk_run_backing_dev(bdi, NULL);
}
-
- cond_resched();
- if (again)
- goto loop;
-
- spin_lock(&device->io_lock);
- if (device->pending_bios.head || device->pending_sync_bios.head)
- goto loop_lock;
- spin_unlock(&device->io_lock);
-
/*
* IO has already been through a long path to get here. Checksumming,
* async helper threads, perhaps compression. We've done a pretty
/*
* IO has already been through a long path to get here. Checksumming,
* async helper threads, perhaps compression. We've done a pretty
@@
-346,6
+337,16
@@
loop_lock:
* cared about found its way down here.
*/
blk_run_backing_dev(bdi, NULL);
* cared about found its way down here.
*/
blk_run_backing_dev(bdi, NULL);
+
+ cond_resched();
+ if (again)
+ goto loop;
+
+ spin_lock(&device->io_lock);
+ if (device->pending_bios.head || device->pending_sync_bios.head)
+ goto loop_lock;
+ spin_unlock(&device->io_lock);
+
done:
return 0;
}
done:
return 0;
}
@@
-365,6
+366,7
@@
static noinline int device_list_add(const char *path,
struct btrfs_device *device;
struct btrfs_fs_devices *fs_devices;
u64 found_transid = btrfs_super_generation(disk_super);
struct btrfs_device *device;
struct btrfs_fs_devices *fs_devices;
u64 found_transid = btrfs_super_generation(disk_super);
+ char *name;
fs_devices = find_fsid(disk_super->fsid);
if (!fs_devices) {
fs_devices = find_fsid(disk_super->fsid);
if (!fs_devices) {
@@
-411,6
+413,12
@@
static noinline int device_list_add(const char *path,
device->fs_devices = fs_devices;
fs_devices->num_devices++;
device->fs_devices = fs_devices;
fs_devices->num_devices++;
+ } else if (strcmp(device->name, path)) {
+ name = kstrdup(path, GFP_NOFS);
+ if (!name)
+ return -ENOMEM;
+ kfree(device->name);
+ device->name = name;
}
if (found_transid > fs_devices->latest_trans) {
}
if (found_transid > fs_devices->latest_trans) {
@@
-446,8
+454,10
@@
static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
goto error;
device->name = kstrdup(orig_dev->name, GFP_NOFS);
goto error;
device->name = kstrdup(orig_dev->name, GFP_NOFS);
- if (!device->name)
+ if (!device->name) {
+ kfree(device);
goto error;
goto error;
+ }
device->devid = orig_dev->devid;
device->work.func = pending_bios_fn;
device->devid = orig_dev->devid;
device->work.func = pending_bios_fn;
@@
-590,7
+600,7
@@
static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
goto error_close;
disk_super = (struct btrfs_super_block *)bh->b_data;
goto error_close;
disk_super = (struct btrfs_super_block *)bh->b_data;
- devid =
le64_to_cpu(disk_super->dev_item.devid
);
+ devid =
btrfs_stack_device_id(&disk_super->dev_item
);
if (devid != device->devid)
goto error_brelse;
if (devid != device->devid)
goto error_brelse;
@@
-692,7
+702,7
@@
int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
goto error_close;
}
disk_super = (struct btrfs_super_block *)bh->b_data;
goto error_close;
}
disk_super = (struct btrfs_super_block *)bh->b_data;
- devid =
le64_to_cpu(disk_super->dev_item.devid
);
+ devid =
btrfs_stack_device_id(&disk_super->dev_item
);
transid = btrfs_super_generation(disk_super);
if (disk_super->label[0])
printk(KERN_INFO "device label %s ", disk_super->label);
transid = btrfs_super_generation(disk_super);
if (disk_super->label[0])
printk(KERN_INFO "device label %s ", disk_super->label);
@@
-719,10
+729,9
@@
error:
* called very infrequently and that a given device has a small number
* of extents
*/
* called very infrequently and that a given device has a small number
* of extents
*/
-static noinline int find_free_dev_extent(struct btrfs_trans_handle *trans,
- struct btrfs_device *device,
- u64 num_bytes, u64 *start,
- u64 *max_avail)
+int find_free_dev_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_device *device, u64 num_bytes,
+ u64 *start, u64 *max_avail)
{
struct btrfs_key key;
struct btrfs_root *root = device->dev_root;
{
struct btrfs_key key;
struct btrfs_root *root = device->dev_root;
@@
-1088,7
+1097,7
@@
static int btrfs_rm_dev_item(struct btrfs_root *root,
if (!path)
return -ENOMEM;
if (!path)
return -ENOMEM;
- trans = btrfs_start_transaction(root,
1
);
+ trans = btrfs_start_transaction(root,
0
);
key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
key.type = BTRFS_DEV_ITEM_KEY;
key.offset = device->devid;
key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
key.type = BTRFS_DEV_ITEM_KEY;
key.offset = device->devid;
@@
-1134,7
+1143,7
@@
int btrfs_rm_device(struct btrfs_root *root, char *device_path)
root->fs_info->avail_metadata_alloc_bits;
if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) &&
root->fs_info->avail_metadata_alloc_bits;
if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) &&
- root->fs_info->fs_devices->
rw
_devices <= 4) {
+ root->fs_info->fs_devices->
num
_devices <= 4) {
printk(KERN_ERR "btrfs: unable to go below four devices "
"on raid10\n");
ret = -EINVAL;
printk(KERN_ERR "btrfs: unable to go below four devices "
"on raid10\n");
ret = -EINVAL;
@@
-1142,7
+1151,7
@@
int btrfs_rm_device(struct btrfs_root *root, char *device_path)
}
if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) &&
}
if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) &&
- root->fs_info->fs_devices->
rw
_devices <= 2) {
+ root->fs_info->fs_devices->
num
_devices <= 2) {
printk(KERN_ERR "btrfs: unable to go below two "
"devices on raid1\n");
ret = -EINVAL;
printk(KERN_ERR "btrfs: unable to go below two "
"devices on raid1\n");
ret = -EINVAL;
@@
-1186,7
+1195,7
@@
int btrfs_rm_device(struct btrfs_root *root, char *device_path)
goto error_close;
}
disk_super = (struct btrfs_super_block *)bh->b_data;
goto error_close;
}
disk_super = (struct btrfs_super_block *)bh->b_data;
- devid =
le64_to_cpu(disk_super->dev_item.devid
);
+ devid =
btrfs_stack_device_id(&disk_super->dev_item
);
dev_uuid = disk_super->dev_item.uuid;
device = btrfs_find_device(root, devid, dev_uuid,
disk_super->fsid);
dev_uuid = disk_super->dev_item.uuid;
device = btrfs_find_device(root, devid, dev_uuid,
disk_super->fsid);
@@
-1433,8
+1442,8
@@
int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
return -EINVAL;
bdev = open_bdev_exclusive(device_path, 0, root->fs_info->bdev_holder);
return -EINVAL;
bdev = open_bdev_exclusive(device_path, 0, root->fs_info->bdev_holder);
- if (
!bdev
)
- return
-EIO
;
+ if (
IS_ERR(bdev)
)
+ return
PTR_ERR(bdev)
;
if (root->fs_info->fs_devices->seeding) {
seeding_dev = 1;
if (root->fs_info->fs_devices->seeding) {
seeding_dev = 1;
@@
-1477,7
+1486,7
@@
int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
goto error;
}
goto error;
}
- trans = btrfs_start_transaction(root,
1
);
+ trans = btrfs_start_transaction(root,
0
);
lock_chunks(root);
device->barriers = 1;
lock_chunks(root);
device->barriers = 1;
@@
-1736,11
+1745,16
@@
static int btrfs_relocate_chunk(struct btrfs_root *root,
extent_root = root->fs_info->extent_root;
em_tree = &root->fs_info->mapping_tree.map_tree;
extent_root = root->fs_info->extent_root;
em_tree = &root->fs_info->mapping_tree.map_tree;
+ ret = btrfs_can_relocate(extent_root, chunk_offset);
+ if (ret)
+ return -ENOSPC;
+
/* step one, relocate all the extents inside this chunk */
ret = btrfs_relocate_block_group(extent_root, chunk_offset);
/* step one, relocate all the extents inside this chunk */
ret = btrfs_relocate_block_group(extent_root, chunk_offset);
- BUG_ON(ret);
+ if (ret)
+ return ret;
- trans = btrfs_start_transaction(root,
1
);
+ trans = btrfs_start_transaction(root,
0
);
BUG_ON(!trans);
lock_chunks(root);
BUG_ON(!trans);
lock_chunks(root);
@@
-1749,9
+1763,9
@@
static int btrfs_relocate_chunk(struct btrfs_root *root,
* step two, delete the device extents and the
* chunk tree entries
*/
* step two, delete the device extents and the
* chunk tree entries
*/
-
spin
_lock(&em_tree->lock);
+
read
_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, chunk_offset, 1);
em = lookup_extent_mapping(em_tree, chunk_offset, 1);
-
spin
_unlock(&em_tree->lock);
+
read
_unlock(&em_tree->lock);
BUG_ON(em->start > chunk_offset ||
em->start + em->len < chunk_offset);
BUG_ON(em->start > chunk_offset ||
em->start + em->len < chunk_offset);
@@
-1780,9
+1794,9
@@
static int btrfs_relocate_chunk(struct btrfs_root *root,
ret = btrfs_remove_block_group(trans, extent_root, chunk_offset);
BUG_ON(ret);
ret = btrfs_remove_block_group(trans, extent_root, chunk_offset);
BUG_ON(ret);
-
spin
_lock(&em_tree->lock);
+
write
_lock(&em_tree->lock);
remove_extent_mapping(em_tree, em);
remove_extent_mapping(em_tree, em);
-
spin
_unlock(&em_tree->lock);
+
write
_unlock(&em_tree->lock);
kfree(map);
em->bdev = NULL;
kfree(map);
em->bdev = NULL;
@@
-1807,12
+1821,15
@@
static int btrfs_relocate_sys_chunks(struct btrfs_root *root)
struct btrfs_key found_key;
u64 chunk_tree = chunk_root->root_key.objectid;
u64 chunk_type;
struct btrfs_key found_key;
u64 chunk_tree = chunk_root->root_key.objectid;
u64 chunk_type;
+ bool retried = false;
+ int failed = 0;
int ret;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
int ret;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
+again:
key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
key.offset = (u64)-1;
key.type = BTRFS_CHUNK_ITEM_KEY;
key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
key.offset = (u64)-1;
key.type = BTRFS_CHUNK_ITEM_KEY;
@@
-1842,7
+1859,10
@@
static int btrfs_relocate_sys_chunks(struct btrfs_root *root)
ret = btrfs_relocate_chunk(chunk_root, chunk_tree,
found_key.objectid,
found_key.offset);
ret = btrfs_relocate_chunk(chunk_root, chunk_tree,
found_key.objectid,
found_key.offset);
- BUG_ON(ret);
+ if (ret == -ENOSPC)
+ failed++;
+ else if (ret)
+ BUG();
}
if (found_key.offset == 0)
}
if (found_key.offset == 0)
@@
-1850,6
+1870,14
@@
static int btrfs_relocate_sys_chunks(struct btrfs_root *root)
key.offset = found_key.offset - 1;
}
ret = 0;
key.offset = found_key.offset - 1;
}
ret = 0;
+ if (failed && !retried) {
+ failed = 0;
+ retried = true;
+ goto again;
+ } else if (failed && retried) {
+ WARN_ON(1);
+ ret = -ENOSPC;
+ }
error:
btrfs_free_path(path);
return ret;
error:
btrfs_free_path(path);
return ret;
@@
-1894,9
+1922,11
@@
int btrfs_balance(struct btrfs_root *dev_root)
continue;
ret = btrfs_shrink_device(device, old_size - size_to_free);
continue;
ret = btrfs_shrink_device(device, old_size - size_to_free);
+ if (ret == -ENOSPC)
+ break;
BUG_ON(ret);
BUG_ON(ret);
- trans = btrfs_start_transaction(dev_root,
1
);
+ trans = btrfs_start_transaction(dev_root,
0
);
BUG_ON(!trans);
ret = btrfs_grow_device(trans, device, old_size);
BUG_ON(!trans);
ret = btrfs_grow_device(trans, device, old_size);
@@
-1938,9
+1968,8
@@
int btrfs_balance(struct btrfs_root *dev_root)
chunk = btrfs_item_ptr(path->nodes[0],
path->slots[0],
struct btrfs_chunk);
chunk = btrfs_item_ptr(path->nodes[0],
path->slots[0],
struct btrfs_chunk);
- key.offset = found_key.offset;
/* chunk zero is special */
/* chunk zero is special */
- if (key.offset == 0)
+ if (
found_
key.offset == 0)
break;
btrfs_release_path(chunk_root, path);
break;
btrfs_release_path(chunk_root, path);
@@
-1948,7
+1977,8
@@
int btrfs_balance(struct btrfs_root *dev_root)
chunk_root->root_key.objectid,
found_key.objectid,
found_key.offset);
chunk_root->root_key.objectid,
found_key.objectid,
found_key.offset);
- BUG_ON(ret);
+ BUG_ON(ret && ret != -ENOSPC);
+ key.offset = found_key.offset - 1;
}
ret = 0;
error:
}
ret = 0;
error:
@@
-1974,10
+2004,13
@@
int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
u64 chunk_offset;
int ret;
int slot;
u64 chunk_offset;
int ret;
int slot;
+ int failed = 0;
+ bool retried = false;
struct extent_buffer *l;
struct btrfs_key key;
struct btrfs_super_block *super_copy = &root->fs_info->super_copy;
u64 old_total = btrfs_super_total_bytes(super_copy);
struct extent_buffer *l;
struct btrfs_key key;
struct btrfs_super_block *super_copy = &root->fs_info->super_copy;
u64 old_total = btrfs_super_total_bytes(super_copy);
+ u64 old_size = device->total_bytes;
u64 diff = device->total_bytes - new_size;
if (new_size >= device->total_bytes)
u64 diff = device->total_bytes - new_size;
if (new_size >= device->total_bytes)
@@
-1987,12
+2020,6
@@
int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
if (!path)
return -ENOMEM;
if (!path)
return -ENOMEM;
- trans = btrfs_start_transaction(root, 1);
- if (!trans) {
- ret = -ENOMEM;
- goto done;
- }
-
path->reada = 2;
lock_chunks(root);
path->reada = 2;
lock_chunks(root);
@@
-2001,8
+2028,8
@@
int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
if (device->writeable)
device->fs_devices->total_rw_bytes -= diff;
unlock_chunks(root);
if (device->writeable)
device->fs_devices->total_rw_bytes -= diff;
unlock_chunks(root);
- btrfs_end_transaction(trans, root);
+again:
key.objectid = device->devid;
key.offset = (u64)-1;
key.type = BTRFS_DEV_EXTENT_KEY;
key.objectid = device->devid;
key.offset = (u64)-1;
key.type = BTRFS_DEV_EXTENT_KEY;
@@
-2017,6
+2044,7
@@
int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
goto done;
if (ret) {
ret = 0;
goto done;
if (ret) {
ret = 0;
+ btrfs_release_path(root, path);
break;
}
break;
}
@@
-2024,14
+2052,18
@@
int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
slot = path->slots[0];
btrfs_item_key_to_cpu(l, &key, path->slots[0]);
slot = path->slots[0];
btrfs_item_key_to_cpu(l, &key, path->slots[0]);
- if (key.objectid != device->devid)
+ if (key.objectid != device->devid) {
+ btrfs_release_path(root, path);
break;
break;
+ }
dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
length = btrfs_dev_extent_length(l, dev_extent);
dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
length = btrfs_dev_extent_length(l, dev_extent);
- if (key.offset + length <= new_size)
+ if (key.offset + length <= new_size) {
+ btrfs_release_path(root, path);
break;
break;
+ }
chunk_tree = btrfs_dev_extent_chunk_tree(l, dev_extent);
chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent);
chunk_tree = btrfs_dev_extent_chunk_tree(l, dev_extent);
chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent);
@@
-2040,16
+2072,30
@@
int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
ret = btrfs_relocate_chunk(root, chunk_tree, chunk_objectid,
chunk_offset);
ret = btrfs_relocate_chunk(root, chunk_tree, chunk_objectid,
chunk_offset);
- if (ret)
+ if (ret
&& ret != -ENOSPC
)
goto done;
goto done;
+ if (ret == -ENOSPC)
+ failed++;
+ key.offset -= 1;
}
}
- /* Shrinking succeeded, else we would be at "done". */
- trans = btrfs_start_transaction(root, 1);
- if (!trans) {
- ret = -ENOMEM;
+ if (failed && !retried) {
+ failed = 0;
+ retried = true;
+ goto again;
+ } else if (failed && retried) {
+ ret = -ENOSPC;
+ lock_chunks(root);
+
+ device->total_bytes = old_size;
+ if (device->writeable)
+ device->fs_devices->total_rw_bytes += diff;
+ unlock_chunks(root);
goto done;
}
goto done;
}
+
+ /* Shrinking succeeded, else we would be at "done". */
+ trans = btrfs_start_transaction(root, 0);
lock_chunks(root);
device->disk_total_bytes = new_size;
lock_chunks(root);
device->disk_total_bytes = new_size;
@@
-2150,9
+2196,9
@@
static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
min_stripes = 2;
}
if (type & (BTRFS_BLOCK_GROUP_RAID1)) {
min_stripes = 2;
}
if (type & (BTRFS_BLOCK_GROUP_RAID1)) {
- num_stripes = min_t(u64, 2, fs_devices->rw_devices);
- if (num_stripes < 2)
+ if (fs_devices->rw_devices < 2)
return -ENOSPC;
return -ENOSPC;
+ num_stripes = 2;
min_stripes = 2;
}
if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
min_stripes = 2;
}
if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
@@
-2168,7
+2214,7
@@
static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
max_chunk_size = 10 * calc_size;
min_stripe_size = 64 * 1024 * 1024;
} else if (type & BTRFS_BLOCK_GROUP_METADATA) {
max_chunk_size = 10 * calc_size;
min_stripe_size = 64 * 1024 * 1024;
} else if (type & BTRFS_BLOCK_GROUP_METADATA) {
- max_chunk_size =
4 * calc_size
;
+ max_chunk_size =
256 * 1024 * 1024
;
min_stripe_size = 32 * 1024 * 1024;
} else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
calc_size = 8 * 1024 * 1024;
min_stripe_size = 32 * 1024 * 1024;
} else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
calc_size = 8 * 1024 * 1024;
@@
-2196,8
+2242,16
@@
again:
do_div(calc_size, stripe_len);
calc_size *= stripe_len;
}
do_div(calc_size, stripe_len);
calc_size *= stripe_len;
}
+
/* we don't want tiny stripes */
/* we don't want tiny stripes */
- calc_size = max_t(u64, min_stripe_size, calc_size);
+ if (!looped)
+ calc_size = max_t(u64, min_stripe_size, calc_size);
+
+ /*
+ * we're about to do_div by the stripe_len so lets make sure
+ * we end up with something bigger than a stripe
+ */
+ calc_size = max_t(u64, calc_size, stripe_len * 4);
do_div(calc_size, stripe_len);
calc_size *= stripe_len;
do_div(calc_size, stripe_len);
calc_size *= stripe_len;
@@
-2294,9
+2348,9
@@
again:
em->block_len = em->len;
em_tree = &extent_root->fs_info->mapping_tree.map_tree;
em->block_len = em->len;
em_tree = &extent_root->fs_info->mapping_tree.map_tree;
-
spin
_lock(&em_tree->lock);
+
write
_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em);
ret = add_extent_mapping(em_tree, em);
-
spin
_unlock(&em_tree->lock);
+
write
_unlock(&em_tree->lock);
BUG_ON(ret);
free_extent_map(em);
BUG_ON(ret);
free_extent_map(em);
@@
-2491,12
+2545,17
@@
int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset)
int readonly = 0;
int i;
int readonly = 0;
int i;
-
spin
_lock(&map_tree->map_tree.lock);
+
read
_lock(&map_tree->map_tree.lock);
em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1);
em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1);
-
spin
_unlock(&map_tree->map_tree.lock);
+
read
_unlock(&map_tree->map_tree.lock);
if (!em)
return 1;
if (!em)
return 1;
+ if (btrfs_test_opt(root, DEGRADED)) {
+ free_extent_map(em);
+ return 0;
+ }
+
map = (struct map_lookup *)em->bdev;
for (i = 0; i < map->num_stripes; i++) {
if (!map->stripes[i].dev->writeable) {
map = (struct map_lookup *)em->bdev;
for (i = 0; i < map->num_stripes; i++) {
if (!map->stripes[i].dev->writeable) {
@@
-2518,11
+2577,11
@@
void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree)
struct extent_map *em;
while (1) {
struct extent_map *em;
while (1) {
-
spin
_lock(&tree->map_tree.lock);
+
write
_lock(&tree->map_tree.lock);
em = lookup_extent_mapping(&tree->map_tree, 0, (u64)-1);
if (em)
remove_extent_mapping(&tree->map_tree, em);
em = lookup_extent_mapping(&tree->map_tree, 0, (u64)-1);
if (em)
remove_extent_mapping(&tree->map_tree, em);
-
spin
_unlock(&tree->map_tree.lock);
+
write
_unlock(&tree->map_tree.lock);
if (!em)
break;
kfree(em->bdev);
if (!em)
break;
kfree(em->bdev);
@@
-2540,9
+2599,9
@@
int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len)
struct extent_map_tree *em_tree = &map_tree->map_tree;
int ret;
struct extent_map_tree *em_tree = &map_tree->map_tree;
int ret;
-
spin
_lock(&em_tree->lock);
+
read
_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, logical, len);
em = lookup_extent_mapping(em_tree, logical, len);
-
spin
_unlock(&em_tree->lock);
+
read
_unlock(&em_tree->lock);
BUG_ON(!em);
BUG_ON(em->start > logical || em->start + em->len < logical);
BUG_ON(!em);
BUG_ON(em->start > logical || em->start + em->len < logical);
@@
-2604,12
+2663,14
@@
again:
atomic_set(&multi->error, 0);
}
atomic_set(&multi->error, 0);
}
-
spin
_lock(&em_tree->lock);
+
read
_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, logical, *length);
em = lookup_extent_mapping(em_tree, logical, *length);
-
spin
_unlock(&em_tree->lock);
+
read
_unlock(&em_tree->lock);
- if (!em && unplug_page)
+ if (!em && unplug_page) {
+ kfree(multi);
return 0;
return 0;
+ }
if (!em) {
printk(KERN_CRIT "unable to find logical %llu len %llu\n",
if (!em) {
printk(KERN_CRIT "unable to find logical %llu len %llu\n",
@@
-2763,9
+2824,9
@@
int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
u64 stripe_nr;
int i, j, nr = 0;
u64 stripe_nr;
int i, j, nr = 0;
-
spin
_lock(&em_tree->lock);
+
read
_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, chunk_start, 1);
em = lookup_extent_mapping(em_tree, chunk_start, 1);
-
spin
_unlock(&em_tree->lock);
+
read
_unlock(&em_tree->lock);
BUG_ON(!em || em->start != chunk_start);
map = (struct map_lookup *)em->bdev;
BUG_ON(!em || em->start != chunk_start);
map = (struct map_lookup *)em->bdev;
@@
-2903,7
+2964,7
@@
static noinline int schedule_bio(struct btrfs_root *root,
bio->bi_rw |= rw;
spin_lock(&device->io_lock);
bio->bi_rw |= rw;
spin_lock(&device->io_lock);
- if (bio_
sync(bio
))
+ if (bio_
rw_flagged(bio, BIO_RW_SYNCIO
))
pending_bios = &device->pending_sync_bios;
else
pending_bios = &device->pending_bios;
pending_bios = &device->pending_sync_bios;
else
pending_bios = &device->pending_bios;
@@
-3053,9
+3114,9
@@
static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
logical = key->offset;
length = btrfs_chunk_length(leaf, chunk);
logical = key->offset;
length = btrfs_chunk_length(leaf, chunk);
-
spin
_lock(&map_tree->map_tree.lock);
+
read
_lock(&map_tree->map_tree.lock);
em = lookup_extent_mapping(&map_tree->map_tree, logical, 1);
em = lookup_extent_mapping(&map_tree->map_tree, logical, 1);
-
spin
_unlock(&map_tree->map_tree.lock);
+
read
_unlock(&map_tree->map_tree.lock);
/* already mapped? */
if (em && em->start <= logical && em->start + em->len > logical) {
/* already mapped? */
if (em && em->start <= logical && em->start + em->len > logical) {
@@
-3114,9
+3175,9
@@
static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
map->stripes[i].dev->in_fs_metadata = 1;
}
map->stripes[i].dev->in_fs_metadata = 1;
}
-
spin
_lock(&map_tree->map_tree.lock);
+
write
_lock(&map_tree->map_tree.lock);
ret = add_extent_mapping(&map_tree->map_tree, em);
ret = add_extent_mapping(&map_tree->map_tree, em);
-
spin
_unlock(&map_tree->map_tree.lock);
+
write
_unlock(&map_tree->map_tree.lock);
BUG_ON(ret);
free_extent_map(em);
BUG_ON(ret);
free_extent_map(em);
@@
-3334,6
+3395,8
@@
int btrfs_read_chunk_tree(struct btrfs_root *root)
key.type = 0;
again:
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
key.type = 0;
again:
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ if (ret < 0)
+ goto error;
while (1) {
leaf = path->nodes[0];
slot = path->slots[0];
while (1) {
leaf = path->nodes[0];
slot = path->slots[0];