diff options
Diffstat (limited to 'drivers/md/dm-snap.c')
-rw-r--r-- | drivers/md/dm-snap.c | 93 |
1 files changed, 84 insertions, 9 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 8b204ae216ab..c2bf822bad6f 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/log2.h> | 20 | #include <linux/log2.h> |
21 | #include <linux/dm-kcopyd.h> | 21 | #include <linux/dm-kcopyd.h> |
22 | 22 | ||
23 | #include "dm.h" | ||
24 | |||
23 | #include "dm-exception-store.h" | 25 | #include "dm-exception-store.h" |
24 | 26 | ||
25 | #define DM_MSG_PREFIX "snapshots" | 27 | #define DM_MSG_PREFIX "snapshots" |
@@ -291,12 +293,23 @@ struct origin { | |||
291 | }; | 293 | }; |
292 | 294 | ||
293 | /* | 295 | /* |
296 | * This structure is allocated for each origin target | ||
297 | */ | ||
298 | struct dm_origin { | ||
299 | struct dm_dev *dev; | ||
300 | struct dm_target *ti; | ||
301 | unsigned split_boundary; | ||
302 | struct list_head hash_list; | ||
303 | }; | ||
304 | |||
305 | /* | ||
294 | * Size of the hash table for origin volumes. If we make this | 306 | * Size of the hash table for origin volumes. If we make this |
295 | * the size of the minors list then it should be nearly perfect | 307 | * the size of the minors list then it should be nearly perfect |
296 | */ | 308 | */ |
297 | #define ORIGIN_HASH_SIZE 256 | 309 | #define ORIGIN_HASH_SIZE 256 |
298 | #define ORIGIN_MASK 0xFF | 310 | #define ORIGIN_MASK 0xFF |
299 | static struct list_head *_origins; | 311 | static struct list_head *_origins; |
312 | static struct list_head *_dm_origins; | ||
300 | static struct rw_semaphore _origins_lock; | 313 | static struct rw_semaphore _origins_lock; |
301 | 314 | ||
302 | static DECLARE_WAIT_QUEUE_HEAD(_pending_exceptions_done); | 315 | static DECLARE_WAIT_QUEUE_HEAD(_pending_exceptions_done); |
@@ -310,12 +323,22 @@ static int init_origin_hash(void) | |||
310 | _origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head), | 323 | _origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head), |
311 | GFP_KERNEL); | 324 | GFP_KERNEL); |
312 | if (!_origins) { | 325 | if (!_origins) { |
313 | DMERR("unable to allocate memory"); | 326 | DMERR("unable to allocate memory for _origins"); |
314 | return -ENOMEM; | 327 | return -ENOMEM; |
315 | } | 328 | } |
316 | |||
317 | for (i = 0; i < ORIGIN_HASH_SIZE; i++) | 329 | for (i = 0; i < ORIGIN_HASH_SIZE; i++) |
318 | INIT_LIST_HEAD(_origins + i); | 330 | INIT_LIST_HEAD(_origins + i); |
331 | |||
332 | _dm_origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head), | ||
333 | GFP_KERNEL); | ||
334 | if (!_dm_origins) { | ||
335 | DMERR("unable to allocate memory for _dm_origins"); | ||
336 | kfree(_origins); | ||
337 | return -ENOMEM; | ||
338 | } | ||
339 | for (i = 0; i < ORIGIN_HASH_SIZE; i++) | ||
340 | INIT_LIST_HEAD(_dm_origins + i); | ||
341 | |||
319 | init_rwsem(&_origins_lock); | 342 | init_rwsem(&_origins_lock); |
320 | 343 | ||
321 | return 0; | 344 | return 0; |
@@ -324,6 +347,7 @@ static int init_origin_hash(void) | |||
324 | static void exit_origin_hash(void) | 347 | static void exit_origin_hash(void) |
325 | { | 348 | { |
326 | kfree(_origins); | 349 | kfree(_origins); |
350 | kfree(_dm_origins); | ||
327 | } | 351 | } |
328 | 352 | ||
329 | static unsigned origin_hash(struct block_device *bdev) | 353 | static unsigned origin_hash(struct block_device *bdev) |
@@ -350,6 +374,30 @@ static void __insert_origin(struct origin *o) | |||
350 | list_add_tail(&o->hash_list, sl); | 374 | list_add_tail(&o->hash_list, sl); |
351 | } | 375 | } |
352 | 376 | ||
377 | static struct dm_origin *__lookup_dm_origin(struct block_device *origin) | ||
378 | { | ||
379 | struct list_head *ol; | ||
380 | struct dm_origin *o; | ||
381 | |||
382 | ol = &_dm_origins[origin_hash(origin)]; | ||
383 | list_for_each_entry (o, ol, hash_list) | ||
384 | if (bdev_equal(o->dev->bdev, origin)) | ||
385 | return o; | ||
386 | |||
387 | return NULL; | ||
388 | } | ||
389 | |||
390 | static void __insert_dm_origin(struct dm_origin *o) | ||
391 | { | ||
392 | struct list_head *sl = &_dm_origins[origin_hash(o->dev->bdev)]; | ||
393 | list_add_tail(&o->hash_list, sl); | ||
394 | } | ||
395 | |||
396 | static void __remove_dm_origin(struct dm_origin *o) | ||
397 | { | ||
398 | list_del(&o->hash_list); | ||
399 | } | ||
400 | |||
353 | /* | 401 | /* |
354 | * _origins_lock must be held when calling this function. | 402 | * _origins_lock must be held when calling this function. |
355 | * Returns number of snapshots registered using the supplied cow device, plus: | 403 | * Returns number of snapshots registered using the supplied cow device, plus: |
@@ -1841,8 +1889,20 @@ static void snapshot_resume(struct dm_target *ti) | |||
1841 | { | 1889 | { |
1842 | struct dm_snapshot *s = ti->private; | 1890 | struct dm_snapshot *s = ti->private; |
1843 | struct dm_snapshot *snap_src = NULL, *snap_dest = NULL; | 1891 | struct dm_snapshot *snap_src = NULL, *snap_dest = NULL; |
1892 | struct dm_origin *o; | ||
1893 | struct mapped_device *origin_md = NULL; | ||
1844 | 1894 | ||
1845 | down_read(&_origins_lock); | 1895 | down_read(&_origins_lock); |
1896 | |||
1897 | o = __lookup_dm_origin(s->origin->bdev); | ||
1898 | if (o) | ||
1899 | origin_md = dm_table_get_md(o->ti->table); | ||
1900 | if (origin_md == dm_table_get_md(ti->table)) | ||
1901 | origin_md = NULL; | ||
1902 | |||
1903 | if (origin_md) | ||
1904 | dm_internal_suspend_fast(origin_md); | ||
1905 | |||
1846 | (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL); | 1906 | (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL); |
1847 | if (snap_src && snap_dest) { | 1907 | if (snap_src && snap_dest) { |
1848 | down_write(&snap_src->lock); | 1908 | down_write(&snap_src->lock); |
@@ -1851,6 +1911,10 @@ static void snapshot_resume(struct dm_target *ti) | |||
1851 | up_write(&snap_dest->lock); | 1911 | up_write(&snap_dest->lock); |
1852 | up_write(&snap_src->lock); | 1912 | up_write(&snap_src->lock); |
1853 | } | 1913 | } |
1914 | |||
1915 | if (origin_md) | ||
1916 | dm_internal_resume_fast(origin_md); | ||
1917 | |||
1854 | up_read(&_origins_lock); | 1918 | up_read(&_origins_lock); |
1855 | 1919 | ||
1856 | /* Now we have correct chunk size, reregister */ | 1920 | /* Now we have correct chunk size, reregister */ |
@@ -2133,11 +2197,6 @@ static int origin_write_extent(struct dm_snapshot *merging_snap, | |||
2133 | * Origin: maps a linear range of a device, with hooks for snapshotting. | 2197 | * Origin: maps a linear range of a device, with hooks for snapshotting. |
2134 | */ | 2198 | */ |
2135 | 2199 | ||
2136 | struct dm_origin { | ||
2137 | struct dm_dev *dev; | ||
2138 | unsigned split_boundary; | ||
2139 | }; | ||
2140 | |||
2141 | /* | 2200 | /* |
2142 | * Construct an origin mapping: <dev_path> | 2201 | * Construct an origin mapping: <dev_path> |
2143 | * The context for an origin is merely a 'struct dm_dev *' | 2202 | * The context for an origin is merely a 'struct dm_dev *' |
@@ -2166,6 +2225,7 @@ static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
2166 | goto bad_open; | 2225 | goto bad_open; |
2167 | } | 2226 | } |
2168 | 2227 | ||
2228 | o->ti = ti; | ||
2169 | ti->private = o; | 2229 | ti->private = o; |
2170 | ti->num_flush_bios = 1; | 2230 | ti->num_flush_bios = 1; |
2171 | 2231 | ||
@@ -2180,6 +2240,7 @@ bad_alloc: | |||
2180 | static void origin_dtr(struct dm_target *ti) | 2240 | static void origin_dtr(struct dm_target *ti) |
2181 | { | 2241 | { |
2182 | struct dm_origin *o = ti->private; | 2242 | struct dm_origin *o = ti->private; |
2243 | |||
2183 | dm_put_device(ti, o->dev); | 2244 | dm_put_device(ti, o->dev); |
2184 | kfree(o); | 2245 | kfree(o); |
2185 | } | 2246 | } |
@@ -2216,6 +2277,19 @@ static void origin_resume(struct dm_target *ti) | |||
2216 | struct dm_origin *o = ti->private; | 2277 | struct dm_origin *o = ti->private; |
2217 | 2278 | ||
2218 | o->split_boundary = get_origin_minimum_chunksize(o->dev->bdev); | 2279 | o->split_boundary = get_origin_minimum_chunksize(o->dev->bdev); |
2280 | |||
2281 | down_write(&_origins_lock); | ||
2282 | __insert_dm_origin(o); | ||
2283 | up_write(&_origins_lock); | ||
2284 | } | ||
2285 | |||
2286 | static void origin_postsuspend(struct dm_target *ti) | ||
2287 | { | ||
2288 | struct dm_origin *o = ti->private; | ||
2289 | |||
2290 | down_write(&_origins_lock); | ||
2291 | __remove_dm_origin(o); | ||
2292 | up_write(&_origins_lock); | ||
2219 | } | 2293 | } |
2220 | 2294 | ||
2221 | static void origin_status(struct dm_target *ti, status_type_t type, | 2295 | static void origin_status(struct dm_target *ti, status_type_t type, |
@@ -2258,12 +2332,13 @@ static int origin_iterate_devices(struct dm_target *ti, | |||
2258 | 2332 | ||
2259 | static struct target_type origin_target = { | 2333 | static struct target_type origin_target = { |
2260 | .name = "snapshot-origin", | 2334 | .name = "snapshot-origin", |
2261 | .version = {1, 8, 1}, | 2335 | .version = {1, 9, 0}, |
2262 | .module = THIS_MODULE, | 2336 | .module = THIS_MODULE, |
2263 | .ctr = origin_ctr, | 2337 | .ctr = origin_ctr, |
2264 | .dtr = origin_dtr, | 2338 | .dtr = origin_dtr, |
2265 | .map = origin_map, | 2339 | .map = origin_map, |
2266 | .resume = origin_resume, | 2340 | .resume = origin_resume, |
2341 | .postsuspend = origin_postsuspend, | ||
2267 | .status = origin_status, | 2342 | .status = origin_status, |
2268 | .merge = origin_merge, | 2343 | .merge = origin_merge, |
2269 | .iterate_devices = origin_iterate_devices, | 2344 | .iterate_devices = origin_iterate_devices, |
@@ -2271,7 +2346,7 @@ static struct target_type origin_target = { | |||
2271 | 2346 | ||
2272 | static struct target_type snapshot_target = { | 2347 | static struct target_type snapshot_target = { |
2273 | .name = "snapshot", | 2348 | .name = "snapshot", |
2274 | .version = {1, 12, 0}, | 2349 | .version = {1, 13, 0}, |
2275 | .module = THIS_MODULE, | 2350 | .module = THIS_MODULE, |
2276 | .ctr = snapshot_ctr, | 2351 | .ctr = snapshot_ctr, |
2277 | .dtr = snapshot_dtr, | 2352 | .dtr = snapshot_dtr, |