These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / md / dm-snap.c
index f83a0f3..61f184a 100644 (file)
@@ -63,6 +63,13 @@ struct dm_snapshot {
         */
        int valid;
 
+       /*
+        * The snapshot overflowed because of a write to the snapshot device.
+        * We don't have to invalidate the snapshot in this case, but we need
+        * to prevent further writes.
+        */
+       int snapshot_overflowed;
+
        /* Origin writes don't trigger exceptions until this is set */
        int active;
 
@@ -1091,7 +1098,7 @@ static void stop_merge(struct dm_snapshot *s)
 }
 
 /*
- * Construct a snapshot mapping: <origin_dev> <COW-dev> <p/n> <chunk-size>
+ * Construct a snapshot mapping: <origin_dev> <COW-dev> <p|po|n> <chunk-size>
  */
 static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
@@ -1152,6 +1159,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        s->ti = ti;
        s->valid = 1;
+       s->snapshot_overflowed = 0;
        s->active = 0;
        atomic_set(&s->pending_exceptions_count, 0);
        s->exception_start_sequence = 0;
@@ -1294,6 +1302,7 @@ static void __handover_exceptions(struct dm_snapshot *snap_src,
 
        u.store_swap = snap_dest->store;
        snap_dest->store = snap_src->store;
+       snap_dest->store->userspace_supports_overflow = u.store_swap->userspace_supports_overflow;
        snap_src->store = u.store_swap;
 
        snap_dest->store->snap = snap_dest;
@@ -1301,6 +1310,7 @@ static void __handover_exceptions(struct dm_snapshot *snap_src,
 
        snap_dest->ti->max_io_len = snap_dest->store->chunk_size;
        snap_dest->valid = snap_src->valid;
+       snap_dest->snapshot_overflowed = snap_src->snapshot_overflowed;
 
        /*
         * Set source invalid to ensure it receives no further I/O.
@@ -1428,8 +1438,9 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err)
        dm_table_event(s->ti->table);
 }
 
-static void pending_complete(struct dm_snap_pending_exception *pe, int success)
+static void pending_complete(void *context, int success)
 {
+       struct dm_snap_pending_exception *pe = context;
        struct dm_exception *e;
        struct dm_snapshot *s = pe->snap;
        struct bio *origin_bios = NULL;
@@ -1478,7 +1489,6 @@ out:
        if (full_bio) {
                full_bio->bi_end_io = pe->full_bio_end_io;
                full_bio->bi_private = pe->full_bio_private;
-               atomic_inc(&full_bio->bi_remaining);
        }
        increment_pending_exceptions_done_count();
 
@@ -1491,7 +1501,7 @@ out:
                error_bios(snapshot_bios);
        } else {
                if (full_bio)
-                       bio_endio(full_bio, 0);
+                       bio_endio(full_bio);
                flush_bios(snapshot_bios);
        }
 
@@ -1500,24 +1510,13 @@ out:
        free_pending_exception(pe);
 }
 
-static void commit_callback(void *context, int success)
-{
-       struct dm_snap_pending_exception *pe = context;
-
-       pending_complete(pe, success);
-}
-
 static void complete_exception(struct dm_snap_pending_exception *pe)
 {
        struct dm_snapshot *s = pe->snap;
 
-       if (unlikely(pe->copy_error))
-               pending_complete(pe, 0);
-
-       else
-               /* Update the metadata if we are persistent */
-               s->store->type->commit_exception(s->store, &pe->e,
-                                                commit_callback, pe);
+       /* Update the metadata if we are persistent */
+       s->store->type->commit_exception(s->store, &pe->e, !pe->copy_error,
+                                        pending_complete, pe);
 }
 
 /*
@@ -1581,11 +1580,11 @@ static void start_copy(struct dm_snap_pending_exception *pe)
        dm_kcopyd_copy(s->kcopyd_client, &src, 1, &dest, 0, copy_callback, pe);
 }
 
-static void full_bio_end_io(struct bio *bio, int error)
+static void full_bio_end_io(struct bio *bio)
 {
        void *callback_data = bio->bi_private;
 
-       dm_kcopyd_do_callback(callback_data, 0, error ? 1 : 0);
+       dm_kcopyd_do_callback(callback_data, 0, bio->bi_error ? 1 : 0);
 }
 
 static void start_full_bio(struct dm_snap_pending_exception *pe,
@@ -1692,7 +1691,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
         * to copy an exception */
        down_write(&s->lock);
 
-       if (!s->valid) {
+       if (!s->valid || (unlikely(s->snapshot_overflowed) && bio_rw(bio) == WRITE)) {
                r = -EIO;
                goto out_unlock;
        }
@@ -1716,7 +1715,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
                        pe = alloc_pending_exception(s);
                        down_write(&s->lock);
 
-                       if (!s->valid) {
+                       if (!s->valid || s->snapshot_overflowed) {
                                free_pending_exception(pe);
                                r = -EIO;
                                goto out_unlock;
@@ -1731,7 +1730,11 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
 
                        pe = __find_pending_exception(s, pe, chunk);
                        if (!pe) {
-                               __invalidate_snapshot(s, -ENOMEM);
+                               if (s->store->userspace_supports_overflow) {
+                                       s->snapshot_overflowed = 1;
+                                       DMERR("Snapshot overflowed: Unable to allocate exception.");
+                               } else
+                                       __invalidate_snapshot(s, -ENOMEM);
                                r = -EIO;
                                goto out_unlock;
                        }
@@ -1991,6 +1994,8 @@ static void snapshot_status(struct dm_target *ti, status_type_t type,
                        DMEMIT("Invalid");
                else if (snap->merge_failed)
                        DMEMIT("Merge failed");
+               else if (snap->snapshot_overflowed)
+                       DMEMIT("Overflow");
                else {
                        if (snap->store->type->usage) {
                                sector_t total_sectors, sectors_allocated,
@@ -2331,20 +2336,6 @@ static void origin_status(struct dm_target *ti, status_type_t type,
        }
 }
 
-static int origin_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
-                       struct bio_vec *biovec, int max_size)
-{
-       struct dm_origin *o = ti->private;
-       struct request_queue *q = bdev_get_queue(o->dev->bdev);
-
-       if (!q->merge_bvec_fn)
-               return max_size;
-
-       bvm->bi_bdev = o->dev->bdev;
-
-       return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
-}
-
 static int origin_iterate_devices(struct dm_target *ti,
                                  iterate_devices_callout_fn fn, void *data)
 {
@@ -2363,13 +2354,12 @@ static struct target_type origin_target = {
        .resume  = origin_resume,
        .postsuspend = origin_postsuspend,
        .status  = origin_status,
-       .merge   = origin_merge,
        .iterate_devices = origin_iterate_devices,
 };
 
 static struct target_type snapshot_target = {
        .name    = "snapshot",
-       .version = {1, 13, 0},
+       .version = {1, 15, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,
@@ -2383,7 +2373,7 @@ static struct target_type snapshot_target = {
 
 static struct target_type merge_target = {
        .name    = dm_snapshot_merge_target_name,
-       .version = {1, 3, 0},
+       .version = {1, 4, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,