diff --git a/Admin/bin/lc-detach b/Admin/bin/lc-detach
index 9247a8e..1d2b372 100644
--- a/Admin/bin/lc-detach
+++ b/Admin/bin/lc-detach
@@ -2,6 +2,7 @@
 
 import os
 import sys
+import time
 from argparse import ArgumentParser
 
 import lc_admin.dirnode as dirnode
@@ -29,13 +30,13 @@ interrupted = False
 
 while True:
 	try:
-		nr = device.nr_dirty_caches()
-		while nr:
+		nr = lambda : device.nr_dirty_caches()
+		while nr():
 			if interrupted:
 				device.unlock()
 				sys.exit()
 
-			print("could not detach the device. %d caches are still dirty remained." % (nr))
+			print("could not detach the device. %d caches are still dirty remained." % (nr()))
 			time.sleep(1)
 
 		print("no dirty cache remained in the device")	
diff --git a/Driver/dm-lc.c b/Driver/dm-lc.c
index 396c49b..53ca8cd 100644
--- a/Driver/dm-lc.c
+++ b/Driver/dm-lc.c
@@ -1295,7 +1295,7 @@ static void migrate_proc(struct work_struct *work)
 		/*
 		 * (Locking)
 		 * Only line of code changes
-		 * last_migrate_segment_id in runtime.
+		 * last_migrate_segment_id during runtime.
 		 */
 		cache->last_migrated_segment_id += nr_mig;
 
@@ -1639,7 +1639,9 @@ static size_t calc_nr_segments(struct dm_dev *dev)
 	sector_t devsize = dm_devsize(dev);
 
 	/*
-	 * Disk format:
+	 * Disk format
+	 *
+	 * Overall:
 	 * superblock(1MB) [segment(1MB)]+
 	 * We reserve the first segment (1MB) as the superblock.
 	 *
@@ -1946,6 +1948,21 @@ static int lc_map(struct dm_target *ti, struct bio *bio)
 	k = ht_hash(cache, &key);
 	head = arr_at(cache->htable, k);
 
+	/*
+	 * (Locking)
+	 * Why mutex?
+	 *
+	 * The reason we use mutex instead of rw_semaphore
+	 * that can allow truely concurrent read access
+	 * is that mutex is even lighter than rw_semaphore.
+	 * Since dm-lc is a real performance centric software
+	 * the overhead of rw_semaphore is crucial.
+	 * All in all,
+	 * since exclusive region in read path is enough small
+	 * and cheap, using rw_semaphore and let the reads
+	 * execute concurrently won't improve the performance
+	 * as much as one expects.
+	 */
 	mutex_lock(&cache->io_lock);
 	mb = ht_lookup(cache, head, &key);
 	if (mb) {
@@ -1979,7 +1996,20 @@ static int lc_map(struct dm_target *ti, struct bio *bio)
 				migrate_buffered_mb(cache, mb, dirty_bits);
 
 			/*
-			 * Dirtiness of a live cache:
+			 * Cache class
+			 * Live and Stable
+			 *
+			 * Live:
+			 * The cache is on the RAM buffer.
+			 *
+			 * Stable:
+			 * The cache is not on the RAM buffer
+			 * but at least queued in flush_queue.
+			 */
+
+			/*
+			 * (Locking)
+			 * Dirtiness of a live cache
 			 *
 			 * We can assume dirtiness of a cache only increase
 			 * when it is on the buffer, we call this cache is live.
@@ -2003,7 +2033,8 @@ static int lc_map(struct dm_target *ti, struct bio *bio)
 		} else {
 
 			/*
-			 * Dirtiness of a stable cache:
+			 * (Locking)
+			 * Dirtiness of a stable cache
 			 *
 			 * Unlike the live caches that don't
 			 * fluctuate the dirtiness,
@@ -2305,13 +2336,43 @@ static struct kobj_type device_ktype = {
 	.release = device_release,
 };
 
+static int parse_cache_id(char *s, u8 *cache_id)
+{
+	unsigned id;
+	if (sscanf(s, "%u", &id) != 1) {
+		LCERR();
+		return -EINVAL;
+	}
+	if (id >= LC_NR_SLOTS) {
+		LCERR();
+		return -EINVAL;
+	}
+	*cache_id = id;
+	return 0;
+}
+
 /*
  * <device-id> <path> <cache-id>
+ *
+ * By replacing it with cache_id_ptr
+ * cache-id can be removed from this constructor
+ * that will result in code dedup
+ * in this constructor and switch_to message.
+ *
+ * The reason why this constructor takes cache-id
+ * is to cooperate with the output of `dmsetup table`,
+ * that is, dmsetup table | dmsetup load should clone
+ * the logical device.
+ * This is an implicit rule in device-mapper
+ * and dm-lc follows it.
+ * Other non-essential tunable parameters
+ * will not be cloned because that is too much.
  */
 static int lc_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
 	struct lc_device *lc;
-	unsigned device_id, cache_id;
+	unsigned device_id;
+	u8 cache_id;
 	struct dm_dev *dev;
 
 	int r = dm_set_target_max_io_len(ti, (1 << 3));
@@ -2339,9 +2400,15 @@ static int lc_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 		r = -EINVAL;
 		goto bad_device_id;
 	}
+	if (device_id >= LC_NR_SLOTS) {
+		LCERR();
+		r = -EINVAL;
+		goto bad_device_id;
+	}
 	lc->id = device_id;
 
-	if (dm_get_device(ti, argv[1], dm_table_get_mode(ti->table), &dev)) {
+	if (dm_get_device(ti, argv[1], dm_table_get_mode(ti->table),
+			  &dev)) {
 		LCERR();
 		r = -EINVAL;
 		goto bad_get_device;
@@ -2349,16 +2416,16 @@ static int lc_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 	lc->device = dev;
 
 	lc->cache = NULL;
-	if (sscanf(argv[2], "%u", &cache_id) != 1) {
+	cache_id = 0;
+	r = parse_cache_id(argv[2], &cache_id);
+	if (r) {
 		LCERR();
-		r = -EINVAL;
 		goto bad_cache_id;
 	}
 	if (cache_id) {
 		struct lc_cache *cache = lc_caches[cache_id];
 		if (!cache) {
-			LCERR("cache is not set for id(%u)",
-			      cache_id);
+			LCERR("cache is not set for id(%u)", cache_id);
 			goto bad_no_cache;
 		}
 		lc->cache = lc_caches[cache_id];
@@ -2381,7 +2448,6 @@ static int lc_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 	 */
 
 	/*
-	 * Note:
 	 * Reference to the mapped_device
 	 * is used to show device name (major:minor).
 	 * major:minor is used in admin scripts
@@ -2420,8 +2486,7 @@ static int lc_message(struct dm_target *ti, unsigned argc, char **argv)
 	char *cmd = argv[0];
 
 	/*
-	 * We must separate
-	 * these add/remove sysfs code from .ctr
+	 * We must separate these add/remove sysfs code from .ctr
 	 * for a very complex reason.
 	 */
 	if (!strcasecmp(cmd, "add_sysfs")) {
@@ -2941,12 +3006,12 @@ static int lc_mgr_message(struct dm_target *ti, unsigned int argc, char **argv)
 	 * cache device to operate.
 	 */
 	if (!strcasecmp(cmd, "switch_to")) {
-		unsigned id;
-		if (sscanf(argv[1], "%u", &id) != 1) {
+		u8 id;
+		int r = parse_cache_id(argv[1], &id);
+		if (r) {
 			LCERR();
-			return -EINVAL;
+			return r;
 		}
-
 		cache_id_ptr = id;
 		return 0;
 	}
