uwb: add pal parameter to new reservation callback
[safe/jmp/linux-2.6] / drivers / md / dm-table.c
index d2eb3c5..a63161a 100644 (file)
@@ -43,7 +43,7 @@ struct dm_table {
         * device.  This should be a combination of FMODE_READ
         * and FMODE_WRITE.
         */
-       int mode;
+       fmode_t mode;
 
        /* a list of devices used by this table */
        struct list_head devices;
@@ -217,7 +217,7 @@ static int alloc_targets(struct dm_table *t, unsigned int num)
        return 0;
 }
 
-int dm_table_create(struct dm_table **result, int mode,
+int dm_table_create(struct dm_table **result, fmode_t mode,
                    unsigned num_targets, struct mapped_device *md)
 {
        struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL);
@@ -245,50 +245,13 @@ int dm_table_create(struct dm_table **result, int mode,
        return 0;
 }
 
-int dm_create_error_table(struct dm_table **result, struct mapped_device *md)
-{
-       struct dm_table *t;
-       sector_t dev_size = 1;
-       int r;
-
-       /*
-        * Find current size of device.
-        * Default to 1 sector if inactive.
-        */
-       t = dm_get_table(md);
-       if (t) {
-               dev_size = dm_table_get_size(t);
-               dm_table_put(t);
-       }
-
-       r = dm_table_create(&t, FMODE_READ, 1, md);
-       if (r)
-               return r;
-
-       r = dm_table_add_target(t, "error", 0, dev_size, NULL);
-       if (r)
-               goto out;
-
-       r = dm_table_complete(t);
-       if (r)
-               goto out;
-
-       *result = t;
-
-out:
-       if (r)
-               dm_table_put(t);
-
-       return r;
-}
-EXPORT_SYMBOL_GPL(dm_create_error_table);
-
 static void free_devices(struct list_head *devices)
 {
        struct list_head *tmp, *next;
 
        list_for_each_safe(tmp, next, devices) {
-               struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
+               struct dm_dev_internal *dd =
+                   list_entry(tmp, struct dm_dev_internal, list);
                kfree(dd);
        }
 }
@@ -350,44 +313,14 @@ static inline int check_space(struct dm_table *t)
 }
 
 /*
- * Convert a device path to a dev_t.
- */
-static int lookup_device(const char *path, dev_t *dev)
-{
-       int r;
-       struct nameidata nd;
-       struct inode *inode;
-
-       if ((r = path_lookup(path, LOOKUP_FOLLOW, &nd)))
-               return r;
-
-       inode = nd.dentry->d_inode;
-       if (!inode) {
-               r = -ENOENT;
-               goto out;
-       }
-
-       if (!S_ISBLK(inode->i_mode)) {
-               r = -ENOTBLK;
-               goto out;
-       }
-
-       *dev = inode->i_rdev;
-
- out:
-       path_release(&nd);
-       return r;
-}
-
-/*
  * See if we've already got a device in the list.
  */
