]> Pileus Git - ~andy/linux/blobdiff - drivers/md/dm-thin.c
xtensa: fixup simdisk driver to work with immutable bio_vecs
[~andy/linux] / drivers / md / dm-thin.c
index 2c0cf511ec2385fa5a558b5d2e1e1ed0c874c9f6..357eb272dbd9d3337bf5d1a13db443261eb2b24b 100644 (file)
@@ -413,7 +413,7 @@ static bool block_size_is_power_of_two(struct pool *pool)
 static dm_block_t get_bio_block(struct thin_c *tc, struct bio *bio)
 {
        struct pool *pool = tc->pool;
-       sector_t block_nr = bio->bi_sector;
+       sector_t block_nr = bio->bi_iter.bi_sector;
 
        if (block_size_is_power_of_two(pool))
                block_nr >>= pool->sectors_per_block_shift;
@@ -426,14 +426,15 @@ static dm_block_t get_bio_block(struct thin_c *tc, struct bio *bio)
 static void remap(struct thin_c *tc, struct bio *bio, dm_block_t block)
 {
        struct pool *pool = tc->pool;
-       sector_t bi_sector = bio->bi_sector;
+       sector_t bi_sector = bio->bi_iter.bi_sector;
 
        bio->bi_bdev = tc->pool_dev->bdev;
        if (block_size_is_power_of_two(pool))
-               bio->bi_sector = (block << pool->sectors_per_block_shift) |
-                               (bi_sector & (pool->sectors_per_block - 1));
+               bio->bi_iter.bi_sector =
+                       (block << pool->sectors_per_block_shift) |
+                       (bi_sector & (pool->sectors_per_block - 1));
        else
-               bio->bi_sector = (block * pool->sectors_per_block) +
+               bio->bi_iter.bi_sector = (block * pool->sectors_per_block) +
                                 sector_div(bi_sector, pool->sectors_per_block);
 }
 
@@ -610,8 +611,10 @@ static void cell_defer_no_holder(struct thin_c *tc, struct dm_bio_prison_cell *c
 
 static void process_prepared_mapping_fail(struct dm_thin_new_mapping *m)
 {
-       if (m->bio)
+       if (m->bio) {
                m->bio->bi_end_io = m->saved_bi_end_io;
+               atomic_inc(&m->bio->bi_remaining);
+       }
        cell_error(m->tc->pool, m->cell);
        list_del(&m->list);
        mempool_free(m, m->tc->pool->mapping_pool);
@@ -625,8 +628,10 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m)
        int r;
 
        bio = m->bio;
-       if (bio)
+       if (bio) {
                bio->bi_end_io = m->saved_bi_end_io;
+               atomic_inc(&bio->bi_remaining);
+       }
 
        if (m->err) {
                cell_error(pool, m->cell);
@@ -640,7 +645,9 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m)
         */
        r = dm_thin_insert_block(tc->td, m->virt_block, m->data_block);
        if (r) {
-               DMERR_LIMIT("dm_thin_insert_block() failed");
+               DMERR_LIMIT("%s: dm_thin_insert_block() failed: error = %d",
+                           dm_device_name(pool->pool_md), r);
+               set_pool_mode(pool, PM_READ_ONLY);
                cell_error(pool, m->cell);
                goto out;
        }
@@ -721,7 +728,8 @@ static void process_prepared(struct pool *pool, struct list_head *head,
  */
 static int io_overlaps_block(struct pool *pool, struct bio *bio)
 {
-       return bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT);
+       return bio->bi_iter.bi_size ==
+               (pool->sectors_per_block << SECTOR_SHIFT);
 }
 
 static int io_overwrites_block(struct pool *pool, struct bio *bio)
@@ -881,32 +889,23 @@ static void schedule_zero(struct thin_c *tc, dm_block_t virt_block,
        }
 }
 
-static int commit(struct pool *pool)
-{
-       int r;
-
-       r = dm_pool_commit_metadata(pool->pmd);
-       if (r)
-               DMERR_LIMIT("%s: commit failed: error = %d",
-                           dm_device_name(pool->pool_md), r);
-
-       return r;
-}
-
 /*
  * A non-zero return indicates read_only or fail_io mode.
  * Many callers don't care about the return value.
  */
-static int commit_or_fallback(struct pool *pool)
+static int commit(struct pool *pool)
 {
        int r;
 
        if (get_pool_mode(pool) != PM_WRITE)
                return -EINVAL;
 
-       r = commit(pool);
-       if (r)
+       r = dm_pool_commit_metadata(pool->pmd);
+       if (r) {
+               DMERR_LIMIT("%s: dm_pool_commit_metadata failed: error = %d",
+                           dm_device_name(pool->pool_md), r);
                set_pool_mode(pool, PM_READ_ONLY);
+       }
 
        return r;
 }
@@ -943,7 +942,9 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
                 * Try to commit to see if that will free up some
                 * more space.
                 */
-               (void) commit_or_fallback(pool);
+               r = commit(pool);
+               if (r)
+                       return r;
 
                r = dm_pool_get_free_block_count(pool->pmd, &free_blocks);
                if (r)
@@ -957,7 +958,7 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
                 * table reload).
                 */
                if (!free_blocks) {
-                       DMWARN("%s: no free space available.",
+                       DMWARN("%s: no free data space available.",
                               dm_device_name(pool->pool_md));
                        spin_lock_irqsave(&pool->lock, flags);
                        pool->no_free_space = 1;
@@ -967,8 +968,16 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
        }
 
        r = dm_pool_alloc_data_block(pool->pmd, result);
-       if (r)
+       if (r) {
+               if (r == -ENOSPC &&
+                   !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) &&
+                   !free_blocks) {
+                       DMWARN("%s: no free metadata space available.",
+                              dm_device_name(pool->pool_md));
+                       set_pool_mode(pool, PM_READ_ONLY);
+               }
                return r;
+       }
 
        return 0;
 }
