diff options
| author | Milan Broz <mbroz@redhat.com> | 2007-07-12 17:28:00 +0100 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-12 15:01:08 -0700 | 
| commit | fcac03abd325e4f7a4cc8fe05fea2793b1c8eb75 (patch) | |
| tree | 79965ed6b2b03468e629a63fca1c14f795091436 /drivers/md | |
| parent | 596f138eede0c113aa655937c8be85fc15ccd61c (diff) | |
| download | olio-linux-3.10-fcac03abd325e4f7a4cc8fe05fea2793b1c8eb75.tar.xz olio-linux-3.10-fcac03abd325e4f7a4cc8fe05fea2793b1c8eb75.zip  | |
dm snapshot: fix invalidation deadlock
Process persistent exception store metadata IOs in a separate thread.
A snapshot may become invalid while inside generic_make_request().
A synchronous write is then needed to update the metadata while still
inside that function.  Since the introduction of
md-dm-reduce-stack-usage-with-stacked-block-devices.patch this has to
be performed by a separate thread to avoid deadlock.
Signed-off-by: Milan Broz <mbroz@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/md')
| -rw-r--r-- | drivers/md/dm-exception-store.c | 48 | 
1 files changed, 43 insertions, 5 deletions
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index cb05b744dea..8c25c2ff724 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c @@ -125,6 +125,8 @@ struct pstore {  	uint32_t callback_count;  	struct commit_callback *callbacks;  	struct dm_io_client *io_client; + +	struct workqueue_struct *metadata_wq;  };  static unsigned sectors_to_pages(unsigned sectors) @@ -156,10 +158,24 @@ static void free_area(struct pstore *ps)  	ps->area = NULL;  } +struct mdata_req { +	struct io_region *where; +	struct dm_io_request *io_req; +	struct work_struct work; +	int result; +}; + +static void do_metadata(struct work_struct *work) +{ +	struct mdata_req *req = container_of(work, struct mdata_req, work); + +	req->result = dm_io(req->io_req, 1, req->where, NULL); +} +  /*   * Read or write a chunk aligned and sized block of data from a device.   */ -static int chunk_io(struct pstore *ps, uint32_t chunk, int rw) +static int chunk_io(struct pstore *ps, uint32_t chunk, int rw, int metadata)  {  	struct io_region where = {  		.bdev = ps->snap->cow->bdev, @@ -173,8 +189,23 @@ static int chunk_io(struct pstore *ps, uint32_t chunk, int rw)  		.client = ps->io_client,  		.notify.fn = NULL,  	}; +	struct mdata_req req; + +	if (!metadata) +		return dm_io(&io_req, 1, &where, NULL); -	return dm_io(&io_req, 1, &where, NULL); +	req.where = &where; +	req.io_req = &io_req; + +	/* +	 * Issue the synchronous I/O from a different thread +	 * to avoid generic_make_request recursion. +	 */ +	INIT_WORK(&req.work, do_metadata); +	queue_work(ps->metadata_wq, &req.work); +	flush_workqueue(ps->metadata_wq); + +	return req.result;  }  /* @@ -189,7 +220,7 @@ static int area_io(struct pstore *ps, uint32_t area, int rw)  	/* convert a metadata area index to a chunk index */  	chunk = 1 + ((ps->exceptions_per_area + 1) * area); -	r = chunk_io(ps, chunk, rw); +	r = chunk_io(ps, chunk, rw, 0);  	if (r)  		return r; @@ -230,7 +261,7 @@ static int read_header(struct pstore *ps, int *new_snapshot)  	if (r)  		return r; -	r = chunk_io(ps, 0, READ); +	r = chunk_io(ps, 0, READ, 1);  	if (r)  		goto bad; @@ -292,7 +323,7 @@ static int write_header(struct pstore *ps)  	dh->version = cpu_to_le32(ps->version);  	dh->chunk_size = cpu_to_le32(ps->snap->chunk_size); -	return chunk_io(ps, 0, WRITE); +	return chunk_io(ps, 0, WRITE, 1);  }  /* @@ -409,6 +440,7 @@ static void persistent_destroy(struct exception_store *store)  {  	struct pstore *ps = get_info(store); +	destroy_workqueue(ps->metadata_wq);  	dm_io_client_destroy(ps->io_client);  	vfree(ps->callbacks);  	free_area(ps); @@ -588,6 +620,12 @@ int dm_create_persistent(struct exception_store *store)  	atomic_set(&ps->pending_count, 0);  	ps->callbacks = NULL; +	ps->metadata_wq = create_singlethread_workqueue("ksnaphd"); +	if (!ps->metadata_wq) { +		DMERR("couldn't start header metadata update thread"); +		return -ENOMEM; +	} +  	store->destroy = persistent_destroy;  	store->read_metadata = persistent_read_metadata;  	store->prepare_exception = persistent_prepare;  |