Merge branch 'allocator' of git://git.kernel.org/pub/scm/linux/kernel/git/arne/btrfs...
authorChris Mason <chris.mason@oracle.com>
Sun, 22 May 2011 16:36:34 +0000 (12:36 -0400)
committerChris Mason <chris.mason@oracle.com>
Sun, 22 May 2011 16:36:34 +0000 (12:36 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
1  2 
fs/btrfs/super.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h

diff --combined fs/btrfs/super.c
index fb72e2bea882ff7d9fc5e56176770ae7b8854497,32fe8b33cc1ce574bcafa0b1a0b292e82f23c831..006655c1d1f75f410e55ab02ba422e88b2464a47
@@@ -40,7 -40,6 +40,7 @@@
  #include <linux/magic.h>
  #include <linux/slab.h>
  #include "compat.h"
 +#include "delayed-inode.h"
  #include "ctree.h"
  #include "disk-io.h"
  #include "transaction.h"
@@@ -740,7 -739,7 +740,7 @@@ static int btrfs_set_super(struct super
   *      for multiple device setup.  Make sure to keep it in sync.
   */
  static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
 -              const char *dev_name, void *data)
 +              const char *device_name, void *data)
  {
        struct block_device *bdev = NULL;
        struct super_block *s;
        if (error)
                return ERR_PTR(error);
  
 -      error = btrfs_scan_one_device(dev_name, mode, fs_type, &fs_devices);
 +      error = btrfs_scan_one_device(device_name, mode, fs_type, &fs_devices);
        if (error)
                goto error_free_subvol_name;
  
@@@ -914,6 -913,32 +914,32 @@@ static int btrfs_remount(struct super_b
        return 0;
  }
  
+ /* Used to sort the devices by max_avail(descending sort) */
+ static int btrfs_cmp_device_free_bytes(const void *dev_info1,
+                                      const void *dev_info2)
+ {
+       if (((struct btrfs_device_info *)dev_info1)->max_avail >
+           ((struct btrfs_device_info *)dev_info2)->max_avail)
+               return -1;
+       else if (((struct btrfs_device_info *)dev_info1)->max_avail <
+                ((struct btrfs_device_info *)dev_info2)->max_avail)
+               return 1;
+       else
+       return 0;
+ }
+ /*
+  * sort the devices by max_avail, in which max free extent size of each device
+  * is stored.(Descending Sort)
+  */
+ static inline void btrfs_descending_sort_devices(
+                                       struct btrfs_device_info *devices,
+                                       size_t nr_devices)
+ {
+       sort(devices, nr_devices, sizeof(struct btrfs_device_info),
+            btrfs_cmp_device_free_bytes, NULL);
+ }
  /*
   * The helper to calc the free space on the devices that can be used to store
   * file data.
@@@ -1207,14 -1232,10 +1233,14 @@@ static int __init init_btrfs_fs(void
        if (err)
                goto free_extent_io;
  
 -      err = btrfs_interface_init();
 +      err = btrfs_delayed_inode_init();
        if (err)
                goto free_extent_map;
  
 +      err = btrfs_interface_init();
 +      if (err)
 +              goto free_delayed_inode;
 +
        err = register_filesystem(&btrfs_fs_type);
        if (err)
                goto unregister_ioctl;
  
  unregister_ioctl:
        btrfs_interface_exit();
 +free_delayed_inode:
 +      btrfs_delayed_inode_exit();
  free_extent_map:
        extent_map_exit();
  free_extent_io:
@@@ -1242,7 -1261,6 +1268,7 @@@ free_sysfs
  static void __exit exit_btrfs_fs(void)
  {
        btrfs_destroy_cachep();
 +      btrfs_delayed_inode_exit();
        extent_map_exit();
        extent_io_exit();
        btrfs_interface_exit();
diff --combined fs/btrfs/volumes.c
index cd0b31a9ba3d360145b63f902b1e8ec61842f7a4,ab55bfc31a068261d1c0e5fbe7b7d49c63768515..f777145203df0397d40baa67a87f91d4860e4052
@@@ -44,6 -44,16 +44,6 @@@ static int btrfs_relocate_sys_chunks(st
  static DEFINE_MUTEX(uuid_mutex);
  static LIST_HEAD(fs_uuids);
  
 -void btrfs_lock_volumes(void)
 -{
 -      mutex_lock(&uuid_mutex);
 -}
 -
 -void btrfs_unlock_volumes(void)
 -{
 -      mutex_unlock(&uuid_mutex);
 -}
 -
  static void lock_chunks(struct btrfs_root *root)
  {
        mutex_lock(&root->fs_info->chunk_mutex);
@@@ -141,25 -151,22 +141,25 @@@ static noinline int run_scheduled_bios(
        struct bio *cur;
        int again = 0;
        unsigned long num_run;
 -      unsigned long num_sync_run;
        unsigned long batch_run = 0;
        unsigned long limit;
        unsigned long last_waited = 0;
        int force_reg = 0;
 +      struct blk_plug plug;
 +
 +      /*
 +       * this function runs all the bios we've collected for
 +       * a particular device.  We don't want to wander off to
 +       * another device without first sending all of these down.
 +       * So, setup a plug here and finish it off before we return
 +       */
 +      blk_start_plug(&plug);
  
        bdi = blk_get_backing_dev_info(device->bdev);
        fs_info = device->dev_root->fs_info;
        limit = btrfs_async_submit_limit(fs_info);
        limit = limit * 2 / 3;
  
 -      /* we want to make sure that every time we switch from the sync
 -       * list to the normal list, we unplug
 -       */
 -      num_sync_run = 0;
 -
  loop:
        spin_lock(&device->io_lock);
  
@@@ -205,6 -212,15 +205,6 @@@ loop_lock
  
        spin_unlock(&device->io_lock);
  
 -      /*
 -       * if we're doing the regular priority list, make sure we unplug
 -       * for any high prio bios we've sent down
 -       */
 -      if (pending_bios == &device->pending_bios && num_sync_run > 0) {
 -              num_sync_run = 0;
 -              blk_run_backing_dev(bdi, NULL);
 -      }
 -
        while (pending) {
  
                rmb();
  
                BUG_ON(atomic_read(&cur->bi_cnt) == 0);
  
 -              if (cur->bi_rw & REQ_SYNC)
 -                      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);
 -                              num_sync_run = 0;
 -                      }
 +              if (need_resched())
                        cond_resched();
 -              }
  
                /*
                 * we made progress, there is more work to do and the bdi
                                 * against it before looping
                                 */
                                last_waited = ioc->last_waited;
 -                              if (need_resched()) {
 -                                      if (num_sync_run) {
 -                                              blk_run_backing_dev(bdi, NULL);
 -                                              num_sync_run = 0;
 -                                      }
 +                              if (need_resched())
                                        cond_resched();
 -                              }
                                continue;
                        }
                        spin_lock(&device->io_lock);
                }
        }
  
 -      if (num_sync_run) {
 -              num_sync_run = 0;
 -              blk_run_backing_dev(bdi, NULL);
 -      }
 -      /*
 -       * IO has already been through a long path to get here.  Checksumming,
 -       * async helper threads, perhaps compression.  We've done a pretty
 -       * good job of collecting a batch of IO and should just unplug
 -       * the device right away.
 -       *
 -       * This will help anyone who is waiting on the IO, they might have
 -       * already unplugged, but managed to do so before the bio they
 -       * cared about found its way down here.
 -       */
 -      blk_run_backing_dev(bdi, NULL);
 -
        cond_resched();
        if (again)
                goto loop;
        spin_unlock(&device->io_lock);
  
  done:
 +      blk_finish_plug(&plug);
        return 0;
  }
  
