activemap.c revision 204076
1258057Sbr/*- 2258057Sbr * Copyright (c) 2009-2010 The FreeBSD Foundation 3258057Sbr * All rights reserved. 4258057Sbr * 5258057Sbr * This software was developed by Pawel Jakub Dawidek under sponsorship from 6258057Sbr * the FreeBSD Foundation. 7258057Sbr * 8258057Sbr * Redistribution and use in source and binary forms, with or without 9258057Sbr * modification, are permitted provided that the following conditions 10258057Sbr * are met: 11258057Sbr * 1. Redistributions of source code must retain the above copyright 12258057Sbr * notice, this list of conditions and the following disclaimer. 13258057Sbr * 2. Redistributions in binary form must reproduce the above copyright 14258057Sbr * notice, this list of conditions and the following disclaimer in the 15258057Sbr * documentation and/or other materials provided with the distribution. 16258057Sbr * 17258057Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18258057Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19258057Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20258057Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21258057Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22258057Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23258057Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24258057Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25258057Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26258057Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27258057Sbr * SUCH DAMAGE. 28258057Sbr */ 29258057Sbr 30258057Sbr#include <sys/cdefs.h> 31258057Sbr__FBSDID("$FreeBSD: head/sbin/hastd/activemap.c 204076 2010-02-18 23:16:19Z pjd $"); 32258057Sbr 33258057Sbr#include <sys/param.h> /* powerof2() */ 34258057Sbr#include <sys/queue.h> 35258057Sbr 36258057Sbr#include <assert.h> 37258057Sbr#include <bitstring.h> 38258057Sbr#include <errno.h> 39258057Sbr#include <stdint.h> 40258057Sbr#include <stdio.h> 41258057Sbr#include <stdlib.h> 42258057Sbr#include <string.h> 43258057Sbr 44258057Sbr#include <activemap.h> 45258057Sbr 46258057Sbr#define ACTIVEMAP_MAGIC 0xac71e4 47258057Sbrstruct activemap { 48258057Sbr int am_magic; /* Magic value. */ 49277996Sloos off_t am_mediasize; /* Media size in bytes. */ 50258057Sbr uint32_t am_extentsize; /* Extent size in bytes, 51258057Sbr must be power of 2. */ 52258057Sbr uint8_t am_extentshift;/* 2 ^ extentbits == extentsize */ 53258057Sbr int am_nextents; /* Number of extents. */ 54258057Sbr size_t am_mapsize; /* Bitmap size in bytes. */ 55258057Sbr uint16_t *am_memtab; /* An array that holds number of pending 56258057Sbr writes per extent. */ 57258057Sbr bitstr_t *am_diskmap; /* On-disk bitmap of dirty extents. */ 58258057Sbr bitstr_t *am_memmap; /* In-memory bitmap of dirty extents. */ 59258057Sbr size_t am_diskmapsize; /* Map size rounded up to sector size. */ 60258057Sbr uint64_t am_ndirty; /* Number of dirty regions. */ 61262885Sbr bitstr_t *am_syncmap; /* Bitmap of extents to sync. */ 62258057Sbr off_t am_syncoff; /* Next synchronization offset. */ 63258057Sbr TAILQ_HEAD(skeepdirty, keepdirty) am_keepdirty; /* List of extents that 64258057Sbr we keep dirty to reduce bitmap 65258057Sbr updates. */ 66258057Sbr int am_nkeepdirty; /* Number of am_keepdirty elements. */ 67258057Sbr int am_nkeepdirty_limit; /* Maximum number of am_keepdirty 68258057Sbr elements. */ 69258057Sbr}; 70258057Sbr 71258057Sbrstruct keepdirty { 72258057Sbr int kd_extent; 73258057Sbr TAILQ_ENTRY(keepdirty) kd_next; 74258057Sbr}; 75258057Sbr 76258057Sbr/* 77277996Sloos * Helper function taken from sys/systm.h to calculate extentshift. 78258057Sbr */ 79258057Sbrstatic uint32_t 80258057Sbrbitcount32(uint32_t x) 81258057Sbr{ 82258057Sbr 83258057Sbr x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 84258057Sbr x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 85258057Sbr x = (x + (x >> 4)) & 0x0f0f0f0f; 86258057Sbr x = (x + (x >> 8)); 87258057Sbr x = (x + (x >> 16)) & 0x000000ff; 88262885Sbr return (x); 89258057Sbr} 90258057Sbr 91258057Sbrstatic __inline int 92277996Sloosoff2ext(const struct activemap *amp, off_t offset) 93258057Sbr{ 94258057Sbr int extent; 95258057Sbr 96258057Sbr assert(offset >= 0 && offset < amp->am_mediasize); 97258057Sbr extent = (offset >> amp->am_extentshift); 98258057Sbr assert(extent >= 0 && extent < amp->am_nextents); 99258057Sbr return (extent); 100258057Sbr} 101258057Sbr 102258057Sbrstatic __inline off_t 103258057Sbrext2off(const struct activemap *amp, int extent) 104258057Sbr{ 105258057Sbr off_t offset; 106258057Sbr 107258057Sbr assert(extent >= 0 && extent < amp->am_nextents); 108258057Sbr offset = ((off_t)extent << amp->am_extentshift); 109261410Sian assert(offset >= 0 && offset < amp->am_mediasize); 110261410Sian return (offset); 111261410Sian} 112258057Sbr 113258057Sbr/* 114258057Sbr * Function calculates number of requests needed to synchronize the given 115258057Sbr * extent. 116258057Sbr */ 117258057Sbrstatic __inline int 118258057Sbrext2reqs(const struct activemap *amp, int ext) 119258057Sbr{ 120258057Sbr off_t left; 121258057Sbr 122258057Sbr if (ext < amp->am_nextents - 1) 123262885Sbr return (((amp->am_extentsize - 1) / MAXPHYS) + 1); 124258057Sbr 125258057Sbr assert(ext == amp->am_nextents - 1); 126258057Sbr left = amp->am_mediasize % amp->am_extentsize; 127258057Sbr if (left == 0) 128258057Sbr left = amp->am_extentsize; 129258057Sbr return (((left - 1) / MAXPHYS) + 1); 130277968Sloos} 131258057Sbr 132258057Sbr/* 133258057Sbr * Initialize activemap structure and allocate memory for internal needs. 134258057Sbr * Function returns 0 on success and -1 if any of the allocations failed. 135258057Sbr */ 136258057Sbrint 137258057Sbractivemap_init(struct activemap **ampp, uint64_t mediasize, uint32_t extentsize, 138262885Sbr uint32_t sectorsize, uint32_t keepdirty) 139262885Sbr{ 140258057Sbr struct activemap *amp; 141258057Sbr 142258057Sbr assert(ampp != NULL); 143258057Sbr assert(mediasize > 0); 144258057Sbr assert(extentsize > 0); 145258057Sbr assert(powerof2(extentsize)); 146258057Sbr assert(sectorsize > 0); 147258057Sbr assert(powerof2(sectorsize)); 148258057Sbr assert(keepdirty > 0); 149258057Sbr 150258057Sbr amp = malloc(sizeof(*amp)); 151258057Sbr if (amp == NULL) 152277996Sloos return (-1); 153277996Sloos 154277996Sloos amp->am_mediasize = mediasize; 155277996Sloos amp->am_nkeepdirty_limit = keepdirty; 156277996Sloos amp->am_extentsize = extentsize; 157277996Sloos amp->am_extentshift = bitcount32(extentsize - 1); 158258057Sbr amp->am_nextents = ((mediasize - 1) / extentsize) + 1; 159277996Sloos amp->am_mapsize = sizeof(bitstr_t) * bitstr_size(amp->am_nextents); 160258057Sbr amp->am_diskmapsize = roundup2(amp->am_mapsize, sectorsize); 161258057Sbr amp->am_ndirty = 0; 162277996Sloos amp->am_syncoff = -2; 163277996Sloos TAILQ_INIT(&->am_keepdirty); 164277996Sloos amp->am_nkeepdirty = 0; 165277996Sloos 166277996Sloos amp->am_memtab = calloc(amp->am_nextents, sizeof(amp->am_memtab[0])); 167277996Sloos amp->am_diskmap = calloc(1, amp->am_diskmapsize); 168277996Sloos amp->am_memmap = bit_alloc(amp->am_nextents); 169277996Sloos amp->am_syncmap = bit_alloc(amp->am_nextents); 170277996Sloos 171277996Sloos /* 172258057Sbr * Check to see if any of the allocations above failed. 173258057Sbr */ 174258057Sbr if (amp->am_memtab == NULL || amp->am_diskmap == NULL || 175258057Sbr amp->am_memmap == NULL || amp->am_syncmap == NULL) { 176258057Sbr if (amp->am_memtab != NULL) 177258057Sbr free(amp->am_memtab); 178258057Sbr if (amp->am_diskmap != NULL) 179258057Sbr free(amp->am_diskmap); 180258057Sbr if (amp->am_memmap != NULL) 181258057Sbr free(amp->am_memmap); 182258057Sbr if (amp->am_syncmap != NULL) 183258057Sbr free(amp->am_syncmap); 184258057Sbr amp->am_magic = 0; 185258057Sbr free(amp); 186258057Sbr errno = ENOMEM; 187258057Sbr return (-1); 188258057Sbr } 189258057Sbr 190258057Sbr amp->am_magic = ACTIVEMAP_MAGIC; 191258057Sbr *ampp = amp; 192258057Sbr 193258057Sbr return (0); 194258057Sbr} 195258057Sbr 196258057Sbrstatic struct keepdirty * 197258057Sbrkeepdirty_find(struct activemap *amp, int extent) 198258057Sbr{ 199258057Sbr struct keepdirty *kd; 200258057Sbr 201258057Sbr TAILQ_FOREACH(kd, &->am_keepdirty, kd_next) { 202258057Sbr if (kd->kd_extent == extent) 203258057Sbr break; 204258057Sbr } 205258057Sbr return (kd); 206258057Sbr} 207258057Sbr 208258057Sbrstatic void 209258057Sbrkeepdirty_add(struct activemap *amp, int extent) 210258057Sbr{ 211258057Sbr struct keepdirty *kd; 212258057Sbr 213258057Sbr kd = keepdirty_find(amp, extent); 214258057Sbr if (kd != NULL) { 215258057Sbr /* 216258057Sbr * Only move element at the begining. 217258057Sbr */ 218258057Sbr TAILQ_REMOVE(&->am_keepdirty, kd, kd_next); 219258057Sbr TAILQ_INSERT_HEAD(&->am_keepdirty, kd, kd_next); 220258057Sbr return; 221258057Sbr } 222258057Sbr /* 223258057Sbr * Add new element, but first remove the most unused one if 224258057Sbr * we have too many. 225258057Sbr */ 226258057Sbr if (amp->am_nkeepdirty >= amp->am_nkeepdirty_limit) { 227258057Sbr kd = TAILQ_LAST(&->am_keepdirty, skeepdirty); 228258057Sbr assert(kd != NULL); 229258057Sbr TAILQ_REMOVE(&->am_keepdirty, kd, kd_next); 230258057Sbr amp->am_nkeepdirty--; 231258057Sbr assert(amp->am_nkeepdirty > 0); 232258057Sbr } 233258057Sbr if (kd == NULL) 234258057Sbr kd = malloc(sizeof(*kd)); 235258057Sbr /* We can ignore allocation failure. */ 236258057Sbr if (kd != NULL) { 237258057Sbr kd->kd_extent = extent; 238258057Sbr amp->am_nkeepdirty++; 239258057Sbr TAILQ_INSERT_HEAD(&->am_keepdirty, kd, kd_next); 240258057Sbr } 241258057Sbr} 242258057Sbr 243258057Sbrstatic void 244258057Sbrkeepdirty_fill(struct activemap *amp) 245258057Sbr{ 246258057Sbr struct keepdirty *kd; 247258057Sbr 248258057Sbr TAILQ_FOREACH(kd, &->am_keepdirty, kd_next) 249258057Sbr bit_set(amp->am_diskmap, kd->kd_extent); 250258057Sbr} 251258057Sbr 252258057Sbrstatic void 253258057Sbrkeepdirty_free(struct activemap *amp) 254258057Sbr{ 255258057Sbr struct keepdirty *kd; 256258057Sbr 257258057Sbr while ((kd = TAILQ_FIRST(&->am_keepdirty)) != NULL) { 258258057Sbr TAILQ_REMOVE(&->am_keepdirty, kd, kd_next); 259258057Sbr amp->am_nkeepdirty--; 260258057Sbr free(kd); 261258057Sbr } 262266119Sbr assert(amp->am_nkeepdirty == 0); 263258057Sbr} 264258057Sbr 265258057Sbr/* 266258057Sbr * Function frees resources allocated by activemap_init() function. 267258057Sbr */ 268258057Sbrvoid 269258057Sbractivemap_free(struct activemap *amp) 270258057Sbr{ 271258057Sbr 272258057Sbr assert(amp->am_magic == ACTIVEMAP_MAGIC); 273258057Sbr 274258057Sbr amp->am_magic = 0; 275258057Sbr 276258057Sbr keepdirty_free(amp); 277258057Sbr free(amp->am_memtab); 278258057Sbr free(amp->am_diskmap); 279258057Sbr free(amp->am_memmap); 280258057Sbr free(amp->am_syncmap); 281258057Sbr} 282258057Sbr 283258057Sbr/* 284258057Sbr * Function should be called before we handle write requests. It updates 285258057Sbr * internal structures and returns true if on-disk metadata should be updated. 286258057Sbr */ 287258057Sbrbool 288258057Sbractivemap_write_start(struct activemap *amp, off_t offset, off_t length) 289258057Sbr{ 290258057Sbr bool modified; 291258057Sbr off_t end; 292258057Sbr int ext; 293258057Sbr 294258057Sbr assert(amp->am_magic == ACTIVEMAP_MAGIC); 295258057Sbr assert(length > 0); 296258057Sbr 297258057Sbr modified = false; 298258057Sbr end = offset + length - 1; 299258057Sbr 300258057Sbr for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 301258057Sbr /* 302258057Sbr * If the number of pending writes is increased from 0, 303258057Sbr * we have to mark the extent as dirty also in on-disk bitmap. 304258057Sbr * By returning true we inform the caller that on-disk bitmap 305258057Sbr * was modified and has to be flushed to disk. 306258057Sbr */ 307258057Sbr if (amp->am_memtab[ext]++ == 0) { 308258057Sbr assert(!bit_test(amp->am_memmap, ext)); 309258057Sbr bit_set(amp->am_memmap, ext); 310258057Sbr amp->am_ndirty++; 311258057Sbr modified = true; 312258057Sbr } 313258057Sbr keepdirty_add(amp, ext); 314258057Sbr } 315258057Sbr 316258057Sbr return (modified); 317258057Sbr} 318258057Sbr 319258057Sbr/* 320258057Sbr * Function should be called after receiving write confirmation. It updates 321258057Sbr * internal structures and returns true if on-disk metadata should be updated. 322258057Sbr */ 323258057Sbrbool 324258057Sbractivemap_write_complete(struct activemap *amp, off_t offset, off_t length) 325258057Sbr{ 326258057Sbr bool modified; 327258057Sbr off_t end; 328258057Sbr int ext; 329258057Sbr 330258057Sbr assert(amp->am_magic == ACTIVEMAP_MAGIC); 331258057Sbr assert(length > 0); 332258057Sbr 333258057Sbr modified = false; 334258057Sbr end = offset + length - 1; 335258057Sbr 336258057Sbr for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 337258057Sbr /* 338258057Sbr * If the number of pending writes goes down to 0, we have to 339258057Sbr * mark the extent as clean also in on-disk bitmap. 340258057Sbr * By returning true we inform the caller that on-disk bitmap 341258057Sbr * was modified and has to be flushed to disk. 342258057Sbr */ 343258057Sbr assert(amp->am_memtab[ext] > 0); 344258057Sbr assert(bit_test(amp->am_memmap, ext)); 345258057Sbr if (--amp->am_memtab[ext] == 0) { 346258057Sbr bit_clear(amp->am_memmap, ext); 347258057Sbr amp->am_ndirty--; 348258057Sbr modified = true; 349258057Sbr } 350258057Sbr } 351258057Sbr 352258057Sbr return (modified); 353258057Sbr} 354258057Sbr 355258057Sbr/* 356258057Sbr * Function should be called after finishing synchronization of one extent. 357258057Sbr * It returns true if on-disk metadata should be updated. 358258057Sbr */ 359258057Sbrbool 360258057Sbractivemap_extent_complete(struct activemap *amp, int extent) 361258057Sbr{ 362258057Sbr bool modified; 363258057Sbr int reqs; 364258057Sbr 365258057Sbr assert(amp->am_magic == ACTIVEMAP_MAGIC); 366258057Sbr assert(extent >= 0 && extent < amp->am_nextents); 367277996Sloos 368258057Sbr modified = false; 369258057Sbr 370258057Sbr reqs = ext2reqs(amp, extent); 371258057Sbr assert(amp->am_memtab[extent] >= reqs); 372258057Sbr amp->am_memtab[extent] -= reqs; 373258057Sbr assert(bit_test(amp->am_memmap, extent)); 374258057Sbr if (amp->am_memtab[extent] == 0) { 375258057Sbr bit_clear(amp->am_memmap, extent); 376258057Sbr amp->am_ndirty--; 377258057Sbr modified = true; 378258057Sbr } 379258057Sbr 380258057Sbr return (modified); 381258057Sbr} 382258057Sbr 383258057Sbr/* 384258057Sbr * Function returns number of dirty regions. 385258057Sbr */ 386258057Sbruint64_t 387258057Sbractivemap_ndirty(const struct activemap *amp) 388{ 389 390 assert(amp->am_magic == ACTIVEMAP_MAGIC); 391 392 return (amp->am_ndirty); 393} 394 395/* 396 * Function compare on-disk bitmap and in-memory bitmap and returns true if 397 * they differ and should be flushed to the disk. 398 */ 399bool 400activemap_differ(const struct activemap *amp) 401{ 402 403 assert(amp->am_magic == ACTIVEMAP_MAGIC); 404 405 return (memcmp(amp->am_diskmap, amp->am_memmap, 406 amp->am_mapsize) != 0); 407} 408 409/* 410 * Function returns number of bytes used by bitmap. 411 */ 412size_t 413activemap_size(const struct activemap *amp) 414{ 415 416 assert(amp->am_magic == ACTIVEMAP_MAGIC); 417 418 return (amp->am_mapsize); 419} 420 421/* 422 * Function returns number of bytes needed for storing on-disk bitmap. 423 * This is the same as activemap_size(), but rounded up to sector size. 424 */ 425size_t 426activemap_ondisk_size(const struct activemap *amp) 427{ 428 429 assert(amp->am_magic == ACTIVEMAP_MAGIC); 430 431 return (amp->am_diskmapsize); 432} 433 434/* 435 * Function copies the given buffer read from disk to the internal bitmap. 436 */ 437void 438activemap_copyin(struct activemap *amp, const unsigned char *buf, size_t size) 439{ 440 int ext; 441 442 assert(amp->am_magic == ACTIVEMAP_MAGIC); 443 assert(size >= amp->am_mapsize); 444 445 memcpy(amp->am_diskmap, buf, amp->am_mapsize); 446 memcpy(amp->am_memmap, buf, amp->am_mapsize); 447 memcpy(amp->am_syncmap, buf, amp->am_mapsize); 448 449 bit_ffs(amp->am_memmap, amp->am_nextents, &ext); 450 if (ext == -1) { 451 /* There are no dirty extents, so we can leave now. */ 452 return; 453 } 454 /* 455 * Set synchronization offset to the first dirty extent. 456 */ 457 activemap_sync_rewind(amp); 458 /* 459 * We have dirty extents and we want them to stay that way until 460 * we synchronize, so we set number of pending writes to number 461 * of requests needed to synchronize one extent. 462 */ 463 amp->am_ndirty = 0; 464 for (; ext < amp->am_nextents; ext++) { 465 if (bit_test(amp->am_memmap, ext)) { 466 amp->am_memtab[ext] = ext2reqs(amp, ext); 467 amp->am_ndirty++; 468 } 469 } 470} 471 472/* 473 * Function merges the given bitmap with existng one. 474 */ 475void 476activemap_merge(struct activemap *amp, const unsigned char *buf, size_t size) 477{ 478 bitstr_t *remmap = __DECONST(bitstr_t *, buf); 479 int ext; 480 481 assert(amp->am_magic == ACTIVEMAP_MAGIC); 482 assert(size >= amp->am_mapsize); 483 484 bit_ffs(remmap, amp->am_nextents, &ext); 485 if (ext == -1) { 486 /* There are no dirty extents, so we can leave now. */ 487 return; 488 } 489 /* 490 * We have dirty extents and we want them to stay that way until 491 * we synchronize, so we set number of pending writes to number 492 * of requests needed to synchronize one extent. 493 */ 494 for (; ext < amp->am_nextents; ext++) { 495 /* Local extent already dirty. */ 496 if (bit_test(amp->am_syncmap, ext)) 497 continue; 498 /* Remote extent isn't dirty. */ 499 if (!bit_test(remmap, ext)) 500 continue; 501 bit_set(amp->am_syncmap, ext); 502 bit_set(amp->am_memmap, ext); 503 bit_set(amp->am_diskmap, ext); 504 if (amp->am_memtab[ext] == 0) 505 amp->am_ndirty++; 506 amp->am_memtab[ext] = ext2reqs(amp, ext); 507 } 508 /* 509 * Set synchronization offset to the first dirty extent. 510 */ 511 activemap_sync_rewind(amp); 512} 513 514/* 515 * Function returns pointer to internal bitmap that should be written to disk. 516 */ 517const unsigned char * 518activemap_bitmap(struct activemap *amp, size_t *sizep) 519{ 520 521 assert(amp->am_magic == ACTIVEMAP_MAGIC); 522 523 if (sizep != NULL) 524 *sizep = amp->am_diskmapsize; 525 memcpy(amp->am_diskmap, amp->am_memmap, amp->am_mapsize); 526 keepdirty_fill(amp); 527 return ((const unsigned char *)amp->am_diskmap); 528} 529 530/* 531 * Function calculates size needed to store bitmap on disk. 532 */ 533size_t 534activemap_calc_ondisk_size(uint64_t mediasize, uint32_t extentsize, 535 uint32_t sectorsize) 536{ 537 uint64_t nextents, mapsize; 538 539 assert(mediasize > 0); 540 assert(extentsize > 0); 541 assert(powerof2(extentsize)); 542 assert(sectorsize > 0); 543 assert(powerof2(sectorsize)); 544 545 nextents = ((mediasize - 1) / extentsize) + 1; 546 mapsize = sizeof(bitstr_t) * bitstr_size(nextents); 547 return (roundup2(mapsize, sectorsize)); 548} 549 550/* 551 * Set synchronization offset to the first dirty extent. 552 */ 553void 554activemap_sync_rewind(struct activemap *amp) 555{ 556 int ext; 557 558 assert(amp->am_magic == ACTIVEMAP_MAGIC); 559 560 bit_ffs(amp->am_syncmap, amp->am_nextents, &ext); 561 if (ext == -1) { 562 /* There are no extents to synchronize. */ 563 amp->am_syncoff = -2; 564 return; 565 } 566 /* 567 * Mark that we want to start synchronization from the begining. 568 */ 569 amp->am_syncoff = -1; 570} 571 572/* 573 * Return next offset of where we should synchronize. 574 */ 575off_t 576activemap_sync_offset(struct activemap *amp, off_t *lengthp, int *syncextp) 577{ 578 off_t syncoff, left; 579 int ext; 580 581 assert(amp->am_magic == ACTIVEMAP_MAGIC); 582 assert(lengthp != NULL); 583 assert(syncextp != NULL); 584 585 *syncextp = -1; 586 587 if (amp->am_syncoff == -2) 588 return (-1); 589 590 if (amp->am_syncoff >= 0 && 591 (amp->am_syncoff + MAXPHYS >= amp->am_mediasize || 592 off2ext(amp, amp->am_syncoff) != 593 off2ext(amp, amp->am_syncoff + MAXPHYS))) { 594 /* 595 * We are about to change extent, so mark previous one as clean. 596 */ 597 ext = off2ext(amp, amp->am_syncoff); 598 bit_clear(amp->am_syncmap, ext); 599 *syncextp = ext; 600 amp->am_syncoff = -1; 601 } 602 603 if (amp->am_syncoff == -1) { 604 /* 605 * Let's find first extent to synchronize. 606 */ 607 bit_ffs(amp->am_syncmap, amp->am_nextents, &ext); 608 if (ext == -1) { 609 amp->am_syncoff = -2; 610 return (-1); 611 } 612 amp->am_syncoff = ext2off(amp, ext); 613 } else { 614 /* 615 * We don't change extent, so just increase offset. 616 */ 617 amp->am_syncoff += MAXPHYS; 618 if (amp->am_syncoff >= amp->am_mediasize) { 619 amp->am_syncoff = -2; 620 return (-1); 621 } 622 } 623 624 syncoff = amp->am_syncoff; 625 left = ext2off(amp, off2ext(amp, syncoff)) + 626 amp->am_extentsize - syncoff; 627 if (syncoff + left > amp->am_mediasize) 628 left = amp->am_mediasize - syncoff; 629 if (left > MAXPHYS) 630 left = MAXPHYS; 631 632 assert(left >= 0 && left <= MAXPHYS); 633 assert(syncoff >= 0 && syncoff < amp->am_mediasize); 634 assert(syncoff + left >= 0 && syncoff + left <= amp->am_mediasize); 635 636 *lengthp = left; 637 return (syncoff); 638} 639 640/* 641 * Mark extent(s) containing the given region for synchronization. 642 * Most likely one of the components is unavailable. 643 */ 644bool 645activemap_need_sync(struct activemap *amp, off_t offset, off_t length) 646{ 647 bool modified; 648 off_t end; 649 int ext; 650 651 assert(amp->am_magic == ACTIVEMAP_MAGIC); 652 653 modified = false; 654 end = offset + length - 1; 655 656 for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 657 if (bit_test(amp->am_syncmap, ext)) { 658 /* Already marked for synchronization. */ 659 assert(bit_test(amp->am_memmap, ext)); 660 continue; 661 } 662 bit_set(amp->am_syncmap, ext); 663 if (!bit_test(amp->am_memmap, ext)) { 664 bit_set(amp->am_memmap, ext); 665 amp->am_ndirty++; 666 } 667 amp->am_memtab[ext] += ext2reqs(amp, ext); 668 modified = true; 669 } 670 671 return (modified); 672} 673 674void 675activemap_dump(const struct activemap *amp) 676{ 677 int bit; 678 679 printf("M: "); 680 for (bit = 0; bit < amp->am_nextents; bit++) 681 printf("%d", bit_test(amp->am_memmap, bit) ? 1 : 0); 682 printf("\n"); 683 printf("D: "); 684 for (bit = 0; bit < amp->am_nextents; bit++) 685 printf("%d", bit_test(amp->am_diskmap, bit) ? 1 : 0); 686 printf("\n"); 687 printf("S: "); 688 for (bit = 0; bit < amp->am_nextents; bit++) 689 printf("%d", bit_test(amp->am_syncmap, bit) ? 1 : 0); 690 printf("\n"); 691} 692