-static struct dm_dev *find_device(struct list_head *l, dev_t dev)
+static struct dm_dev_internal *find_device(struct list_head *l, dev_t dev)
 {
-       struct dm_dev *dd;
+       struct dm_dev_internal *dd;
 
        list_for_each_entry (dd, l, list)
-               if (dd->bdev->bd_dev == dev)
+               if (dd->dm_dev.bdev->bd_dev == dev)
                        return dd;
 
        return NULL;
@@ -396,45 +329,47 @@ static struct dm_dev *find_device(struct list_head *l, dev_t dev)
 /*
  * Open a device so we can use it as a map destination.
  */
-static int open_dev(struct dm_dev *d, dev_t dev, struct mapped_device *md)
+static int open_dev(struct dm_dev_internal *d, dev_t dev,
+                   struct mapped_device *md)
 {
        static char *_claim_ptr = "I belong to device-mapper";
        struct block_device *bdev;
 
        int r;
 
-       BUG_ON(d->bdev);
+       BUG_ON(d->dm_dev.bdev);
 
-       bdev = open_by_devnum(dev, d->mode);
+       bdev = open_by_devnum(dev, d->dm_dev.mode);
        if (IS_ERR(bdev))
                return PTR_ERR(bdev);
        r = bd_claim_by_disk(bdev, _claim_ptr, dm_disk(md));
        if (r)
-               blkdev_put(bdev);
+               blkdev_put(bdev, d->dm_dev.mode);
        else
-               d->bdev = bdev;
+               d->dm_dev.bdev = bdev;
        return r;
 }
 
 /*
  * Close a device that we've been using.
  */
-static void close_dev(struct dm_dev *d, struct mapped_device *md)
+static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
 {
-       if (!d->bdev)
+       if (!d->dm_dev.bdev)
                return;
 
-       bd_release_from_disk(d->bdev, dm_disk(md));
-       blkdev_put(d->bdev);
-       d->bdev = NULL;
+       bd_release_from_disk(d->dm_dev.bdev, dm_disk(md));
+       blkdev_put(d->dm_dev.bdev, d->dm_dev.mode);
+       d->dm_dev.bdev = NULL;
 }
 
 /*
  * If possible, this checks an area of a destination device is valid.
  */
-static int check_device_area(struct dm_dev *dd, sector_t start, sector_t len)
+static int check_device_area(struct dm_dev_internal *dd, sector_t start,
+                            sector_t len)
 {
-       sector_t dev_size = dd->bdev->bd_inode->i_size >> SECTOR_SHIFT;
+       sector_t dev_size = dd->dm_dev.bdev->bd_inode->i_size >> SECTOR_SHIFT;
 
        if (!dev_size)
                return 1;
@@ -447,16 +382,17 @@ static int check_device_area(struct dm_dev *dd, sector_t start, sector_t len)
  * careful to leave things as they were if we fail to reopen the
  * device.
  */
-static int upgrade_mode(struct dm_dev *dd, int new_mode, struct mapped_device *md)
+static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode,
+                       struct mapped_device *md)
 {
        int r;
-       struct dm_dev dd_copy;
-       dev_t dev = dd->bdev->bd_dev;
+       struct dm_dev_internal dd_copy;
+       dev_t dev = dd->dm_dev.bdev->bd_dev;
 
        dd_copy = *dd;
 
-       dd->mode |= new_mode;
-       dd->bdev = NULL;
+       dd->dm_dev.mode |= new_mode;
+       dd->dm_dev.bdev = NULL;
        r = open_dev(dd, dev, md);
        if (!r)
                close_dev(&dd_copy, md);
@@ -472,11 +408,11 @@ static int upgrade_mode(struct dm_dev *dd, int new_mode, struct mapped_device *m
  */
 static int __table_get_device(struct dm_table *t, struct dm_target *ti,
                              const char *path, sector_t start, sector_t len,
-                             int mode, struct dm_dev **result)
+                             fmode_t mode, struct dm_dev **result)
 {
        int r;
-       dev_t dev;
-       struct dm_dev *dd;
+       dev_t uninitialized_var(dev);
+       struct dm_dev_internal *dd;
        unsigned int major, minor;
 
        BUG_ON(!t);
@@ -488,8 +424,12 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
                        return -EOVERFLOW;
        } else {
                /* convert the path to a device */
-               if ((r = lookup_device(path, &dev)))
-                       return r;
+               struct block_device *bdev = lookup_bdev(path);
+
+               if (IS_ERR(bdev))
+                       return PTR_ERR(bdev);
+               dev = bdev->bd_dev;
+               bdput(bdev);
        }
 
        dd = find_device(&t->devices, dev);
@@ -498,20 +438,20 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
                if (!dd)
                        return -ENOMEM;
 
-               dd->mode = mode;
-               dd->bdev = NULL;
+               dd->dm_dev.mode = mode;
+               dd->dm_dev.bdev = NULL;
 
                if ((r = open_dev(dd, dev, t->md))) {
                        kfree(dd);
                        return r;
                }
 
-               format_dev_t(dd->name, dev);
+               format_dev_t(dd->dm_dev.name, dev);
 
                atomic_set(&dd->count, 0);
                list_add(&dd->list, &t->devices);
 
-       } else if (dd->mode != (mode | dd->mode)) {
+       } else if (dd->dm_dev.mode != (mode | dd->dm_dev.mode)) {
                r = upgrade_mode(dd, mode, t->md);
                if (r)
                        return r;
@@ -520,11 +460,11 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
 
        if (!check_device_area(dd, start, len)) {
                DMWARN("device %s too small for target", path);
-               dm_put_device(ti, dd);
+               dm_put_device(ti, &dd->dm_dev);
                return -EINVAL;
        }
 
-       *result = dd;
+       *result = &dd->dm_dev;
 
        return 0;
 }
@@ -533,6 +473,13 @@ void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev)
 {
        struct request_queue *q = bdev_get_queue(bdev);
        struct io_restrictions *rs = &ti->limits;
+       char b[BDEVNAME_SIZE];
+
+       if (unlikely(!q)) {
+               DMWARN("%s: Cannot set limits for nonexistent device %s",
+                      dm_device_name(ti->table->md), bdevname(bdev, b));
+               return;
+       }
 
        /*
         * Combine the device limits low.
@@ -544,14 +491,13 @@ void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev)
        rs->max_sectors =
                min_not_zero(rs->max_sectors, q->max_sectors);
 
-       /* FIXME: Device-Mapper on top of RAID-0 breaks because DM
-        *        currently doesn't honor MD's merge_bvec_fn routine.
-        *        In this case, we'll force DM to use PAGE_SIZE or
-        *        smaller I/O, just to be safe. A better fix is in the
-        *        works, but add this for the time being so it will at
-        *        least operate correctly.
+       /*
+        * Check if merge fn is supported.
+        * If not we'll force DM to use PAGE_SIZE or
+        * smaller I/O, just to be safe.
         */
-       if (q->merge_bvec_fn)
+
+       if (q->merge_bvec_fn && !ti->type->merge)
                rs->max_sectors =
                        min_not_zero(rs->max_sectors,
                                     (unsigned int) (PAGE_SIZE >> 9));
@@ -582,7 +528,7 @@ void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev)
 EXPORT_SYMBOL_GPL(dm_set_device_limits);
 
 int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