@@@ -805,10 -849,7 +805,7 @@@ int find_free_dev_extent(struct btrfs_t
        /* we don't want to overwrite the superblock on the drive,
         * so we make sure to start at an offset of at least 1MB
         */
-       search_start = 1024 * 1024;
-       if (root->fs_info->alloc_start + num_bytes <= search_end)
-               search_start = max(root->fs_info->alloc_start, search_start);
+       search_start = max(root->fs_info->alloc_start, 1024ull * 1024);
  
        max_hole_start = search_start;
        max_hole_size = 0;
@@@ -1465,7 -1506,7 +1462,7 @@@ next_slot
                                goto error;
                        leaf = path->nodes[0];
                        btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                        continue;
                }
  
@@@ -1937,7 -1978,7 +1934,7 @@@ again
                chunk = btrfs_item_ptr(leaf, path->slots[0],
                                       struct btrfs_chunk);
                chunk_type = btrfs_chunk_type(leaf, chunk);
 -              btrfs_release_path(chunk_root, path);
 +              btrfs_release_path(path);
  
                if (chunk_type & BTRFS_BLOCK_GROUP_SYSTEM) {
                        ret = btrfs_relocate_chunk(chunk_root, chunk_tree,
@@@ -2055,7 -2096,7 +2052,7 @@@ int btrfs_balance(struct btrfs_root *de
                if (found_key.offset == 0)
                        break;
  
 -              btrfs_release_path(chunk_root, path);
 +              btrfs_release_path(path);
                ret = btrfs_relocate_chunk(chunk_root,
                                           chunk_root->root_key.objectid,
                                           found_key.objectid,
@@@ -2127,7 -2168,7 +2124,7 @@@ again
                        goto done;
                if (ret) {
                        ret = 0;
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                        break;
                }
  
                btrfs_item_key_to_cpu(l, &key, path->slots[0]);
  
                if (key.objectid != device->devid) {
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                        break;
                }
  
                length = btrfs_dev_extent_length(l, dev_extent);
  
                if (key.offset + length <= new_size) {
 -                      btrfs_release_path(root, path);
 +                      btrfs_release_path(path);
                        break;
                }
  
                chunk_tree = btrfs_dev_extent_chunk_tree(l, dev_extent);
                chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent);
                chunk_offset = btrfs_dev_extent_chunk_offset(l, dev_extent);
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
  
                ret = btrfs_relocate_chunk(root, chunk_tree, chunk_objectid,
                                           chunk_offset);
@@@ -2227,275 -2268,204 +2224,204 @@@ static int btrfs_add_system_chunk(struc
        return 0;
  }
  
- static noinline u64 chunk_bytes_by_type(u64 type, u64 calc_size,
-                                       int num_stripes, int sub_stripes)
+ /*
+  * sort the devices in descending order by max_avail, total_avail
+  */
+ static int btrfs_cmp_device_info(const void *a, const void *b)
  {
-       if (type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP))
-               return calc_size;
-       else if (type & BTRFS_BLOCK_GROUP_RAID10)
-               return calc_size * (num_stripes / sub_stripes);
-       else
-               return calc_size * num_stripes;
- }
+       const struct btrfs_device_info *di_a = a;
+       const struct btrfs_device_info *di_b = b;
  
- /* Used to sort the devices by max_avail(descending sort) */
- int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2)
- {
-       if (((struct btrfs_device_info *)dev_info1)->max_avail >
-           ((struct btrfs_device_info *)dev_info2)->max_avail)
+       if (di_a->max_avail > di_b->max_avail)
                return -1;
-       else if (((struct btrfs_device_info *)dev_info1)->max_avail <
-                ((struct btrfs_device_info *)dev_info2)->max_avail)
+       if (di_a->max_avail < di_b->max_avail)
                return 1;
-       else
-               return 0;
+       if (di_a->total_avail > di_b->total_avail)
+               return -1;
+       if (di_a->total_avail < di_b->total_avail)
+               return 1;
+       return 0;
  }
  
- static int __btrfs_calc_nstripes(struct btrfs_fs_devices *fs_devices, u64 type,
-                                int *num_stripes, int *min_stripes,
-                                int *sub_stripes)
+ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
+                              struct btrfs_root *extent_root,
+                              struct map_lookup **map_ret,
+                              u64 *num_bytes_out, u64 *stripe_size_out,
+                              u64 start, u64 type)
  {
-       *num_stripes = 1;
-       *min_stripes = 1;
-       *sub_stripes = 0;
+       struct btrfs_fs_info *info = extent_root->fs_info;
+       struct btrfs_fs_devices *fs_devices = info->fs_devices;
+       struct list_head *cur;
+       struct map_lookup *map = NULL;
+       struct extent_map_tree *em_tree;
+       struct extent_map *em;
+       struct btrfs_device_info *devices_info = NULL;
+       u64 total_avail;
+       int num_stripes;        /* total number of stripes to allocate */
+       int sub_stripes;        /* sub_stripes info for map */
+       int dev_stripes;        /* stripes per dev */
+       int devs_max;           /* max devs to use */
+       int devs_min;           /* min devs needed */
+       int devs_increment;     /* ndevs has to be a multiple of this */
+       int ncopies;            /* how many copies to data has */
+       int ret;
+       u64 max_stripe_size;
+       u64 max_chunk_size;
+       u64 stripe_size;
+       u64 num_bytes;
+       int ndevs;
+       int i;
+       int j;
  
-       if (type & (BTRFS_BLOCK_GROUP_RAID0)) {
-               *num_stripes = fs_devices->rw_devices;
-               *min_stripes = 2;
-       }
-       if (type & (BTRFS_BLOCK_GROUP_DUP)) {
-               *num_stripes = 2;
-               *min_stripes = 2;
-       }
-       if (type & (BTRFS_BLOCK_GROUP_RAID1)) {
-               if (fs_devices->rw_devices < 2)
-                       return -ENOSPC;
-               *num_stripes = 2;
-               *min_stripes = 2;
-       }
-       if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
-               *num_stripes = fs_devices->rw_devices;
-               if (*num_stripes < 4)
-                       return -ENOSPC;
-               *num_stripes &= ~(u32)1;
-               *sub_stripes = 2;
-               *min_stripes = 4;
+       if ((type & BTRFS_BLOCK_GROUP_RAID1) &&
+           (type & BTRFS_BLOCK_GROUP_DUP)) {
+               WARN_ON(1);
+               type &= ~BTRFS_BLOCK_GROUP_DUP;
        }
  
-       return 0;
- }
+       if (list_empty(&fs_devices->alloc_list))
+               return -ENOSPC;
  
