Optimize locking. First, lock the exception store locally and only if the exception is not found, ugrade to local+remote lock. Signed-off-by: Mikulas Patocka --- drivers/md/dm-snap.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) Index: linux-2.6.31-fast/drivers/md/dm-snap.c =================================================================== --- linux-2.6.31-fast.orig/drivers/md/dm-snap.c 2009-10-19 12:53:25.000000000 +0200 +++ linux-2.6.31-fast/drivers/md/dm-snap.c 2009-10-19 12:53:38.000000000 +0200 @@ -345,10 +345,12 @@ static void __insert_origin(struct origi #define LOCK_DEPTH 0xff #define LOCK_LOCAL_ONLY 0x100 +#define LOCK_REMOTE_ONLY 0x200 static void lock_snapshot(struct dm_snapshot *s, int flags) { - down_write_nested(&s->lock, flags & LOCK_DEPTH); + if (likely(!(flags & LOCK_REMOTE_ONLY))) + down_write_nested(&s->lock, flags & LOCK_DEPTH); #ifdef CLUSTER_SNAPSHOTS if (is_clustered(s) && !s->pending_exceptions_submitted && !(flags & LOCK_LOCAL_ONLY)) { @@ -375,7 +377,8 @@ static void unlock_snapshot(struct dm_sn BUG_ON(r < 0); } #endif - up_write(&s->lock); + if (likely(!(flags & LOCK_REMOTE_ONLY))) + up_write(&s->lock); } static struct dm_snapshot *__find_merging_snapshot(struct block_device *origin) @@ -1514,6 +1517,7 @@ static int snapshot_map(struct dm_target int r = DM_MAPIO_REMAPPED; chunk_t chunk; struct dm_snap_pending_exception *pe = NULL; + int lockflags; if (unlikely(bio_empty_barrier(bio))) { bio->bi_bdev = s->cow->bdev; @@ -1529,7 +1533,8 @@ static int snapshot_map(struct dm_target /* FIXME: should only take write lock if we need * to copy an exception */ - lock_snapshot(s, 0); + lockflags = LOCK_LOCAL_ONLY; + lock_snapshot(s, lockflags); if (!s->valid) { r = -EIO; @@ -1543,6 +1548,13 @@ static int snapshot_map(struct dm_target goto out_unlock; } + lockflags = 0; + lock_snapshot(s, LOCK_REMOTE_ONLY); /* upgrade to local+remote lock */ + /* + * New exceptions may have been added in lock_snapshot, but they will be + * rechecked after alloc_pending_exception. + */ + /* * Write to snapshot - higher level takes care of RW/RO * flags so we should only get this if we are @@ -1551,9 +1563,9 @@ static int snapshot_map(struct dm_target if (bio_rw(bio) == WRITE) { pe = __lookup_pending_exception(s, chunk); if (!pe) { - unlock_snapshot(s, 0); + unlock_snapshot(s, lockflags); pe = alloc_pending_exception(s); - lock_snapshot(s, 0); + lock_snapshot(s, lockflags); if (!s->valid) { free_pending_exception(pe); @@ -1584,7 +1596,7 @@ static int snapshot_map(struct dm_target if (!pe->started) { /* this is protected by snap->lock */ pe->started = 1; - unlock_snapshot(s, 0); + unlock_snapshot(s, lockflags); start_copy(pe); goto out; } @@ -1594,7 +1606,7 @@ static int snapshot_map(struct dm_target } out_unlock: - unlock_snapshot(s, 0); + unlock_snapshot(s, lockflags); out: return r; } @@ -1789,13 +1801,15 @@ static int __origin_write(struct list_he /* Do all the snapshots on this origin */ list_for_each_entry (snap, snapshots, list) { + int lockflags; /* If the snapshot is merging, don't make new exceptions in it - but in this case no one should be writing to the origin */ if (is_merge(snap->ti)) continue; - lock_snapshot(snap, 0); + lockflags = LOCK_LOCAL_ONLY; + lock_snapshot(snap, lockflags); /* Only deal with valid and active snapshots */ if (!snap->valid || !snap->active) @@ -1820,11 +1834,14 @@ static int __origin_write(struct list_he if (e) goto next_snapshot; + lockflags = 0; /* upgrade to local+remote lock */ + lock_snapshot(snap, LOCK_REMOTE_ONLY); + pe = __lookup_pending_exception(snap, chunk); if (!pe) { - unlock_snapshot(snap, 0); + unlock_snapshot(snap, lockflags); pe = alloc_pending_exception(snap); - lock_snapshot(snap, 0); + lock_snapshot(snap, lockflags); if (!snap->valid) { free_pending_exception(pe); @@ -1862,7 +1879,7 @@ static int __origin_write(struct list_he } next_snapshot: - unlock_snapshot(snap, 0); + unlock_snapshot(snap, lockflags); } /*