@@ -1130,7 +1139,7 @@ static void process_shared_bio(struct thin_c *tc, struct bio *bio,
        if (bio_detain(pool, &key, bio, &cell))
                return;
 
-       if (bio_data_dir(bio) == WRITE && bio->bi_size)
+       if (bio_data_dir(bio) == WRITE && bio->bi_iter.bi_size)
                break_sharing(tc, bio, block, &key, lookup_result, cell);
        else {
                struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
@@ -1153,7 +1162,7 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block
        /*
         * Remap empty bios (flushes) immediately, without provisioning.
         */
-       if (!bio->bi_size) {
+       if (!bio->bi_iter.bi_size) {
                inc_all_io_entry(pool, bio);
                cell_defer_no_holder(tc, cell);
 
@@ -1253,7 +1262,7 @@ static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
        r = dm_thin_find_block(tc->td, block, 1, &lookup_result);
        switch (r) {
        case 0:
-               if (lookup_result.shared && (rw == WRITE) && bio->bi_size)
+               if (lookup_result.shared && (rw == WRITE) && bio->bi_iter.bi_size)
                        bio_io_error(bio);
                else {
                        inc_all_io_entry(tc->pool, bio);
@@ -1349,7 +1358,7 @@ static void process_deferred_bios(struct pool *pool)
        if (bio_list_empty(&bios) && !need_commit_due_to_time(pool))
                return;
 
-       if (commit_or_fallback(pool)) {
+       if (commit(pool)) {
                while ((bio = bio_list_pop(&bios)))
                        bio_io_error(bio);
                return;
@@ -1397,6 +1406,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode mode)
        case PM_FAIL:
                DMERR("%s: switching pool to failure mode",
                      dm_device_name(pool->pool_md));
+               dm_pool_metadata_read_only(pool->pmd);
                pool->process_bio = process_bio_fail;
                pool->process_discard = process_bio_fail;
                pool->process_prepared_mapping = process_prepared_mapping_fail;
@@ -1421,6 +1431,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode mode)
                break;
 
        case PM_WRITE:
+               dm_pool_metadata_read_write(pool->pmd);
                pool->process_bio = process_bio;
                pool->process_discard = process_discard;
                pool->process_prepared_mapping = process_prepared_mapping;
@@ -1637,12 +1648,19 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
        struct pool_c *pt = ti->private;
 
        /*
-        * We want to make sure that degraded pools are never upgraded.
+        * We want to make sure that a pool in PM_FAIL mode is never upgraded.
         */
        enum pool_mode old_mode = pool->pf.mode;
        enum pool_mode new_mode = pt->adjusted_pf.mode;
 
-       if (old_mode > new_mode)
+       /*
+        * If we were in PM_FAIL mode, rollback of metadata failed.  We're
+        * not going to recover without a thin_repair.  So we never let the
+        * pool move out of the old mode.  On the other hand a PM_READ_ONLY
+        * may have been due to a lack of metadata or data space, and may
+        * now work (ie. if the underlying devices have been resized).
+        */
+       if (old_mode == PM_FAIL)
                new_mode = old_mode;
 
        pool->ti = ti;
@@ -2266,7 +2284,7 @@ static int pool_preresume(struct dm_target *ti)
                return r;
 
        if (need_commit1 || need_commit2)
-               (void) commit_or_fallback(pool);
+               (void) commit(pool);
 
        return 0;
 }
@@ -2293,7 +2311,7 @@ static void pool_postsuspend(struct dm_target *ti)
 
        cancel_delayed_work(&pool->waker);
        flush_workqueue(pool->wq);
-       (void) commit_or_fallback(pool);
+       (void) commit(pool);
 }
 
 static int check_arg_count(unsigned argc, unsigned args_required)
@@ -2427,7 +2445,7 @@ static int process_reserve_metadata_snap_mesg(unsigned argc, char **argv, struct
        if (r)
                return r;
 
-       (void) commit_or_fallback(pool);
+       (void) commit(pool);
 
        r = dm_pool_reserve_metadata_snap(pool->pmd);
        if (r)
@@ -2489,7 +2507,7 @@ static int pool_message(struct dm_target *ti, unsigned argc, char **argv)
                DMWARN("Unrecognised thin pool target message received: %s", argv[0]);
 
        if (!r)
-               (void) commit_or_fallback(pool);
+               (void) commit(pool);
 
        return r;
 }
@@ -2544,7 +2562,7 @@ static void pool_status(struct dm_target *ti, status_type_t type,
 
                /* Commit to ensure statistics aren't out-of-date */
                if (!(status_flags & DM_STATUS_NOFLUSH_FLAG) && !dm_suspended(ti))
-                       (void) commit_or_fallback(pool);
+                       (void) commit(pool);
 
                r = dm_pool_get_metadata_transaction_id(pool->pmd, &transaction_id);
                if (r) {
@@ -2867,7 +2885,7 @@ out_unlock:
 
 static int thin_map(struct dm_target *ti, struct bio *bio)
 {
-       bio->bi_sector = dm_target_offset(ti, bio->bi_sector);
+       bio->bi_iter.bi_sector = dm_target_offset(ti, bio->bi_iter.bi_sector);
 
        return thin_bio_map(ti, bio);
 }