- static u64 __btrfs_calc_stripe_size(struct btrfs_fs_devices *fs_devices,
-                                   u64 proposed_size, u64 type,
-                                   int num_stripes, int small_stripe)
- {
-       int min_stripe_size = 1 * 1024 * 1024;
-       u64 calc_size = proposed_size;
-       u64 max_chunk_size = calc_size;
-       int ncopies = 1;
-       if (type & (BTRFS_BLOCK_GROUP_RAID1 |
-                   BTRFS_BLOCK_GROUP_DUP |
-                   BTRFS_BLOCK_GROUP_RAID10))
+       sub_stripes = 1;
+       dev_stripes = 1;
+       devs_increment = 1;
+       ncopies = 1;
+       devs_max = 0;   /* 0 == as many as possible */
+       devs_min = 1;
+       /*
+        * define the properties of each RAID type.
+        * FIXME: move this to a global table and use it in all RAID
+        * calculation code
+        */
+       if (type & (BTRFS_BLOCK_GROUP_DUP)) {
+               dev_stripes = 2;
                ncopies = 2;
+               devs_max = 1;
+       } else if (type & (BTRFS_BLOCK_GROUP_RAID0)) {
+               devs_min = 2;
+       } else if (type & (BTRFS_BLOCK_GROUP_RAID1)) {
+               devs_increment = 2;
+               ncopies = 2;
+               devs_max = 2;
+               devs_min = 2;
+       } else if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
+               sub_stripes = 2;
+               devs_increment = 2;
+               ncopies = 2;
+               devs_min = 4;
+       } else {
+               devs_max = 1;
+       }
  
        if (type & BTRFS_BLOCK_GROUP_DATA) {
-               max_chunk_size = 10 * calc_size;
-               min_stripe_size = 64 * 1024 * 1024;
+               max_stripe_size = 1024 * 1024 * 1024;
+               max_chunk_size = 10 * max_stripe_size;
        } else if (type & BTRFS_BLOCK_GROUP_METADATA) {
-               max_chunk_size = 256 * 1024 * 1024;
-               min_stripe_size = 32 * 1024 * 1024;
+               max_stripe_size = 256 * 1024 * 1024;
+               max_chunk_size = max_stripe_size;
        } else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