-                 sector_t len, int mode, struct dm_dev **result)
+                 sector_t len, fmode_t mode, struct dm_dev **result)
 {
        int r = __table_get_device(ti->table, ti, path,
                                   start, len, mode, result);
@@ -596,8 +542,11 @@ int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
 /*
  * Decrement a devices use count and remove it if necessary.
  */
-void dm_put_device(struct dm_target *ti, struct dm_dev *dd)
+void dm_put_device(struct dm_target *ti, struct dm_dev *d)
 {
+       struct dm_dev_internal *dd = container_of(d, struct dm_dev_internal,
+                                                 dm_dev);
+
        if (atomic_dec_and_test(&dd->count)) {
                close_dev(dd, ti->table->md);
                list_del(&dd->list);
@@ -804,7 +753,7 @@ static int setup_indexes(struct dm_table *t)
                return -ENOMEM;
 
        /* set up internal nodes, bottom-up */
-       for (i = t->depth - 2, total = 0; i >= 0; i--) {
+       for (i = t->depth - 2; i >= 0; i--) {
                t->index[i] = indexes;
                indexes += (KEYS_PER_NODE * t->counts[i]);
                setup_btree_index(i, t);
@@ -911,10 +860,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q)
        q->max_hw_sectors = t->limits.max_hw_sectors;
        q->seg_boundary_mask = t->limits.seg_boundary_mask;
        q->bounce_pfn = t->limits.bounce_pfn;
+
        if (t->limits.no_cluster)
-               q->queue_flags &= ~(1 << QUEUE_FLAG_CLUSTER);
+               queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q);
        else
-               q->queue_flags |= (1 << QUEUE_FLAG_CLUSTER);
+               queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q);
 
 }
 
@@ -928,7 +878,7 @@ struct list_head *dm_table_get_devices(struct dm_table *t)
        return &t->devices;
 }
 
-int dm_table_get_mode(struct dm_table *t)
+fmode_t dm_table_get_mode(struct dm_table *t)
 {
        return t->mode;
 }
@@ -954,7 +904,7 @@ void dm_table_presuspend_targets(struct dm_table *t)
        if (!t)
                return;
 
-       return suspend_targets(t, 0);
+       suspend_targets(t, 0);
 }
 
 void dm_table_postsuspend_targets(struct dm_table *t)
@@ -962,7 +912,7 @@ void dm_table_postsuspend_targets(struct dm_table *t)
        if (!t)
                return;
 
-       return suspend_targets(t, 1);
+       suspend_targets(t, 1);
 }
 
 int dm_table_resume_targets(struct dm_table *t)
@@ -992,13 +942,20 @@ int dm_table_resume_targets(struct dm_table *t)
 
 int dm_table_any_congested(struct dm_table *t, int bdi_bits)
 {
-       struct dm_dev *dd;
+       struct dm_dev_internal *dd;
        struct list_head *devices = dm_table_get_devices(t);
        int r = 0;
 
        list_for_each_entry(dd, devices, list) {
-               struct request_queue *q = bdev_get_queue(dd->bdev);
-               r |= bdi_congested(&q->backing_dev_info, bdi_bits);
+               struct request_queue *q = bdev_get_queue(dd->dm_dev.bdev);
+               char b[BDEVNAME_SIZE];
+
+               if (likely(q))
+                       r |= bdi_congested(&q->backing_dev_info, bdi_bits);
+               else
+                       DMWARN_LIMIT("%s: any_congested: nonexistent device %s",
+                                    dm_device_name(t->md),
+                                    bdevname(dd->dm_dev.bdev, b));
        }
 
        return r;
@@ -1006,13 +963,19 @@ int dm_table_any_congested(struct dm_table *t, int bdi_bits)
 
 void dm_table_unplug_all(struct dm_table *t)
 {
-       struct dm_dev *dd;
+       struct dm_dev_internal *dd;
        struct list_head *devices = dm_table_get_devices(t);
 
        list_for_each_entry(dd, devices, list) {
-               struct request_queue *q = bdev_get_queue(dd->bdev);
-
-               blk_unplug(q);
+               struct request_queue *q = bdev_get_queue(dd->dm_dev.bdev);
+               char b[BDEVNAME_SIZE];
+
+               if (likely(q))
+                       blk_unplug(q);
+               else
+                       DMWARN_LIMIT("%s: Cannot unplug nonexistent device %s",
+                                    dm_device_name(t->md),
+                                    bdevname(dd->dm_dev.bdev, b));
        }
 }