|
|
@@ -19,6 +19,7 @@
|
|
|
#include <linux/vmalloc.h>
|
|
|
#include <linux/log2.h>
|
|
|
#include <linux/dm-kcopyd.h>
|
|
|
+#include <linux/semaphore.h>
|
|
|
|
|
|
#include "dm.h"
|
|
|
|
|
|
@@ -105,6 +106,9 @@ struct dm_snapshot {
|
|
|
/* The on disk metadata handler */
|
|
|
struct dm_exception_store *store;
|
|
|
|
|
|
+ /* Maximum number of in-flight COW jobs. */
|
|
|
+ struct semaphore cow_count;
|
|
|
+
|
|
|
struct dm_kcopyd_client *kcopyd_client;
|
|
|
|
|
|
/* Wait for events based on state_bits */
|
|
|
@@ -145,6 +149,19 @@ struct dm_snapshot {
|
|
|
#define RUNNING_MERGE 0
|
|
|
#define SHUTDOWN_MERGE 1
|
|
|
|
|
|
+/*
|
|
|
+ * Maximum number of chunks being copied on write.
|
|
|
+ *
|
|
|
+ * The value was decided experimentally as a trade-off between memory
|
|
|
+ * consumption, stalling the kernel's workqueues and maintaining a high enough
|
|
|
+ * throughput.
|
|
|
+ */
|
|
|
+#define DEFAULT_COW_THRESHOLD 2048
|
|
|
+
|
|
|
+static int cow_threshold = DEFAULT_COW_THRESHOLD;
|
|
|
+module_param_named(snapshot_cow_threshold, cow_threshold, int, 0644);
|
|
|
+MODULE_PARM_DESC(snapshot_cow_threshold, "Maximum number of chunks being copied on write");
|
|
|
+
|
|
|
DECLARE_DM_KCOPYD_THROTTLE_WITH_MODULE_PARM(snapshot_copy_throttle,
|
|
|
"A percentage of time allocated for copy on write");
|
|
|
|
|
|
@@ -1190,6 +1207,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
|
|
goto bad_hash_tables;
|
|
|
}
|
|
|
|
|
|
+ sema_init(&s->cow_count, (cow_threshold > 0) ? cow_threshold : INT_MAX);
|
|
|
+
|
|
|
s->kcopyd_client = dm_kcopyd_client_create(&dm_kcopyd_throttle);
|
|
|
if (IS_ERR(s->kcopyd_client)) {
|
|
|
r = PTR_ERR(s->kcopyd_client);
|
|
|
@@ -1575,6 +1594,7 @@ static void copy_callback(int read_err, unsigned long write_err, void *context)
|
|
|
rb_link_node(&pe->out_of_order_node, parent, p);
|
|
|
rb_insert_color(&pe->out_of_order_node, &s->out_of_order_tree);
|
|
|
}
|
|
|
+ up(&s->cow_count);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
@@ -1598,6 +1618,7 @@ static void start_copy(struct dm_snap_pending_exception *pe)
|
|
|
dest.count = src.count;
|
|
|
|
|
|
/* Hand over to kcopyd */
|
|
|
+ down(&s->cow_count);
|
|
|
dm_kcopyd_copy(s->kcopyd_client, &src, 1, &dest, 0, copy_callback, pe);
|
|
|
}
|
|
|
|
|
|
@@ -1617,6 +1638,7 @@ static void start_full_bio(struct dm_snap_pending_exception *pe,
|
|
|
pe->full_bio = bio;
|
|
|
pe->full_bio_end_io = bio->bi_end_io;
|
|
|
|
|
|
+ down(&s->cow_count);
|
|
|
callback_data = dm_kcopyd_prepare_callback(s->kcopyd_client,
|
|
|
copy_callback, pe);
|
|
|
|