-               calc_size = 8 * 1024 * 1024;
-               max_chunk_size = calc_size * 2;
-               min_stripe_size = 1 * 1024 * 1024;
+               max_stripe_size = 8 * 1024 * 1024;
+               max_chunk_size = 2 * max_stripe_size;
+       } else {
+               printk(KERN_ERR "btrfs: invalid chunk type 0x%llx requested\n",
+                      type);
+               BUG_ON(1);
        }
  
        /* we don't want a chunk larger than 10% of writeable space */
        max_chunk_size = min(div_factor(fs_devices->total_rw_bytes, 1),
                             max_chunk_size);
  
-       if (calc_size * num_stripes > max_chunk_size * ncopies) {
-               calc_size = max_chunk_size * ncopies;
-               do_div(calc_size, num_stripes);
-               do_div(calc_size, BTRFS_STRIPE_LEN);
-               calc_size *= BTRFS_STRIPE_LEN;
-       }
+       devices_info = kzalloc(sizeof(*devices_info) * fs_devices->rw_devices,
+                              GFP_NOFS);
+       if (!devices_info)
+               return -ENOMEM;
  
-       /* we don't want tiny stripes */
-       if (!small_stripe)
-               calc_size = max_t(u64, min_stripe_size, calc_size);
+       cur = fs_devices->alloc_list.next;
  
        /*
-        * we're about to do_div by the BTRFS_STRIPE_LEN so lets make sure
-        * we end up with something bigger than a stripe
+        * in the first pass through the devices list, we gather information
+        * about the available holes on each device.
         */
