From: Milan Broz Release memory if snapshot is invalidated. All I/O operations on the full (invalidated) snapshot will cause -EIO so no memory is needed anymore. If there are no kcopyd jobs running, memory is released immediately. Otherwise it gets freed later in the workqueue. Signed-off-by: Milan Broz --- [Still problems with this] drivers/md/dm-snap.c | 28 +++++++++++++++++++++++----- 1 files changed, 23 insertions(+), 5 deletions(-) Index: linux-2.6.19/drivers/md/dm-snap.c =================================================================== --- linux-2.6.19.orig/drivers/md/dm-snap.c 2006-12-06 20:49:41.000000000 +0000 +++ linux-2.6.19/drivers/md/dm-snap.c 2006-12-06 20:49:41.000000000 +0000 @@ -564,9 +564,17 @@ static int snapshot_ctr(struct dm_target return r; } -static void __free_exceptions(struct dm_snapshot *s) +/* + * If async is set, return immediately. + */ +static void __free_exceptions(struct dm_snapshot *s, unsigned async) { - kcopyd_client_destroy(s->kcopyd_client, 0); + async = kcopyd_client_destroy(s->kcopyd_client, async); + if (async) { + queue_work(ksnapd, &s->queued_bios_work); + return; + } + s->kcopyd_client = NULL; exit_exception_table(&s->pending, pending_cache); @@ -585,7 +593,8 @@ static void snapshot_dtr(struct dm_targe /* After this returns there can be no new kcopyd jobs. */ unregister_snapshot(s); - __free_exceptions(s); + if (s->valid) + __free_exceptions(s, 1); dm_put_device(ti, s->origin); dm_put_device(ti, s->cow); @@ -611,14 +620,20 @@ static void flush_bios(struct bio *bio) static void flush_queued_bios(void *data) { struct dm_snapshot *s = (struct dm_snapshot *) data; - struct bio *queued_bios; - unsigned long flags; +// struct bio *queued_bios; +// unsigned long flags; + if (!s->valid && s->kcopyd_client) { + __free_exceptions(s, 0); + return; + } +/* spin_lock_irqsave(&s->pe_lock, flags); queued_bios = bio_list_get(&s->queued_bios); spin_unlock_irqrestore(&s->pe_lock, flags); flush_bios(queued_bios); +*/ } /* @@ -651,6 +666,9 @@ static void __invalidate_snapshot(struct s->valid = 0; + /* schedule release memory */ + __free_exceptions(s, 1); + dm_table_event(s->table); }