[dm-devel] [PATCH 08/14] dm-multisnap-mikulas-delete
Mike Snitzer
snitzer at redhat.com
Tue Mar 2 00:23:52 UTC 2010
From: Mikulas Patocka <mpatocka at redhat.com>
Background delete operation.
Scan the b+tree on background and find entries that have unused snapshot IDs.
Delete these entries and the associated chunks.
Signed-off-by: Mikulas Patocka <mpatocka at redhat.com>
---
drivers/md/dm-multisnap-delete.c | 137 ++++++++++++++++++++++++++++++++++++++
1 files changed, 137 insertions(+), 0 deletions(-)
create mode 100644 drivers/md/dm-multisnap-delete.c
diff --git a/drivers/md/dm-multisnap-delete.c b/drivers/md/dm-multisnap-delete.c
new file mode 100644
index 0000000..22705a3
--- /dev/null
+++ b/drivers/md/dm-multisnap-delete.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2009 Red Hat Czech, s.r.o.
+ *
+ * Mikulas Patocka <mpatocka at redhat.com>
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm-multisnap-mikulas.h"
+
+/*
+ * Commit after this number of deleted entries.
+ * Too big number causes spurious overflows on nearly-full device.
+ * Too small number degrades delete performance.
+ */
+#define COMMIT_AFTER 128
+
+struct list_cookie {
+ struct bt_key key;
+ chunk_t new_chunk;
+};
+
+#define RET_END 1
+#define RET_DO_FREE 2
+#define RET_RESCHEDULE 3
+
+static int list_callback(struct dm_exception_store *s,
+ struct dm_multisnap_bt_node *node,
+ struct dm_multisnap_bt_entry *bt, void *cookie)
+{
+ struct list_cookie *lc = cookie;
+ mikulas_snapid_t found_from, found_to;
+
+ lc->key.chunk = read_48(bt, orig_chunk);
+ lc->key.snap_from = mikulas_snapid_to_cpu(bt->snap_from);
+ lc->key.snap_to = mikulas_snapid_to_cpu(bt->snap_to);
+
+ if (unlikely(lc->key.chunk > DM_CHUNK_T_MAX))
+ return RET_END;
+
+ s->delete_rover_chunk = lc->key.chunk;
+ s->delete_rover_snapid = lc->key.snap_to + 1;
+ if (unlikely(!s->delete_rover_snapid))
+ s->delete_rover_chunk++;
+
+ if (!dm_multisnap_find_next_snapid_range(s, lc->key.snap_from,
+ &found_from, &found_to) ||
+ found_from > lc->key.snap_to) {
+ /*
+ * This range maps unused snapshots, delete it.
+ * But we can't do it now, so submit it to the caller;
+ */
+ lc->new_chunk = read_48(bt, new_chunk);
+ return RET_DO_FREE;
+ }
+
+ /*
+ * If we are at a last entry in the btree node, drop the lock and
+ * allow other requests to be processed.
+ *
+ * This avoids a starvation when there are no nodes to delete.
+ */
+ if (bt == &node->entries[le32_to_cpu(node->n_entries) - 1])
+ return RET_RESCHEDULE;
+
+ return 0;
+}
+
+static void delete_step(struct dm_exception_store *s)
+{
+ struct bt_key key;
+ int r;
+ struct list_cookie lc;
+
+ key.chunk = s->delete_rover_chunk;
+ key.snap_from = s->delete_rover_snapid;
+ key.snap_to = s->delete_rover_snapid;
+
+ r = dm_multisnap_list_btree(s, &key, list_callback, &lc);
+
+ if (unlikely(r < 0))
+ return;
+
+ switch (r) {
+
+ case RET_END:
+ s->flags &= ~DM_MULTISNAP_FLAG_DELETING;
+
+ /* If we finished the job and there is no pending I/O, commit */
+ if (dm_multisnap_can_commit(s->dm))
+ dm_multisnap_call_commit(s->dm);
+
+ return;
+ case RET_DO_FREE:
+ if (unlikely(dm_multisnap_has_error(s->dm)))
+ return;
+
+ dm_multisnap_delete_from_btree(s, &lc.key);
+
+ dm_multisnap_transition_mark(s);
+
+ dm_multisnap_free_block(s, lc.new_chunk, FREELIST_DATA_FLAG);
+
+ /* fall through */
+ case RET_RESCHEDULE:
+ if (dm_multisnap_can_commit(s->dm)) {
+ if (++s->delete_commit_count >= COMMIT_AFTER) {
+ s->delete_commit_count = 0;
+ dm_multisnap_call_commit(s->dm);
+ }
+ }
+ return;
+ default:
+ printk(KERN_CRIT "delete_step: invalid return value %d", r);
+ BUG();
+
+ }
+}
+
+void dm_multisnap_background_delete(struct dm_exception_store *s,
+ struct dm_multisnap_background_work *bw)
+{
+ if (unlikely(dm_multisnap_has_error(s->dm)))
+ return;
+
+ if (s->flags & DM_MULTISNAP_FLAG_DELETING) {
+ delete_step(s);
+ } else if (s->flags & DM_MULTISNAP_FLAG_PENDING_DELETE) {
+ s->flags &= ~DM_MULTISNAP_FLAG_PENDING_DELETE;
+ s->flags |= DM_MULTISNAP_FLAG_DELETING;
+ s->delete_rover_chunk = 0;
+ s->delete_rover_snapid = 0;
+ } else
+ return;
+
+ dm_multisnap_queue_work(s->dm, &s->delete_work);
+}
--
1.6.5.2
More information about the dm-devel
mailing list