-       calc_size = max_t(u64, calc_size, BTRFS_STRIPE_LEN);
-       do_div(calc_size, BTRFS_STRIPE_LEN);
-       calc_size *= BTRFS_STRIPE_LEN;
-       return calc_size;
- }
- static struct map_lookup *__shrink_map_lookup_stripes(struct map_lookup *map,
-                                                     int num_stripes)
- {
-       struct map_lookup *new;
-       size_t len = map_lookup_size(num_stripes);
-       BUG_ON(map->num_stripes < num_stripes);
-       if (map->num_stripes == num_stripes)
-               return map;
-       new = kmalloc(len, GFP_NOFS);
-       if (!new) {
-               /* just change map->num_stripes */
-               map->num_stripes = num_stripes;
-               return map;
-       }
+       ndevs = 0;
+       while (cur != &fs_devices->alloc_list) {
+               struct btrfs_device *device;
+               u64 max_avail;
+               u64 dev_offset;
  
-       memcpy(new, map, len);
-       new->num_stripes = num_stripes;
-       kfree(map);
-       return new;
- }
- /*
-  * helper to allocate device space from btrfs_device_info, in which we stored
-  * max free space information of every device. It is used when we can not
-  * allocate chunks by default size.
-  *
-  * By this helper, we can allocate a new chunk as larger as possible.
-  */
- static int __btrfs_alloc_tiny_space(struct btrfs_trans_handle *trans,
-                                   struct btrfs_fs_devices *fs_devices,
-                                   struct btrfs_device_info *devices,
-                                   int nr_device, u64 type,
-                                   struct map_lookup **map_lookup,
-                                   int min_stripes, u64 *stripe_size)
- {
-       int i, index, sort_again = 0;
-       int min_devices = min_stripes;
-       u64 max_avail, min_free;
-       struct map_lookup *map = *map_lookup;
-       int ret;
+               device = list_entry(cur, struct btrfs_device, dev_alloc_list);
  
-       if (nr_device < min_stripes)
-               return -ENOSPC;
+               cur = cur->next;
  
-       btrfs_descending_sort_devices(devices, nr_device);
+               if (!device->writeable) {
+                       printk(KERN_ERR
+                              "btrfs: read-only device in alloc_list\n");
+                       WARN_ON(1);
+                       continue;
+               }
  
-       max_avail = devices[0].max_avail;
-       if (!max_avail)
-               return -ENOSPC;
+               if (!device->in_fs_metadata)
+                       continue;
  
-       for (i = 0; i < nr_device; i++) {
-               /*
-                * if dev_offset = 0, it means the free space of this device
-                * is less than what we need, and we didn't search max avail
-                * extent on this device, so do it now.
+               if (device->total_bytes > device->bytes_used)
+                       total_avail = device->total_bytes - device->bytes_used;
+               else
+                       total_avail = 0;
+               /* avail is off by max(alloc_start, 1MB), but that is the same
+                * for all devices, so it doesn't hurt the sorting later on
                 */
-               if (!devices[i].dev_offset) {
-                       ret = find_free_dev_extent(trans, devices[i].dev,
-                                                  max_avail,
-                                                  &devices[i].dev_offset,
-                                                  &devices[i].max_avail);
-                       if (ret != 0 && ret != -ENOSPC)
-                               return ret;
-                       sort_again = 1;
-               }
-       }
-       /* we update the max avail free extent of each devices, sort again */
-       if (sort_again)
-               btrfs_descending_sort_devices(devices, nr_device);
  
-       if (type & BTRFS_BLOCK_GROUP_DUP)
-               min_devices = 1;
+               ret = find_free_dev_extent(trans, device,
+                                          max_stripe_size * dev_stripes,
+                                          &dev_offset, &max_avail);
+               if (ret && ret != -ENOSPC)
+                       goto error;
  
-       if (!devices[min_devices - 1].max_avail)
-               return -ENOSPC;
+               if (ret == 0)
+                       max_avail = max_stripe_size * dev_stripes;
  
-       max_avail = devices[min_devices - 1].max_avail;
-       if (type & BTRFS_BLOCK_GROUP_DUP)
-               do_div(max_avail, 2);
+               if (max_avail < BTRFS_STRIPE_LEN * dev_stripes)
+                       continue;
  
-       max_avail = __btrfs_calc_stripe_size(fs_devices, max_avail, type,
-                                            min_stripes, 1);
-       if (type & BTRFS_BLOCK_GROUP_DUP)
-               min_free = max_avail * 2;
-       else
-               min_free = max_avail;
+               devices_info[ndevs].dev_offset = dev_offset;
+               devices_info[ndevs].max_avail = max_avail;
+               devices_info[ndevs].total_avail = total_avail;
+               devices_info[ndevs].dev = device;
+               ++ndevs;
+       }
  
-       if (min_free > devices[min_devices - 1].max_avail)
-               return -ENOSPC;
+       /*
+        * now sort the devices by hole size / available space
+        */
+       sort(devices_info, ndevs, sizeof(struct btrfs_device_info),
+            btrfs_cmp_device_info, NULL);
  
-       map = __shrink_map_lookup_stripes(map, min_stripes);
-       *stripe_size = max_avail;
+       /* round down to number of usable stripes */
+       ndevs -= ndevs % devs_increment;
  
-       index = 0;
-       for (i = 0; i < min_stripes; i++) {
-               map->stripes[i].dev = devices[index].dev;
-               map->stripes[i].physical = devices[index].dev_offset;
-               if (type & BTRFS_BLOCK_GROUP_DUP) {
-                       i++;
-                       map->stripes[i].dev = devices[index].dev;
-                       map->stripes[i].physical = devices[index].dev_offset +
-                                                  max_avail;
-               }
-               index++;
+       if (ndevs < devs_increment * sub_stripes || ndevs < devs_min) {
+               ret = -ENOSPC;
+               goto error;
        }
-       *map_lookup = map;
  
-       return 0;
- }
- static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
-                              struct btrfs_root *extent_root,
-                              struct map_lookup **map_ret,
-                              u64 *num_bytes, u64 *stripe_size,
-                              u64 start, u64 type)
- {
-       struct btrfs_fs_info *info = extent_root->fs_info;
-       struct btrfs_device *device = NULL;
-       struct btrfs_fs_devices *fs_devices = info->fs_devices;
-       struct list_head *cur;
-       struct map_lookup *map;
-       struct extent_map_tree *em_tree;
-       struct extent_map *em;
-       struct btrfs_device_info *devices_info;
-       struct list_head private_devs;
-       u64 calc_size = 1024 * 1024 * 1024;
-       u64 min_free;
-       u64 avail;
-       u64 dev_offset;
-       int num_stripes;
-       int min_stripes;
-       int sub_stripes;
-       int min_devices;        /* the min number of devices we need */
-       int i;
-       int ret;
-       int index;
+       if (devs_max && ndevs > devs_max)
+               ndevs = devs_max;
+       /*
+        * the primary goal is to maximize the number of stripes, so use as many
+        * devices as possible, even if the stripes are not maximum sized.
+        */
+       stripe_size = devices_info[ndevs-1].max_avail;
+       num_stripes = ndevs * dev_stripes;
  
-       if ((type & BTRFS_BLOCK_GROUP_RAID1) &&
-           (type & BTRFS_BLOCK_GROUP_DUP)) {
-               WARN_ON(1);
-               type &= ~BTRFS_BLOCK_GROUP_DUP;
+       if (stripe_size * num_stripes > max_chunk_size * ncopies) {
+               stripe_size = max_chunk_size * ncopies;
+               do_div(stripe_size, num_stripes);
        }
-       if (list_empty(&fs_devices->alloc_list))
-               return -ENOSPC;
-       ret = __btrfs_calc_nstripes(fs_devices, type, &num_stripes,
-                                   &min_stripes, &sub_stripes);
-       if (ret)
-               return ret;
  
-       devices_info = kzalloc(sizeof(*devices_info) * fs_devices->rw_devices,
-                              GFP_NOFS);
-       if (!devices_info)
-               return -ENOMEM;
+       do_div(stripe_size, dev_stripes);
+       do_div(stripe_size, BTRFS_STRIPE_LEN);
+       stripe_size *= BTRFS_STRIPE_LEN;
  
        map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
        if (!map) {
        }
        map->num_stripes = num_stripes;
  
-       cur = fs_devices->alloc_list.next;
-       index = 0;
-       i = 0;
-       calc_size = __btrfs_calc_stripe_size(fs_devices, calc_size, type,
-                                            num_stripes, 0);
-       if (type & BTRFS_BLOCK_GROUP_DUP) {
-               min_free = calc_size * 2;
-               min_devices = 1;
-       } else {
-               min_free = calc_size;
-               min_devices = min_stripes;
-       }
-       INIT_LIST_HEAD(&private_devs);
-       while (index < num_stripes) {
-               device = list_entry(cur, struct btrfs_device, dev_alloc_list);
-               BUG_ON(!device->writeable);
-               if (device->total_bytes > device->bytes_used)
-                       avail = device->total_bytes - device->bytes_used;
-               else
-                       avail = 0;
-               cur = cur->next;
-               if (device->in_fs_metadata && avail >= min_free) {
-                       ret = find_free_dev_extent(trans, device, min_free,
-                                                  &devices_info[i].dev_offset,
-                                                  &devices_info[i].max_avail);
-                       if (ret == 0) {
-                               list_move_tail(&device->dev_alloc_list,
-                                              &private_devs);
-                               map->stripes[index].dev = device;
-                               map->stripes[index].physical =
-                                               devices_info[i].dev_offset;
-                               index++;
-                               if (type & BTRFS_BLOCK_GROUP_DUP) {
-                                       map->stripes[index].dev = device;
-                                       map->stripes[index].physical =
-                                               devices_info[i].dev_offset +
-                                               calc_size;
-                                       index++;
-                               }
-                       } else if (ret != -ENOSPC)
-                               goto error;
-                       devices_info[i].dev = device;
-                       i++;
-               } else if (device->in_fs_metadata &&
-                          avail >= BTRFS_STRIPE_LEN) {
-                       devices_info[i].dev = device;
-                       devices_info[i].max_avail = avail;
-                       i++;
-               }
-               if (cur == &fs_devices->alloc_list)
-                       break;
-       }
-       list_splice(&private_devs, &fs_devices->alloc_list);
-       if (index < num_stripes) {
-               if (index >= min_stripes) {
-                       num_stripes = index;
-                       if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
-                               num_stripes /= sub_stripes;
-                               num_stripes *= sub_stripes;
-                       }
-                       map = __shrink_map_lookup_stripes(map, num_stripes);
-               } else if (i >= min_devices) {
-                       ret = __btrfs_alloc_tiny_space(trans, fs_devices,
-                                                      devices_info, i, type,
-                                                      &map, min_stripes,
-                                                      &calc_size);
-                       if (ret)
-                               goto error;
-               } else {
-                       ret = -ENOSPC;
-                       goto error;
+       for (i = 0; i < ndevs; ++i) {
+               for (j = 0; j < dev_stripes; ++j) {
+                       int s = i * dev_stripes + j;
+                       map->stripes[s].dev = devices_info[i].dev;
+                       map->stripes[s].physical = devices_info[i].dev_offset +
+                                                  j * stripe_size;
                }
        }
        map->sector_size = extent_root->sectorsize;
        map->sub_stripes = sub_stripes;
  
        *map_ret = map;
-       *stripe_size = calc_size;
-       *num_bytes = chunk_bytes_by_type(type, calc_size,
-                                        map->num_stripes, sub_stripes);
+       num_bytes = stripe_size * (num_stripes / ncopies);
+       *stripe_size_out = stripe_size;
+       *num_bytes_out = num_bytes;
  
-       trace_btrfs_chunk_alloc(info->chunk_root, map, start, *num_bytes);
+       trace_btrfs_chunk_alloc(info->chunk_root, map, start, num_bytes);
  
 -      em = alloc_extent_map(GFP_NOFS);
 +      em = alloc_extent_map();
        if (!em) {
                ret = -ENOMEM;
                goto error;
        }
        em->bdev = (struct block_device *)map;
        em->start = start;
-       em->len = *num_bytes;
+       em->len = num_bytes;
        em->block_start = 0;
        em->block_len = em->len;
  
  
        ret = btrfs_make_block_group(trans, extent_root, 0, type,
                                     BTRFS_FIRST_CHUNK_TREE_OBJECTID,
-                                    start, *num_bytes);
+                                    start, num_bytes);
        BUG_ON(ret);
  
-       index = 0;
-       while (index < map->num_stripes) {
-               device = map->stripes[index].dev;
-               dev_offset = map->stripes[index].physical;
+       for (i = 0; i < map->num_stripes; ++i) {
+               struct btrfs_device *device;
+               u64 dev_offset;
+               device = map->stripes[i].dev;
+               dev_offset = map->stripes[i].physical;
  
                ret = btrfs_alloc_dev_extent(trans, device,
                                info->chunk_root->root_key.objectid,
                                BTRFS_FIRST_CHUNK_TREE_OBJECTID,
-                               start, dev_offset, calc_size);
+                               start, dev_offset, stripe_size);
                BUG_ON(ret);
-               index++;
        }
  
        kfree(devices_info);
@@@ -2839,7 -2738,7 +2694,7 @@@ int btrfs_chunk_readonly(struct btrfs_r
  
  void btrfs_mapping_init(struct btrfs_mapping_tree *tree)
  {
 -      extent_map_tree_init(&tree->map_tree, GFP_NOFS);
 +      extent_map_tree_init(&tree->map_tree);
  }
  
  void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree)
@@@ -2905,7 -2804,7 +2760,7 @@@ static int find_live_mirror(struct map_
  static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
                             u64 logical, u64 *length,
                             struct btrfs_multi_bio **multi_ret,
 -                           int mirror_num, struct page *unplug_page)
 +                           int mirror_num)
  {
        struct extent_map *em;
        struct map_lookup *map;
@@@ -2940,6 -2839,11 +2795,6 @@@ again
        em = lookup_extent_mapping(em_tree, logical, *length);
        read_unlock(&em_tree->lock);
  
 -      if (!em && unplug_page) {
 -              kfree(multi);
 -              return 0;
 -      }
 -
        if (!em) {
                printk(KERN_CRIT "unable to find logical %llu len %llu\n",
                       (unsigned long long)logical,
                *length = em->len - offset;
        }
  
 -      if (!multi_ret && !unplug_page)
 +      if (!multi_ret)
                goto out;
  
        num_stripes = 1;
                                            stripe_nr_end - stripe_nr_orig);
                stripe_index = do_div(stripe_nr, map->num_stripes);
        } else if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
 -              if (unplug_page || (rw & (REQ_WRITE | REQ_DISCARD)))
 +              if (rw & (REQ_WRITE | REQ_DISCARD))
                        num_stripes = map->num_stripes;
                else if (mirror_num)
                        stripe_index = mirror_num - 1;
                stripe_index = do_div(stripe_nr, factor);
                stripe_index *= map->sub_stripes;
  
 -              if (unplug_page || (rw & REQ_WRITE))
 +              if (rw & REQ_WRITE)
                        num_stripes = map->sub_stripes;
                else if (rw & REQ_DISCARD)
                        num_stripes = min_t(u64, map->sub_stripes *
                }
        } else {
                for (i = 0; i < num_stripes; i++) {
 -                      if (unplug_page) {
 -                              struct btrfs_device *device;
 -                              struct backing_dev_info *bdi;
 -
 -                              device = map->stripes[stripe_index].dev;
 -                              if (device->bdev) {
 -                                      bdi = blk_get_backing_dev_info(device->
 -                                                                     bdev);
 -                                      if (bdi->unplug_io_fn)
 -                                              bdi->unplug_io_fn(bdi,
 -                                                                unplug_page);
 -                              }
 -                      } else {
 -                              multi->stripes[i].physical =
 -                                      map->stripes[stripe_index].physical +
 -                                      stripe_offset +
 -                                      stripe_nr * map->stripe_len;
 -                              multi->stripes[i].dev =
 -                                      map->stripes[stripe_index].dev;
 -                      }
 +                      multi->stripes[i].physical =
 +                              map->stripes[stripe_index].physical +
 +                              stripe_offset +
 +                              stripe_nr * map->stripe_len;
 +                      multi->stripes[i].dev =
 +                              map->stripes[stripe_index].dev;
                        stripe_index++;
                }
        }
