diff options
Diffstat (limited to 'drivers/md/dm-snap-persistent.c')
| -rw-r--r-- | drivers/md/dm-snap-persistent.c | 88 |
1 files changed, 53 insertions, 35 deletions
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index 6e3fe4f14934..d5b2e08750d5 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c | |||
| @@ -106,6 +106,13 @@ struct pstore { | |||
| 106 | void *zero_area; | 106 | void *zero_area; |
| 107 | 107 | ||
| 108 | /* | 108 | /* |
| 109 | * An area used for header. The header can be written | ||
| 110 | * concurrently with metadata (when invalidating the snapshot), | ||
| 111 | * so it needs a separate buffer. | ||
| 112 | */ | ||
| 113 | void *header_area; | ||
| 114 | |||
| 115 | /* | ||
| 109 | * Used to keep track of which metadata area the data in | 116 | * Used to keep track of which metadata area the data in |
| 110 | * 'chunk' refers to. | 117 | * 'chunk' refers to. |
| 111 | */ | 118 | */ |
| @@ -148,16 +155,27 @@ static int alloc_area(struct pstore *ps) | |||
| 148 | */ | 155 | */ |
| 149 | ps->area = vmalloc(len); | 156 | ps->area = vmalloc(len); |
| 150 | if (!ps->area) | 157 | if (!ps->area) |
| 151 | return r; | 158 | goto err_area; |
| 152 | 159 | ||
| 153 | ps->zero_area = vmalloc(len); | 160 | ps->zero_area = vmalloc(len); |
| 154 | if (!ps->zero_area) { | 161 | if (!ps->zero_area) |
| 155 | vfree(ps->area); | 162 | goto err_zero_area; |
| 156 | return r; | ||
| 157 | } | ||
| 158 | memset(ps->zero_area, 0, len); | 163 | memset(ps->zero_area, 0, len); |
| 159 | 164 | ||
| 165 | ps->header_area = vmalloc(len); | ||
| 166 | if (!ps->header_area) | ||
| 167 | goto err_header_area; | ||
| 168 | |||
| 160 | return 0; | 169 | return 0; |
| 170 | |||
| 171 | err_header_area: | ||
| 172 | vfree(ps->zero_area); | ||
| 173 | |||
| 174 | err_zero_area: | ||
| 175 | vfree(ps->area); | ||
| 176 | |||
| 177 | err_area: | ||
| 178 | return r; | ||
| 161 | } | 179 | } |
| 162 | 180 | ||
| 163 | static void free_area(struct pstore *ps) | 181 | static void free_area(struct pstore *ps) |
| @@ -169,6 +187,10 @@ static void free_area(struct pstore *ps) | |||
| 169 | if (ps->zero_area) | 187 | if (ps->zero_area) |
| 170 | vfree(ps->zero_area); | 188 | vfree(ps->zero_area); |
| 171 | ps->zero_area = NULL; | 189 | ps->zero_area = NULL; |
| 190 | |||
| 191 | if (ps->header_area) | ||
| 192 | vfree(ps->header_area); | ||
| 193 | ps->header_area = NULL; | ||
| 172 | } | 194 | } |
| 173 | 195 | ||
| 174 | struct mdata_req { | 196 | struct mdata_req { |
| @@ -188,7 +210,8 @@ static void do_metadata(struct work_struct *work) | |||
| 188 | /* | 210 | /* |
| 189 | * Read or write a chunk aligned and sized block of data from a device. | 211 | * Read or write a chunk aligned and sized block of data from a device. |
| 190 | */ | 212 | */ |
| 191 | static int chunk_io(struct pstore *ps, chunk_t chunk, int rw, int metadata) | 213 | static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw, |
| 214 | int metadata) | ||
| 192 | { | 215 | { |
| 193 | struct dm_io_region where = { | 216 | struct dm_io_region where = { |
| 194 | .bdev = ps->store->cow->bdev, | 217 | .bdev = ps->store->cow->bdev, |
| @@ -198,7 +221,7 @@ static int chunk_io(struct pstore *ps, chunk_t chunk, int rw, int metadata) | |||
| 198 | struct dm_io_request io_req = { | 221 | struct dm_io_request io_req = { |
| 199 | .bi_rw = rw, | 222 | .bi_rw = rw, |
| 200 | .mem.type = DM_IO_VMA, | 223 | .mem.type = DM_IO_VMA, |
| 201 | .mem.ptr.vma = ps->area, | 224 | .mem.ptr.vma = area, |
| 202 | .client = ps->io_client, | 225 | .client = ps->io_client, |
| 203 | .notify.fn = NULL, | 226 | .notify.fn = NULL, |
| 204 | }; | 227 | }; |
| @@ -240,7 +263,7 @@ static int area_io(struct pstore *ps, int rw) | |||
| 240 | 263 | ||
| 241 | chunk = area_location(ps, ps->current_area); | 264 | chunk = area_location(ps, ps->current_area); |
| 242 | 265 | ||
| 243 | r = chunk_io(ps, chunk, rw, 0); | 266 | r = chunk_io(ps, ps->area, chunk, rw, 0); |
| 244 | if (r) | 267 | if (r) |
| 245 | return r; | 268 | return r; |
| 246 | 269 | ||
| @@ -254,20 +277,7 @@ static void zero_memory_area(struct pstore *ps) | |||
| 254 | 277 | ||
| 255 | static int zero_disk_area(struct pstore *ps, chunk_t area) | 278 | static int zero_disk_area(struct pstore *ps, chunk_t area) |
| 256 | { | 279 | { |
| 257 | struct dm_io_region where = { | 280 | return chunk_io(ps, ps->zero_area, area_location(ps, area), WRITE, 0); |
| 258 | .bdev = ps->store->cow->bdev, | ||
| 259 | .sector = ps->store->chunk_size * area_location(ps, area), | ||
| 260 | .count = ps->store->chunk_size, | ||
| 261 | }; | ||
| 262 | struct dm_io_request io_req = { | ||
| 263 | .bi_rw = WRITE, | ||
| 264 | .mem.type = DM_IO_VMA, | ||
| 265 | .mem.ptr.vma = ps->zero_area, | ||
| 266 | .client = ps->io_client, | ||
| 267 | .notify.fn = NULL, | ||
| 268 | }; | ||
| 269 | |||
| 270 | return dm_io(&io_req, 1, &where, NULL); | ||
| 271 | } | 281 | } |
| 272 | 282 | ||
| 273 | static int read_header(struct pstore *ps, int *new_snapshot) | 283 | static int read_header(struct pstore *ps, int *new_snapshot) |
| @@ -276,6 +286,7 @@ static int read_header(struct pstore *ps, int *new_snapshot) | |||
| 276 | struct disk_header *dh; | 286 | struct disk_header *dh; |
| 277 | chunk_t chunk_size; | 287 | chunk_t chunk_size; |
| 278 | int chunk_size_supplied = 1; | 288 | int chunk_size_supplied = 1; |
| 289 | char *chunk_err; | ||
| 279 | 290 | ||
| 280 | /* | 291 | /* |
| 281 | * Use default chunk size (or hardsect_size, if larger) if none supplied | 292 | * Use default chunk size (or hardsect_size, if larger) if none supplied |
| @@ -297,11 +308,11 @@ static int read_header(struct pstore *ps, int *new_snapshot) | |||
| 297 | if (r) | 308 | if (r) |
| 298 | return r; | 309 | return r; |
| 299 | 310 | ||
| 300 | r = chunk_io(ps, 0, READ, 1); | 311 | r = chunk_io(ps, ps->header_area, 0, READ, 1); |
| 301 | if (r) | 312 | if (r) |
| 302 | goto bad; | 313 | goto bad; |
| 303 | 314 | ||
| 304 | dh = (struct disk_header *) ps->area; | 315 | dh = ps->header_area; |
| 305 | 316 | ||
| 306 | if (le32_to_cpu(dh->magic) == 0) { | 317 | if (le32_to_cpu(dh->magic) == 0) { |
| 307 | *new_snapshot = 1; | 318 | *new_snapshot = 1; |
| @@ -319,20 +330,25 @@ static int read_header(struct pstore *ps, int *new_snapshot) | |||
| 319 | ps->version = le32_to_cpu(dh->version); | 330 | ps->version = le32_to_cpu(dh->version); |
| 320 | chunk_size = le32_to_cpu(dh->chunk_size); | 331 | chunk_size = le32_to_cpu(dh->chunk_size); |
| 321 | 332 | ||
| 322 | if (!chunk_size_supplied || ps->store->chunk_size == chunk_size) | 333 | if (ps->store->chunk_size == chunk_size) |
| 323 | return 0; | 334 | return 0; |
| 324 | 335 | ||
| 325 | DMWARN("chunk size %llu in device metadata overrides " | 336 | if (chunk_size_supplied) |
| 326 | "table chunk size of %llu.", | 337 | DMWARN("chunk size %llu in device metadata overrides " |
| 327 | (unsigned long long)chunk_size, | 338 | "table chunk size of %llu.", |
| 328 | (unsigned long long)ps->store->chunk_size); | 339 | (unsigned long long)chunk_size, |
| 340 | (unsigned long long)ps->store->chunk_size); | ||
| 329 | 341 | ||
| 330 | /* We had a bogus chunk_size. Fix stuff up. */ | 342 | /* We had a bogus chunk_size. Fix stuff up. */ |
| 331 | free_area(ps); | 343 | free_area(ps); |
| 332 | 344 | ||
| 333 | ps->store->chunk_size = chunk_size; | 345 | r = dm_exception_store_set_chunk_size(ps->store, chunk_size, |
| 334 | ps->store->chunk_mask = chunk_size - 1; | 346 | &chunk_err); |
| 335 | ps->store->chunk_shift = ffs(chunk_size) - 1; | 347 | if (r) { |
| 348 | DMERR("invalid on-disk chunk size %llu: %s.", | ||
| 349 | (unsigned long long)chunk_size, chunk_err); | ||
| 350 | return r; | ||
| 351 | } | ||
| 336 | 352 | ||
| 337 | r = dm_io_client_resize(sectors_to_pages(ps->store->chunk_size), | 353 | r = dm_io_client_resize(sectors_to_pages(ps->store->chunk_size), |
| 338 | ps->io_client); | 354 | ps->io_client); |
| @@ -351,15 +367,15 @@ static int write_header(struct pstore *ps) | |||
| 351 | { | 367 | { |
| 352 | struct disk_header *dh; | 368 | struct disk_header *dh; |
| 353 | 369 | ||
| 354 | memset(ps->area, 0, ps->store->chunk_size << SECTOR_SHIFT); | 370 | memset(ps->header_area, 0, ps->store->chunk_size << SECTOR_SHIFT); |
| 355 | 371 | ||
| 356 | dh = (struct disk_header *) ps->area; | 372 | dh = ps->header_area; |
| 357 | dh->magic = cpu_to_le32(SNAP_MAGIC); | 373 | dh->magic = cpu_to_le32(SNAP_MAGIC); |
| 358 | dh->valid = cpu_to_le32(ps->valid); | 374 | dh->valid = cpu_to_le32(ps->valid); |
| 359 | dh->version = cpu_to_le32(ps->version); | 375 | dh->version = cpu_to_le32(ps->version); |
| 360 | dh->chunk_size = cpu_to_le32(ps->store->chunk_size); | 376 | dh->chunk_size = cpu_to_le32(ps->store->chunk_size); |
| 361 | 377 | ||
| 362 | return chunk_io(ps, 0, WRITE, 1); | 378 | return chunk_io(ps, ps->header_area, 0, WRITE, 1); |
| 363 | } | 379 | } |
| 364 | 380 | ||
| 365 | /* | 381 | /* |
| @@ -679,6 +695,8 @@ static int persistent_ctr(struct dm_exception_store *store, | |||
| 679 | ps->valid = 1; | 695 | ps->valid = 1; |
| 680 | ps->version = SNAPSHOT_DISK_VERSION; | 696 | ps->version = SNAPSHOT_DISK_VERSION; |
| 681 | ps->area = NULL; | 697 | ps->area = NULL; |
| 698 | ps->zero_area = NULL; | ||
| 699 | ps->header_area = NULL; | ||
| 682 | ps->next_free = 2; /* skipping the header and first area */ | 700 | ps->next_free = 2; /* skipping the header and first area */ |
| 683 | ps->current_committed = 0; | 701 | ps->current_committed = 0; |
| 684 | 702 | ||
