These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / md / dm-snap-persistent.c
index 808b841..4d39093 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "dm-exception-store.h"
 
+#include <linux/ctype.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/vmalloc.h>
@@ -321,7 +322,7 @@ static int read_header(struct pstore *ps, int *new_snapshot)
                    bdev_logical_block_size(dm_snap_cow(ps->store->snap)->
                                            bdev) >> 9);
                ps->store->chunk_mask = ps->store->chunk_size - 1;
-               ps->store->chunk_shift = ffs(ps->store->chunk_size) - 1;
+               ps->store->chunk_shift = __ffs(ps->store->chunk_size);
                chunk_size_supplied = 0;
        }
 
@@ -533,7 +534,7 @@ static int read_exceptions(struct pstore *ps,
                chunk = area_location(ps, ps->current_area);
 
                area = dm_bufio_read(client, chunk, &bp);
-               if (unlikely(IS_ERR(area))) {
+               if (IS_ERR(area)) {
                        r = PTR_ERR(area);
                        goto ret_destroy_bufio;
                }
@@ -694,7 +695,7 @@ static int persistent_prepare_exception(struct dm_exception_store *store,
 }
 
 static void persistent_commit_exception(struct dm_exception_store *store,
-                                       struct dm_exception *e,
+                                       struct dm_exception *e, int valid,
                                        void (*callback) (void *, int success),
                                        void *callback_context)
 {
@@ -703,6 +704,9 @@ static void persistent_commit_exception(struct dm_exception_store *store,
        struct core_exception ce;
        struct commit_callback *cb;
 
+       if (!valid)
+               ps->valid = 0;
+
        ce.old_chunk = e->old_chunk;
        ce.new_chunk = e->new_chunk;
        write_exception(ps, ps->current_committed++, &ce);
@@ -843,10 +847,10 @@ static void persistent_drop_snapshot(struct dm_exception_store *store)
                DMWARN("write header failed");
 }
 
-static int persistent_ctr(struct dm_exception_store *store,
-                         unsigned argc, char **argv)
+static int persistent_ctr(struct dm_exception_store *store, char *options)
 {
        struct pstore *ps;
+       int r;
 
        /* allocate the pstore */
        ps = kzalloc(sizeof(*ps), GFP_KERNEL);
@@ -868,14 +872,32 @@ static int persistent_ctr(struct dm_exception_store *store,
 
        ps->metadata_wq = alloc_workqueue("ksnaphd", WQ_MEM_RECLAIM, 0);
        if (!ps->metadata_wq) {
-               kfree(ps);
                DMERR("couldn't start header metadata update thread");
-               return -ENOMEM;
+               r = -ENOMEM;
+               goto err_workqueue;
+       }
+
+       if (options) {
+               char overflow = toupper(options[0]);
+               if (overflow == 'O')
+                       store->userspace_supports_overflow = true;
+               else {
+                       DMERR("Unsupported persistent store option: %s", options);
+                       r = -EINVAL;
+                       goto err_options;
+               }
        }
 
        store->context = ps;
 
        return 0;
+
+err_options:
+       destroy_workqueue(ps->metadata_wq);
+err_workqueue:
+       kfree(ps);
+
+       return r;
 }
 
 static unsigned persistent_status(struct dm_exception_store *store,
@@ -888,7 +910,8 @@ static unsigned persistent_status(struct dm_exception_store *store,
        case STATUSTYPE_INFO:
                break;
        case STATUSTYPE_TABLE:
-               DMEMIT(" P %llu", (unsigned long long)store->chunk_size);
+               DMEMIT(" %s %llu", store->userspace_supports_overflow ? "PO" : "P",
+                      (unsigned long long)store->chunk_size);
        }
 
        return sz;