@@@ -3179,7 -3097,7 +3034,7 @@@ int btrfs_map_block(struct btrfs_mappin
                      struct btrfs_multi_bio **multi_ret, int mirror_num)
  {
        return __btrfs_map_block(map_tree, rw, logical, length, multi_ret,
 -                               mirror_num, NULL);
 +                               mirror_num);
  }
  
  int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
        return 0;
  }
  
 -int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree,
 -                    u64 logical, struct page *page)
 -{
 -      u64 length = PAGE_CACHE_SIZE;
 -      return __btrfs_map_block(map_tree, READ, logical, &length,
 -                               NULL, 0, page);
 -}
 -
  static void end_bio_multi_stripe(struct bio *bio, int err)
  {
        struct btrfs_multi_bio *multi = bio->bi_private;
@@@ -3489,7 -3415,7 +3344,7 @@@ static int read_one_chunk(struct btrfs_
                free_extent_map(em);
        }
  
 -      em = alloc_extent_map(GFP_NOFS);
 +      em = alloc_extent_map();
        if (!em)
                return -ENOMEM;
        num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
@@@ -3678,6 -3604,15 +3533,6 @@@ static int read_one_dev(struct btrfs_ro
        return ret;
  }
  
 -int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf)
 -{
 -      struct btrfs_dev_item *dev_item;
 -
 -      dev_item = (struct btrfs_dev_item *)offsetof(struct btrfs_super_block,
 -                                                   dev_item);
 -      return read_one_dev(root, buf, dev_item);
 -}
 -
  int btrfs_read_sys_array(struct btrfs_root *root)
  {
        struct btrfs_super_block *super_copy = &root->fs_info->super_copy;
@@@ -3794,7 -3729,7 +3649,7 @@@ again
        }
        if (key.objectid == BTRFS_DEV_ITEMS_OBJECTID) {
                key.objectid = 0;
 -              btrfs_release_path(root, path);
 +              btrfs_release_path(path);
                goto again;
        }
        ret = 0;
