activemap.c revision 229778
11844Swollman/*- 250476Speter * Copyright (c) 2009-2010 The FreeBSD Foundation 31844Swollman * All rights reserved. 41638Srgrimes * 594940Sru * This software was developed by Pawel Jakub Dawidek under sponsorship from 61638Srgrimes * the FreeBSD Foundation. 742915Sjdp * 842915Sjdp * Redistribution and use in source and binary forms, with or without 942915Sjdp * modification, are permitted provided that the following conditions 1042915Sjdp * are met: 11139106Sru * 1. Redistributions of source code must retain the above copyright 1242915Sjdp * notice, this list of conditions and the following disclaimer. 1342915Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1442915Sjdp * notice, this list of conditions and the following disclaimer in the 15129024Sdes * documentation and/or other materials provided with the distribution. 16129024Sdes * 1729141Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18129024Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19129024Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20129024Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21125119Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22100332Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23100332Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2442915Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2542915Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2629141Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27119607Sru * SUCH DAMAGE. 28117034Sgordon */ 29119607Sru 30117034Sgordon#include <sys/cdefs.h> 31162210Simp__FBSDID("$FreeBSD: head/sbin/hastd/activemap.c 229778 2012-01-07 16:09:33Z uqs $"); 32162210Simp 33162293Sobrien#include <sys/param.h> /* powerof2() */ 34162210Simp#include <sys/queue.h> 35162210Simp 36206082Snetchild#include <bitstring.h> 37206082Snetchild#include <errno.h> 38206082Snetchild#include <stdint.h> 39206082Snetchild#include <stdio.h> 40206082Snetchild#include <stdlib.h> 412827Sjkh#include <string.h> 422827Sjkh 43179184Sjb#include <pjdlog.h> 44179184Sjb 45179184Sjb#include "activemap.h" 462827Sjkh 47179184Sjb#ifndef PJDLOG_ASSERT 482827Sjkh#include <assert.h> 492827Sjkh#define PJDLOG_ASSERT(...) assert(__VA_ARGS__) 501638Srgrimes#endif 512827Sjkh 521638Srgrimes#define ACTIVEMAP_MAGIC 0xac71e4 5318529Sbdestruct activemap { 5418529Sbde int am_magic; /* Magic value. */ 551638Srgrimes off_t am_mediasize; /* Media size in bytes. */ 5642450Sjdp uint32_t am_extentsize; /* Extent size in bytes, 571638Srgrimes must be power of 2. */ 58220755Sdim uint8_t am_extentshift;/* 2 ^ extentbits == extentsize */ 591638Srgrimes int am_nextents; /* Number of extents. */ 6096512Sru size_t am_mapsize; /* Bitmap size in bytes. */ 61211725Simp uint16_t *am_memtab; /* An array that holds number of pending 6296512Sru writes per extent. */ 6396512Sru bitstr_t *am_diskmap; /* On-disk bitmap of dirty extents. */ 6496512Sru bitstr_t *am_memmap; /* In-memory bitmap of dirty extents. */ 6596512Sru size_t am_diskmapsize; /* Map size rounded up to sector size. */ 6696512Sru uint64_t am_ndirty; /* Number of dirty regions. */ 6796512Sru bitstr_t *am_syncmap; /* Bitmap of extents to sync. */ 68211437Srpaulo off_t am_syncoff; /* Next synchronization offset. */ 69126890Strhodes TAILQ_HEAD(skeepdirty, keepdirty) am_keepdirty; /* List of extents that 70126890Strhodes we keep dirty to reduce bitmap 71126890Strhodes updates. */ 72126890Strhodes int am_nkeepdirty; /* Number of am_keepdirty elements. */ 73126890Strhodes int am_nkeepdirty_limit; /* Maximum number of am_keepdirty 741638Srgrimes elements. */ 75202807Ssepotvin}; 76210612Srpaulo 77210636Srpaulostruct keepdirty { 78210636Srpaulo int kd_extent; 791638Srgrimes TAILQ_ENTRY(keepdirty) kd_next; 8042450Sjdp}; 811844Swollman 82210612Srpaulo/* 83210636Srpaulo * Helper function taken from sys/systm.h to calculate extentshift. 84210636Srpaulo */ 851844Swollmanstatic uint32_t 8636673Sdtbitcount32(uint32_t x) 87202807Ssepotvin{ 881844Swollman 8942450Sjdp x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 901844Swollman x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 911844Swollman x = (x + (x >> 4)) & 0x0f0f0f0f; 921844Swollman x = (x + (x >> 8)); 93127027Strhodes x = (x + (x >> 16)) & 0x000000ff; 94210612Srpaulo return (x); 95210636Srpaulo} 96210636Srpaulo 971844Swollmanstatic __inline int 9842450Sjdpoff2ext(const struct activemap *amp, off_t offset) 991844Swollman{ 100210612Srpaulo int extent; 101210636Srpaulo 102210636Srpaulo PJDLOG_ASSERT(offset >= 0 && offset < amp->am_mediasize); 1031844Swollman extent = (offset >> amp->am_extentshift); 104117173Sru PJDLOG_ASSERT(extent >= 0 && extent < amp->am_nextents); 105117159Sru return (extent); 106210612Srpaulo} 107210636Srpaulo 108210636Srpaulostatic __inline off_t 1091638Srgrimesext2off(const struct activemap *amp, int extent) 110117173Sru{ 111217100Skib off_t offset; 112217100Skib 113210612Srpaulo PJDLOG_ASSERT(extent >= 0 && extent < amp->am_nextents); 114210636Srpaulo offset = ((off_t)extent << amp->am_extentshift); 115210636Srpaulo PJDLOG_ASSERT(offset >= 0 && offset < amp->am_mediasize); 116117173Sru return (offset); 117117173Sru} 118217100Skib 119117173Sru/* 120210612Srpaulo * Function calculates number of requests needed to synchronize the given 121210636Srpaulo * extent. 122210636Srpaulo */ 123117173Srustatic __inline int 1241844Swollmanext2reqs(const struct activemap *amp, int ext) 125217100Skib{ 126210612Srpaulo off_t left; 127210636Srpaulo 128210636Srpaulo if (ext < amp->am_nextents - 1) 1291844Swollman return (((amp->am_extentsize - 1) / MAXPHYS) + 1); 13042450Sjdp 131217100Skib PJDLOG_ASSERT(ext == amp->am_nextents - 1); 132210612Srpaulo left = amp->am_mediasize % amp->am_extentsize; 133210636Srpaulo if (left == 0) 134210636Srpaulo left = amp->am_extentsize; 1351844Swollman return (((left - 1) / MAXPHYS) + 1); 13696512Sru} 1371638Srgrimes 138168317Skan/* 139156772Sdeischen * Initialize activemap structure and allocate memory for internal needs. 140178047Skan * Function returns 0 on success and -1 if any of the allocations failed. 141168317Skan */ 142169822Sruint 143156772Sdeischenactivemap_init(struct activemap **ampp, uint64_t mediasize, uint32_t extentsize, 144156772Sdeischen uint32_t sectorsize, uint32_t keepdirty) 145156772Sdeischen{ 146156772Sdeischen struct activemap *amp; 14799362Sru 14899362Sru PJDLOG_ASSERT(ampp != NULL); 14999362Sru PJDLOG_ASSERT(mediasize > 0); 15099362Sru PJDLOG_ASSERT(extentsize > 0); 15196512Sru PJDLOG_ASSERT(powerof2(extentsize)); 15296512Sru PJDLOG_ASSERT(sectorsize > 0); 1531638Srgrimes PJDLOG_ASSERT(powerof2(sectorsize)); 15496512Sru PJDLOG_ASSERT(keepdirty > 0); 15596512Sru 15696512Sru amp = malloc(sizeof(*amp)); 157163683Sru if (amp == NULL) 158163683Sru return (-1); 159163683Sru 160163683Sru amp->am_mediasize = mediasize; 161163683Sru amp->am_nkeepdirty_limit = keepdirty; 16296512Sru amp->am_extentsize = extentsize; 16399362Sru amp->am_extentshift = bitcount32(extentsize - 1); 1641638Srgrimes amp->am_nextents = ((mediasize - 1) / extentsize) + 1; 16596512Sru amp->am_mapsize = sizeof(bitstr_t) * bitstr_size(amp->am_nextents); 16695114Sobrien amp->am_diskmapsize = roundup2(amp->am_mapsize, sectorsize); 167156854Sru amp->am_ndirty = 0; 16896512Sru amp->am_syncoff = -2; 16996512Sru TAILQ_INIT(&->am_keepdirty); 17095306Sru amp->am_nkeepdirty = 0; 17196512Sru 17296512Sru amp->am_memtab = calloc(amp->am_nextents, sizeof(amp->am_memtab[0])); 17396512Sru amp->am_diskmap = calloc(1, amp->am_diskmapsize); 174163683Sru amp->am_memmap = bit_alloc(amp->am_nextents); 175163683Sru amp->am_syncmap = bit_alloc(amp->am_nextents); 176163683Sru 177163683Sru /* 178163683Sru * Check to see if any of the allocations above failed. 17996512Sru */ 18074805Sru if (amp->am_memtab == NULL || amp->am_diskmap == NULL || 1811844Swollman amp->am_memmap == NULL || amp->am_syncmap == NULL) { 18299362Sru if (amp->am_memtab != NULL) 18399362Sru free(amp->am_memtab); 18496512Sru if (amp->am_diskmap != NULL) 18599362Sru free(amp->am_diskmap); 1861844Swollman if (amp->am_memmap != NULL) 18796512Sru free(amp->am_memmap); 18896512Sru if (amp->am_syncmap != NULL) 1891638Srgrimes free(amp->am_syncmap); 190212423Srpaulo amp->am_magic = 0; 191212423Srpaulo free(amp); 192212423Srpaulo errno = ENOMEM; 19342915Sjdp return (-1); 194212423Srpaulo } 19542915Sjdp 19696512Sru amp->am_magic = ACTIVEMAP_MAGIC; 19742915Sjdp *ampp = amp; 19896512Sru 19942915Sjdp return (0); 200163683Sru} 201195697Skan 20296512Srustatic struct keepdirty * 203163683Srukeepdirty_find(struct activemap *amp, int extent) 204163683Sru{ 205195697Skan struct keepdirty *kd; 206163683Sru 207163683Sru TAILQ_FOREACH(kd, &->am_keepdirty, kd_next) { 20828945Speter if (kd->kd_extent == extent) 209210612Srpaulo break; 210210656Srpaulo } 211210636Srpaulo return (kd); 212163683Sru} 2131844Swollman 214156813Srustatic bool 21596512Srukeepdirty_add(struct activemap *amp, int extent) 21696512Sru{ 21796512Sru struct keepdirty *kd; 2182353Sbde 21996512Sru kd = keepdirty_find(amp, extent); 22096512Sru if (kd != NULL) { 22196512Sru /* 2223859Sbde * Only move element at the beginning. 2231844Swollman */ 224139106Sru TAILQ_REMOVE(&->am_keepdirty, kd, kd_next); 22596512Sru TAILQ_INSERT_HEAD(&->am_keepdirty, kd, kd_next); 22696512Sru return (false); 22796512Sru } 22896512Sru /* 22992491Smarkm * Add new element, but first remove the most unused one if 23096512Sru * we have too many. 23196512Sru */ 23292491Smarkm if (amp->am_nkeepdirty >= amp->am_nkeepdirty_limit) { 23392491Smarkm kd = TAILQ_LAST(&->am_keepdirty, skeepdirty); 2341638Srgrimes PJDLOG_ASSERT(kd != NULL); 235144893Sharti TAILQ_REMOVE(&->am_keepdirty, kd, kd_next); 23696512Sru amp->am_nkeepdirty--; 23796512Sru PJDLOG_ASSERT(amp->am_nkeepdirty > 0); 23896512Sru } 239156813Sru if (kd == NULL) 24096512Sru kd = malloc(sizeof(*kd)); 2411638Srgrimes /* We can ignore allocation failure. */ 2421638Srgrimes if (kd != NULL) { 24334179Sbde kd->kd_extent = extent; 24424750Sbde amp->am_nkeepdirty++; 24542450Sjdp TAILQ_INSERT_HEAD(&->am_keepdirty, kd, kd_next); 24624750Sbde } 24724750Sbde 248139107Sru return (true); 24931809Sbde} 25042915Sjdp 25127910Sasamistatic void 25228945Speterkeepdirty_fill(struct activemap *amp) 2531638Srgrimes{ 2541638Srgrimes struct keepdirty *kd; 2551638Srgrimes 256136019Sru TAILQ_FOREACH(kd, &->am_keepdirty, kd_next) 257139111Sru bit_set(amp->am_diskmap, kd->kd_extent); 2582298Swollman} 2592298Swollman 260136019Srustatic void 261136019Srukeepdirty_free(struct activemap *amp) 2622298Swollman{ 26349328Shoek struct keepdirty *kd; 26449328Shoek 26549328Shoek while ((kd = TAILQ_FIRST(&->am_keepdirty)) != NULL) { 26649328Shoek TAILQ_REMOVE(&->am_keepdirty, kd, kd_next); 26756971Sru amp->am_nkeepdirty--; 26849328Shoek free(kd); 26949328Shoek } 27049328Shoek PJDLOG_ASSERT(amp->am_nkeepdirty == 0); 27149328Shoek} 27299362Sru 27395306Sru/* 27499343Sru * Function frees resources allocated by activemap_init() function. 27595306Sru */ 276172832Sruvoid 27792980Sdesactivemap_free(struct activemap *amp) 27849328Shoek{ 27996512Sru 280156854Sru PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 28192980Sdes 28249328Shoek amp->am_magic = 0; 2831638Srgrimes 284116144Sobrien keepdirty_free(amp); 285100872Sru free(amp->am_memtab); 28649328Shoek free(amp->am_diskmap); 28742915Sjdp free(amp->am_memmap); 28842915Sjdp free(amp->am_syncmap); 289119846Sru} 290119846Sru 291119846Sru/* 292119846Sru * Function should be called before we handle write requests. It updates 293119730Speter * internal structures and returns true if on-disk metadata should be updated. 294119846Sru */ 295119846Srubool 296119846Sruactivemap_write_start(struct activemap *amp, off_t offset, off_t length) 2971844Swollman{ 29828945Speter bool modified; 299119730Speter off_t end; 300119846Sru int ext; 301156813Sru 302100872Sru PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 30349328Shoek PJDLOG_ASSERT(length > 0); 3041844Swollman 305139106Sru modified = false; 306100872Sru end = offset + length - 1; 30796462Sru 30896462Sru for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 309144893Sharti /* 31096462Sru * If the number of pending writes is increased from 0, 311141503Sphantom * we have to mark the extent as dirty also in on-disk bitmap. 31297769Sru * By returning true we inform the caller that on-disk bitmap 31396668Sru * was modified and has to be flushed to disk. 31499256Sru */ 31596462Sru if (amp->am_memtab[ext]++ == 0) { 316156813Sru PJDLOG_ASSERT(!bit_test(amp->am_memmap, ext)); 31796164Sru bit_set(amp->am_memmap, ext); 31899343Sru amp->am_ndirty++; 31996162Sru } 32096162Sru if (keepdirty_add(amp, ext)) 3211638Srgrimes modified = true; 3221638Srgrimes } 3231638Srgrimes 32495306Sru return (modified); 325103713Smarkm} 3261638Srgrimes 3271638Srgrimes/* 328156813Sru * Function should be called after receiving write confirmation. It updates 3291638Srgrimes * internal structures and returns true if on-disk metadata should be updated. 33074842Sru */ 3311844Swollmanbool 3321844Swollmanactivemap_write_complete(struct activemap *amp, off_t offset, off_t length) 33334092Sbde{ 33499362Sru bool modified; 33596512Sru off_t end; 33699362Sru int ext; 337124637Sru 338124637Sru PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 339124637Sru PJDLOG_ASSERT(length > 0); 34034092Sbde 34199362Sru modified = false; 34299362Sru end = offset + length - 1; 34399362Sru 344124637Sru for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 345124637Sru /* 346124637Sru * If the number of pending writes goes down to 0, we have to 34796512Sru * mark the extent as clean also in on-disk bitmap. 34899362Sru * By returning true we inform the caller that on-disk bitmap 34934092Sbde * was modified and has to be flushed to disk. 350100457Sru */ 351100457Sru PJDLOG_ASSERT(amp->am_memtab[ext] > 0); 352100457Sru PJDLOG_ASSERT(bit_test(amp->am_memmap, ext)); 353100457Sru if (--amp->am_memtab[ext] == 0) { 354100457Sru bit_clear(amp->am_memmap, ext); 355100457Sru amp->am_ndirty--; 356100457Sru if (keepdirty_find(amp, ext) == NULL) 357100457Sru modified = true; 358100457Sru } 359156854Sru } 360100457Sru 361100457Sru return (modified); 362100457Sru} 363100457Sru 364100457Sru/* 365100457Sru * Function should be called after finishing synchronization of one extent. 366100457Sru * It returns true if on-disk metadata should be updated. 367100457Sru */ 368100457Srubool 369100457Sruactivemap_extent_complete(struct activemap *amp, int extent) 370100457Sru{ 371100457Sru bool modified; 372100457Sru int reqs; 373100457Sru 374100457Sru PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 375100457Sru PJDLOG_ASSERT(extent >= 0 && extent < amp->am_nextents); 376100457Sru 377144893Sharti modified = false; 378100457Sru 379100457Sru reqs = ext2reqs(amp, extent); 380100457Sru PJDLOG_ASSERT(amp->am_memtab[extent] >= reqs); 381100457Sru amp->am_memtab[extent] -= reqs; 382100457Sru PJDLOG_ASSERT(bit_test(amp->am_memmap, extent)); 383100457Sru if (amp->am_memtab[extent] == 0) { 384157054Sdes bit_clear(amp->am_memmap, extent); 385157054Sdes amp->am_ndirty--; 386100457Sru modified = true; 387157054Sdes } 388100457Sru 38916663Sjkh return (modified); 39076861Skris} 39176861Skris 392/* 393 * Function returns number of dirty regions. 394 */ 395uint64_t 396activemap_ndirty(const struct activemap *amp) 397{ 398 399 PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 400 401 return (amp->am_ndirty); 402} 403 404/* 405 * Function compare on-disk bitmap and in-memory bitmap and returns true if 406 * they differ and should be flushed to the disk. 407 */ 408bool 409activemap_differ(const struct activemap *amp) 410{ 411 412 PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 413 414 return (memcmp(amp->am_diskmap, amp->am_memmap, 415 amp->am_mapsize) != 0); 416} 417 418/* 419 * Function returns number of bytes used by bitmap. 420 */ 421size_t 422activemap_size(const struct activemap *amp) 423{ 424 425 PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 426 427 return (amp->am_mapsize); 428} 429 430/* 431 * Function returns number of bytes needed for storing on-disk bitmap. 432 * This is the same as activemap_size(), but rounded up to sector size. 433 */ 434size_t 435activemap_ondisk_size(const struct activemap *amp) 436{ 437 438 PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 439 440 return (amp->am_diskmapsize); 441} 442 443/* 444 * Function copies the given buffer read from disk to the internal bitmap. 445 */ 446void 447activemap_copyin(struct activemap *amp, const unsigned char *buf, size_t size) 448{ 449 int ext; 450 451 PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 452 PJDLOG_ASSERT(size >= amp->am_mapsize); 453 454 memcpy(amp->am_diskmap, buf, amp->am_mapsize); 455 memcpy(amp->am_memmap, buf, amp->am_mapsize); 456 memcpy(amp->am_syncmap, buf, amp->am_mapsize); 457 458 bit_ffs(amp->am_memmap, amp->am_nextents, &ext); 459 if (ext == -1) { 460 /* There are no dirty extents, so we can leave now. */ 461 return; 462 } 463 /* 464 * Set synchronization offset to the first dirty extent. 465 */ 466 activemap_sync_rewind(amp); 467 /* 468 * We have dirty extents and we want them to stay that way until 469 * we synchronize, so we set number of pending writes to number 470 * of requests needed to synchronize one extent. 471 */ 472 amp->am_ndirty = 0; 473 for (; ext < amp->am_nextents; ext++) { 474 if (bit_test(amp->am_memmap, ext)) { 475 amp->am_memtab[ext] = ext2reqs(amp, ext); 476 amp->am_ndirty++; 477 } 478 } 479} 480 481/* 482 * Function merges the given bitmap with existing one. 483 */ 484void 485activemap_merge(struct activemap *amp, const unsigned char *buf, size_t size) 486{ 487 bitstr_t *remmap = __DECONST(bitstr_t *, buf); 488 int ext; 489 490 PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 491 PJDLOG_ASSERT(size >= amp->am_mapsize); 492 493 bit_ffs(remmap, amp->am_nextents, &ext); 494 if (ext == -1) { 495 /* There are no dirty extents, so we can leave now. */ 496 return; 497 } 498 /* 499 * We have dirty extents and we want them to stay that way until 500 * we synchronize, so we set number of pending writes to number 501 * of requests needed to synchronize one extent. 502 */ 503 for (; ext < amp->am_nextents; ext++) { 504 /* Local extent already dirty. */ 505 if (bit_test(amp->am_syncmap, ext)) 506 continue; 507 /* Remote extent isn't dirty. */ 508 if (!bit_test(remmap, ext)) 509 continue; 510 bit_set(amp->am_syncmap, ext); 511 bit_set(amp->am_memmap, ext); 512 bit_set(amp->am_diskmap, ext); 513 if (amp->am_memtab[ext] == 0) 514 amp->am_ndirty++; 515 amp->am_memtab[ext] = ext2reqs(amp, ext); 516 } 517 /* 518 * Set synchronization offset to the first dirty extent. 519 */ 520 activemap_sync_rewind(amp); 521} 522 523/* 524 * Function returns pointer to internal bitmap that should be written to disk. 525 */ 526const unsigned char * 527activemap_bitmap(struct activemap *amp, size_t *sizep) 528{ 529 530 PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 531 532 if (sizep != NULL) 533 *sizep = amp->am_diskmapsize; 534 memcpy(amp->am_diskmap, amp->am_memmap, amp->am_mapsize); 535 keepdirty_fill(amp); 536 return ((const unsigned char *)amp->am_diskmap); 537} 538 539/* 540 * Function calculates size needed to store bitmap on disk. 541 */ 542size_t 543activemap_calc_ondisk_size(uint64_t mediasize, uint32_t extentsize, 544 uint32_t sectorsize) 545{ 546 uint64_t nextents, mapsize; 547 548 PJDLOG_ASSERT(mediasize > 0); 549 PJDLOG_ASSERT(extentsize > 0); 550 PJDLOG_ASSERT(powerof2(extentsize)); 551 PJDLOG_ASSERT(sectorsize > 0); 552 PJDLOG_ASSERT(powerof2(sectorsize)); 553 554 nextents = ((mediasize - 1) / extentsize) + 1; 555 mapsize = sizeof(bitstr_t) * bitstr_size(nextents); 556 return (roundup2(mapsize, sectorsize)); 557} 558 559/* 560 * Set synchronization offset to the first dirty extent. 561 */ 562void 563activemap_sync_rewind(struct activemap *amp) 564{ 565 int ext; 566 567 PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 568 569 bit_ffs(amp->am_syncmap, amp->am_nextents, &ext); 570 if (ext == -1) { 571 /* There are no extents to synchronize. */ 572 amp->am_syncoff = -2; 573 return; 574 } 575 /* 576 * Mark that we want to start synchronization from the beginning. 577 */ 578 amp->am_syncoff = -1; 579} 580 581/* 582 * Return next offset of where we should synchronize. 583 */ 584off_t 585activemap_sync_offset(struct activemap *amp, off_t *lengthp, int *syncextp) 586{ 587 off_t syncoff, left; 588 int ext; 589 590 PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 591 PJDLOG_ASSERT(lengthp != NULL); 592 PJDLOG_ASSERT(syncextp != NULL); 593 594 *syncextp = -1; 595 596 if (amp->am_syncoff == -2) 597 return (-1); 598 599 if (amp->am_syncoff >= 0 && 600 (amp->am_syncoff + MAXPHYS >= amp->am_mediasize || 601 off2ext(amp, amp->am_syncoff) != 602 off2ext(amp, amp->am_syncoff + MAXPHYS))) { 603 /* 604 * We are about to change extent, so mark previous one as clean. 605 */ 606 ext = off2ext(amp, amp->am_syncoff); 607 bit_clear(amp->am_syncmap, ext); 608 *syncextp = ext; 609 amp->am_syncoff = -1; 610 } 611 612 if (amp->am_syncoff == -1) { 613 /* 614 * Let's find first extent to synchronize. 615 */ 616 bit_ffs(amp->am_syncmap, amp->am_nextents, &ext); 617 if (ext == -1) { 618 amp->am_syncoff = -2; 619 return (-1); 620 } 621 amp->am_syncoff = ext2off(amp, ext); 622 } else { 623 /* 624 * We don't change extent, so just increase offset. 625 */ 626 amp->am_syncoff += MAXPHYS; 627 if (amp->am_syncoff >= amp->am_mediasize) { 628 amp->am_syncoff = -2; 629 return (-1); 630 } 631 } 632 633 syncoff = amp->am_syncoff; 634 left = ext2off(amp, off2ext(amp, syncoff)) + 635 amp->am_extentsize - syncoff; 636 if (syncoff + left > amp->am_mediasize) 637 left = amp->am_mediasize - syncoff; 638 if (left > MAXPHYS) 639 left = MAXPHYS; 640 641 PJDLOG_ASSERT(left >= 0 && left <= MAXPHYS); 642 PJDLOG_ASSERT(syncoff >= 0 && syncoff < amp->am_mediasize); 643 PJDLOG_ASSERT(syncoff + left >= 0 && 644 syncoff + left <= amp->am_mediasize); 645 646 *lengthp = left; 647 return (syncoff); 648} 649 650/* 651 * Mark extent(s) containing the given region for synchronization. 652 * Most likely one of the components is unavailable. 653 */ 654bool 655activemap_need_sync(struct activemap *amp, off_t offset, off_t length) 656{ 657 bool modified; 658 off_t end; 659 int ext; 660 661 PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 662 663 modified = false; 664 end = offset + length - 1; 665 666 for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 667 if (bit_test(amp->am_syncmap, ext)) { 668 /* Already marked for synchronization. */ 669 PJDLOG_ASSERT(bit_test(amp->am_memmap, ext)); 670 continue; 671 } 672 bit_set(amp->am_syncmap, ext); 673 if (!bit_test(amp->am_memmap, ext)) { 674 bit_set(amp->am_memmap, ext); 675 amp->am_ndirty++; 676 } 677 amp->am_memtab[ext] += ext2reqs(amp, ext); 678 modified = true; 679 } 680 681 return (modified); 682} 683 684void 685activemap_dump(const struct activemap *amp) 686{ 687 int bit; 688 689 printf("M: "); 690 for (bit = 0; bit < amp->am_nextents; bit++) 691 printf("%d", bit_test(amp->am_memmap, bit) ? 1 : 0); 692 printf("\n"); 693 printf("D: "); 694 for (bit = 0; bit < amp->am_nextents; bit++) 695 printf("%d", bit_test(amp->am_diskmap, bit) ? 1 : 0); 696 printf("\n"); 697 printf("S: "); 698 for (bit = 0; bit < amp->am_nextents; bit++) 699 printf("%d", bit_test(amp->am_syncmap, bit) ? 1 : 0); 700 printf("\n"); 701} 702