diff --combined fs/btrfs/volumes.h
index 5669ae8ea1c9ffa9306daa18416e101042cec68e,37ae6e2126a1cde2624228f20aab137071584a8a..05d5d199381adbfb3e65b69a60558f5eedafec8b
@@@ -144,6 -144,7 +144,7 @@@ struct btrfs_device_info 
        struct btrfs_device *dev;
        u64 dev_offset;
        u64 max_avail;
+       u64 total_avail;
  };
  
  struct map_lookup {
        struct btrfs_bio_stripe stripes[];
  };
  
- /* Used to sort the devices by max_avail(descending sort) */
- int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2);
- /*
-  * sort the devices by max_avail, in which max free extent size of each device
-  * is stored.(Descending Sort)
-  */
- static inline void btrfs_descending_sort_devices(
-                                       struct btrfs_device_info *devices,
-                                       size_t nr_devices)
- {
-       sort(devices, nr_devices, sizeof(struct btrfs_device_info),
-            btrfs_cmp_device_free_bytes, NULL);
- }
  int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,
                                   u64 end, u64 *length);
  
@@@ -196,6 -182,7 +182,6 @@@ void btrfs_mapping_init(struct btrfs_ma
  void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree);
  int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
                  int mirror_num, int async_submit);
 -int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf);
  int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                       fmode_t flags, void *holder);
  int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
@@@ -208,6 -195,8 +194,6 @@@ int btrfs_add_device(struct btrfs_trans
  int btrfs_rm_device(struct btrfs_root *root, char *device_path);
  int btrfs_cleanup_fs_uuids(void);
  int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len);
 -int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree,
 -                    u64 logical, struct page *page);
  int btrfs_grow_device(struct btrfs_trans_handle *trans,
                      struct btrfs_device *device, u64 new_size);
  struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid,
  int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
  int btrfs_init_new_device(struct btrfs_root *root, char *path);
  int btrfs_balance(struct btrfs_root *dev_root);
 -void btrfs_unlock_volumes(void);
 -void btrfs_lock_volumes(void);
  int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
  int find_free_dev_extent(struct btrfs_trans_handle *trans,
                         struct btrfs_device *device, u64 num_bytes,