activemap.c revision 223654
1204076Spjd/*- 2204076Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation 3204076Spjd * All rights reserved. 4204076Spjd * 5204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from 6204076Spjd * the FreeBSD Foundation. 7204076Spjd * 8204076Spjd * Redistribution and use in source and binary forms, with or without 9204076Spjd * modification, are permitted provided that the following conditions 10204076Spjd * are met: 11204076Spjd * 1. Redistributions of source code must retain the above copyright 12204076Spjd * notice, this list of conditions and the following disclaimer. 13204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 14204076Spjd * notice, this list of conditions and the following disclaimer in the 15204076Spjd * documentation and/or other materials provided with the distribution. 16204076Spjd * 17204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27204076Spjd * SUCH DAMAGE. 28204076Spjd */ 29204076Spjd 30204076Spjd#include <sys/cdefs.h> 31204076Spjd__FBSDID("$FreeBSD: head/sbin/hastd/activemap.c 223654 2011-06-28 20:57:54Z trociny $"); 32204076Spjd 33204076Spjd#include <sys/param.h> /* powerof2() */ 34204076Spjd#include <sys/queue.h> 35204076Spjd 36204076Spjd#include <assert.h> 37204076Spjd#include <bitstring.h> 38204076Spjd#include <errno.h> 39204076Spjd#include <stdint.h> 40204076Spjd#include <stdio.h> 41204076Spjd#include <stdlib.h> 42204076Spjd#include <string.h> 43204076Spjd 44204076Spjd#include <activemap.h> 45204076Spjd 46204076Spjd#define ACTIVEMAP_MAGIC 0xac71e4 47204076Spjdstruct activemap { 48204076Spjd int am_magic; /* Magic value. */ 49219864Spjd off_t am_mediasize; /* Media size in bytes. */ 50204076Spjd uint32_t am_extentsize; /* Extent size in bytes, 51204076Spjd must be power of 2. */ 52204076Spjd uint8_t am_extentshift;/* 2 ^ extentbits == extentsize */ 53204076Spjd int am_nextents; /* Number of extents. */ 54204076Spjd size_t am_mapsize; /* Bitmap size in bytes. */ 55204076Spjd uint16_t *am_memtab; /* An array that holds number of pending 56204076Spjd writes per extent. */ 57204076Spjd bitstr_t *am_diskmap; /* On-disk bitmap of dirty extents. */ 58204076Spjd bitstr_t *am_memmap; /* In-memory bitmap of dirty extents. */ 59204076Spjd size_t am_diskmapsize; /* Map size rounded up to sector size. */ 60204076Spjd uint64_t am_ndirty; /* Number of dirty regions. */ 61204076Spjd bitstr_t *am_syncmap; /* Bitmap of extents to sync. */ 62204076Spjd off_t am_syncoff; /* Next synchronization offset. */ 63204076Spjd TAILQ_HEAD(skeepdirty, keepdirty) am_keepdirty; /* List of extents that 64204076Spjd we keep dirty to reduce bitmap 65204076Spjd updates. */ 66204076Spjd int am_nkeepdirty; /* Number of am_keepdirty elements. */ 67204076Spjd int am_nkeepdirty_limit; /* Maximum number of am_keepdirty 68204076Spjd elements. */ 69204076Spjd}; 70204076Spjd 71204076Spjdstruct keepdirty { 72204076Spjd int kd_extent; 73204076Spjd TAILQ_ENTRY(keepdirty) kd_next; 74204076Spjd}; 75204076Spjd 76204076Spjd/* 77204076Spjd * Helper function taken from sys/systm.h to calculate extentshift. 78204076Spjd */ 79204076Spjdstatic uint32_t 80204076Spjdbitcount32(uint32_t x) 81204076Spjd{ 82204076Spjd 83204076Spjd x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 84204076Spjd x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 85204076Spjd x = (x + (x >> 4)) & 0x0f0f0f0f; 86204076Spjd x = (x + (x >> 8)); 87204076Spjd x = (x + (x >> 16)) & 0x000000ff; 88204076Spjd return (x); 89204076Spjd} 90204076Spjd 91204076Spjdstatic __inline int 92204076Spjdoff2ext(const struct activemap *amp, off_t offset) 93204076Spjd{ 94204076Spjd int extent; 95204076Spjd 96204076Spjd assert(offset >= 0 && offset < amp->am_mediasize); 97204076Spjd extent = (offset >> amp->am_extentshift); 98204076Spjd assert(extent >= 0 && extent < amp->am_nextents); 99204076Spjd return (extent); 100204076Spjd} 101204076Spjd 102204076Spjdstatic __inline off_t 103204076Spjdext2off(const struct activemap *amp, int extent) 104204076Spjd{ 105204076Spjd off_t offset; 106204076Spjd 107204076Spjd assert(extent >= 0 && extent < amp->am_nextents); 108204076Spjd offset = ((off_t)extent << amp->am_extentshift); 109204076Spjd assert(offset >= 0 && offset < amp->am_mediasize); 110204076Spjd return (offset); 111204076Spjd} 112204076Spjd 113204076Spjd/* 114204076Spjd * Function calculates number of requests needed to synchronize the given 115204076Spjd * extent. 116204076Spjd */ 117204076Spjdstatic __inline int 118204076Spjdext2reqs(const struct activemap *amp, int ext) 119204076Spjd{ 120204076Spjd off_t left; 121204076Spjd 122204076Spjd if (ext < amp->am_nextents - 1) 123204076Spjd return (((amp->am_extentsize - 1) / MAXPHYS) + 1); 124204076Spjd 125204076Spjd assert(ext == amp->am_nextents - 1); 126204076Spjd left = amp->am_mediasize % amp->am_extentsize; 127204076Spjd if (left == 0) 128204076Spjd left = amp->am_extentsize; 129204076Spjd return (((left - 1) / MAXPHYS) + 1); 130204076Spjd} 131204076Spjd 132204076Spjd/* 133204076Spjd * Initialize activemap structure and allocate memory for internal needs. 134204076Spjd * Function returns 0 on success and -1 if any of the allocations failed. 135204076Spjd */ 136204076Spjdint 137204076Spjdactivemap_init(struct activemap **ampp, uint64_t mediasize, uint32_t extentsize, 138204076Spjd uint32_t sectorsize, uint32_t keepdirty) 139204076Spjd{ 140204076Spjd struct activemap *amp; 141204076Spjd 142204076Spjd assert(ampp != NULL); 143204076Spjd assert(mediasize > 0); 144204076Spjd assert(extentsize > 0); 145204076Spjd assert(powerof2(extentsize)); 146204076Spjd assert(sectorsize > 0); 147204076Spjd assert(powerof2(sectorsize)); 148204076Spjd assert(keepdirty > 0); 149204076Spjd 150204076Spjd amp = malloc(sizeof(*amp)); 151204076Spjd if (amp == NULL) 152204076Spjd return (-1); 153204076Spjd 154204076Spjd amp->am_mediasize = mediasize; 155204076Spjd amp->am_nkeepdirty_limit = keepdirty; 156204076Spjd amp->am_extentsize = extentsize; 157204076Spjd amp->am_extentshift = bitcount32(extentsize - 1); 158204076Spjd amp->am_nextents = ((mediasize - 1) / extentsize) + 1; 159204076Spjd amp->am_mapsize = sizeof(bitstr_t) * bitstr_size(amp->am_nextents); 160204076Spjd amp->am_diskmapsize = roundup2(amp->am_mapsize, sectorsize); 161204076Spjd amp->am_ndirty = 0; 162204076Spjd amp->am_syncoff = -2; 163204076Spjd TAILQ_INIT(&->am_keepdirty); 164204076Spjd amp->am_nkeepdirty = 0; 165204076Spjd 166204076Spjd amp->am_memtab = calloc(amp->am_nextents, sizeof(amp->am_memtab[0])); 167204076Spjd amp->am_diskmap = calloc(1, amp->am_diskmapsize); 168204076Spjd amp->am_memmap = bit_alloc(amp->am_nextents); 169204076Spjd amp->am_syncmap = bit_alloc(amp->am_nextents); 170204076Spjd 171204076Spjd /* 172204076Spjd * Check to see if any of the allocations above failed. 173204076Spjd */ 174204076Spjd if (amp->am_memtab == NULL || amp->am_diskmap == NULL || 175204076Spjd amp->am_memmap == NULL || amp->am_syncmap == NULL) { 176204076Spjd if (amp->am_memtab != NULL) 177204076Spjd free(amp->am_memtab); 178204076Spjd if (amp->am_diskmap != NULL) 179204076Spjd free(amp->am_diskmap); 180204076Spjd if (amp->am_memmap != NULL) 181204076Spjd free(amp->am_memmap); 182204076Spjd if (amp->am_syncmap != NULL) 183204076Spjd free(amp->am_syncmap); 184204076Spjd amp->am_magic = 0; 185204076Spjd free(amp); 186204076Spjd errno = ENOMEM; 187204076Spjd return (-1); 188204076Spjd } 189204076Spjd 190204076Spjd amp->am_magic = ACTIVEMAP_MAGIC; 191204076Spjd *ampp = amp; 192204076Spjd 193204076Spjd return (0); 194204076Spjd} 195204076Spjd 196204076Spjdstatic struct keepdirty * 197204076Spjdkeepdirty_find(struct activemap *amp, int extent) 198204076Spjd{ 199204076Spjd struct keepdirty *kd; 200204076Spjd 201204076Spjd TAILQ_FOREACH(kd, &->am_keepdirty, kd_next) { 202204076Spjd if (kd->kd_extent == extent) 203204076Spjd break; 204204076Spjd } 205204076Spjd return (kd); 206204076Spjd} 207204076Spjd 208223654Strocinystatic bool 209204076Spjdkeepdirty_add(struct activemap *amp, int extent) 210204076Spjd{ 211204076Spjd struct keepdirty *kd; 212204076Spjd 213204076Spjd kd = keepdirty_find(amp, extent); 214204076Spjd if (kd != NULL) { 215204076Spjd /* 216204076Spjd * Only move element at the begining. 217204076Spjd */ 218204076Spjd TAILQ_REMOVE(&->am_keepdirty, kd, kd_next); 219204076Spjd TAILQ_INSERT_HEAD(&->am_keepdirty, kd, kd_next); 220223654Strociny return (false); 221204076Spjd } 222204076Spjd /* 223204076Spjd * Add new element, but first remove the most unused one if 224204076Spjd * we have too many. 225204076Spjd */ 226204076Spjd if (amp->am_nkeepdirty >= amp->am_nkeepdirty_limit) { 227204076Spjd kd = TAILQ_LAST(&->am_keepdirty, skeepdirty); 228204076Spjd assert(kd != NULL); 229204076Spjd TAILQ_REMOVE(&->am_keepdirty, kd, kd_next); 230204076Spjd amp->am_nkeepdirty--; 231204076Spjd assert(amp->am_nkeepdirty > 0); 232204076Spjd } 233204076Spjd if (kd == NULL) 234204076Spjd kd = malloc(sizeof(*kd)); 235204076Spjd /* We can ignore allocation failure. */ 236204076Spjd if (kd != NULL) { 237204076Spjd kd->kd_extent = extent; 238204076Spjd amp->am_nkeepdirty++; 239204076Spjd TAILQ_INSERT_HEAD(&->am_keepdirty, kd, kd_next); 240204076Spjd } 241223654Strociny 242223654Strociny return (true); 243204076Spjd} 244204076Spjd 245204076Spjdstatic void 246204076Spjdkeepdirty_fill(struct activemap *amp) 247204076Spjd{ 248204076Spjd struct keepdirty *kd; 249204076Spjd 250204076Spjd TAILQ_FOREACH(kd, &->am_keepdirty, kd_next) 251204076Spjd bit_set(amp->am_diskmap, kd->kd_extent); 252204076Spjd} 253204076Spjd 254204076Spjdstatic void 255204076Spjdkeepdirty_free(struct activemap *amp) 256204076Spjd{ 257204076Spjd struct keepdirty *kd; 258204076Spjd 259204076Spjd while ((kd = TAILQ_FIRST(&->am_keepdirty)) != NULL) { 260204076Spjd TAILQ_REMOVE(&->am_keepdirty, kd, kd_next); 261204076Spjd amp->am_nkeepdirty--; 262204076Spjd free(kd); 263204076Spjd } 264204076Spjd assert(amp->am_nkeepdirty == 0); 265204076Spjd} 266204076Spjd 267204076Spjd/* 268204076Spjd * Function frees resources allocated by activemap_init() function. 269204076Spjd */ 270204076Spjdvoid 271204076Spjdactivemap_free(struct activemap *amp) 272204076Spjd{ 273204076Spjd 274204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 275204076Spjd 276204076Spjd amp->am_magic = 0; 277204076Spjd 278204076Spjd keepdirty_free(amp); 279204076Spjd free(amp->am_memtab); 280204076Spjd free(amp->am_diskmap); 281204076Spjd free(amp->am_memmap); 282204076Spjd free(amp->am_syncmap); 283204076Spjd} 284204076Spjd 285204076Spjd/* 286204076Spjd * Function should be called before we handle write requests. It updates 287204076Spjd * internal structures and returns true if on-disk metadata should be updated. 288204076Spjd */ 289204076Spjdbool 290204076Spjdactivemap_write_start(struct activemap *amp, off_t offset, off_t length) 291204076Spjd{ 292204076Spjd bool modified; 293204076Spjd off_t end; 294204076Spjd int ext; 295204076Spjd 296204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 297204076Spjd assert(length > 0); 298204076Spjd 299204076Spjd modified = false; 300204076Spjd end = offset + length - 1; 301204076Spjd 302204076Spjd for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 303204076Spjd /* 304204076Spjd * If the number of pending writes is increased from 0, 305204076Spjd * we have to mark the extent as dirty also in on-disk bitmap. 306204076Spjd * By returning true we inform the caller that on-disk bitmap 307204076Spjd * was modified and has to be flushed to disk. 308204076Spjd */ 309204076Spjd if (amp->am_memtab[ext]++ == 0) { 310204076Spjd assert(!bit_test(amp->am_memmap, ext)); 311204076Spjd bit_set(amp->am_memmap, ext); 312204076Spjd amp->am_ndirty++; 313223654Strociny } 314223654Strociny if (keepdirty_add(amp, ext)) 315204076Spjd modified = true; 316204076Spjd } 317204076Spjd 318204076Spjd return (modified); 319204076Spjd} 320204076Spjd 321204076Spjd/* 322204076Spjd * Function should be called after receiving write confirmation. It updates 323204076Spjd * internal structures and returns true if on-disk metadata should be updated. 324204076Spjd */ 325204076Spjdbool 326204076Spjdactivemap_write_complete(struct activemap *amp, off_t offset, off_t length) 327204076Spjd{ 328204076Spjd bool modified; 329204076Spjd off_t end; 330204076Spjd int ext; 331204076Spjd 332204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 333204076Spjd assert(length > 0); 334204076Spjd 335204076Spjd modified = false; 336204076Spjd end = offset + length - 1; 337204076Spjd 338204076Spjd for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 339204076Spjd /* 340204076Spjd * If the number of pending writes goes down to 0, we have to 341204076Spjd * mark the extent as clean also in on-disk bitmap. 342204076Spjd * By returning true we inform the caller that on-disk bitmap 343204076Spjd * was modified and has to be flushed to disk. 344204076Spjd */ 345204076Spjd assert(amp->am_memtab[ext] > 0); 346204076Spjd assert(bit_test(amp->am_memmap, ext)); 347204076Spjd if (--amp->am_memtab[ext] == 0) { 348204076Spjd bit_clear(amp->am_memmap, ext); 349204076Spjd amp->am_ndirty--; 350223654Strociny if (keepdirty_find(amp, ext) == NULL) 351223654Strociny modified = true; 352204076Spjd } 353204076Spjd } 354204076Spjd 355204076Spjd return (modified); 356204076Spjd} 357204076Spjd 358204076Spjd/* 359204076Spjd * Function should be called after finishing synchronization of one extent. 360204076Spjd * It returns true if on-disk metadata should be updated. 361204076Spjd */ 362204076Spjdbool 363204076Spjdactivemap_extent_complete(struct activemap *amp, int extent) 364204076Spjd{ 365204076Spjd bool modified; 366204076Spjd int reqs; 367204076Spjd 368204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 369204076Spjd assert(extent >= 0 && extent < amp->am_nextents); 370204076Spjd 371204076Spjd modified = false; 372204076Spjd 373204076Spjd reqs = ext2reqs(amp, extent); 374204076Spjd assert(amp->am_memtab[extent] >= reqs); 375204076Spjd amp->am_memtab[extent] -= reqs; 376204076Spjd assert(bit_test(amp->am_memmap, extent)); 377204076Spjd if (amp->am_memtab[extent] == 0) { 378204076Spjd bit_clear(amp->am_memmap, extent); 379204076Spjd amp->am_ndirty--; 380204076Spjd modified = true; 381204076Spjd } 382204076Spjd 383204076Spjd return (modified); 384204076Spjd} 385204076Spjd 386204076Spjd/* 387204076Spjd * Function returns number of dirty regions. 388204076Spjd */ 389204076Spjduint64_t 390204076Spjdactivemap_ndirty(const struct activemap *amp) 391204076Spjd{ 392204076Spjd 393204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 394204076Spjd 395204076Spjd return (amp->am_ndirty); 396204076Spjd} 397204076Spjd 398204076Spjd/* 399204076Spjd * Function compare on-disk bitmap and in-memory bitmap and returns true if 400204076Spjd * they differ and should be flushed to the disk. 401204076Spjd */ 402204076Spjdbool 403204076Spjdactivemap_differ(const struct activemap *amp) 404204076Spjd{ 405204076Spjd 406204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 407204076Spjd 408204076Spjd return (memcmp(amp->am_diskmap, amp->am_memmap, 409204076Spjd amp->am_mapsize) != 0); 410204076Spjd} 411204076Spjd 412204076Spjd/* 413204076Spjd * Function returns number of bytes used by bitmap. 414204076Spjd */ 415204076Spjdsize_t 416204076Spjdactivemap_size(const struct activemap *amp) 417204076Spjd{ 418204076Spjd 419204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 420204076Spjd 421204076Spjd return (amp->am_mapsize); 422204076Spjd} 423204076Spjd 424204076Spjd/* 425204076Spjd * Function returns number of bytes needed for storing on-disk bitmap. 426204076Spjd * This is the same as activemap_size(), but rounded up to sector size. 427204076Spjd */ 428204076Spjdsize_t 429204076Spjdactivemap_ondisk_size(const struct activemap *amp) 430204076Spjd{ 431204076Spjd 432204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 433204076Spjd 434204076Spjd return (amp->am_diskmapsize); 435204076Spjd} 436204076Spjd 437204076Spjd/* 438204076Spjd * Function copies the given buffer read from disk to the internal bitmap. 439204076Spjd */ 440204076Spjdvoid 441204076Spjdactivemap_copyin(struct activemap *amp, const unsigned char *buf, size_t size) 442204076Spjd{ 443204076Spjd int ext; 444204076Spjd 445204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 446204076Spjd assert(size >= amp->am_mapsize); 447204076Spjd 448204076Spjd memcpy(amp->am_diskmap, buf, amp->am_mapsize); 449204076Spjd memcpy(amp->am_memmap, buf, amp->am_mapsize); 450204076Spjd memcpy(amp->am_syncmap, buf, amp->am_mapsize); 451204076Spjd 452204076Spjd bit_ffs(amp->am_memmap, amp->am_nextents, &ext); 453204076Spjd if (ext == -1) { 454204076Spjd /* There are no dirty extents, so we can leave now. */ 455204076Spjd return; 456204076Spjd } 457204076Spjd /* 458204076Spjd * Set synchronization offset to the first dirty extent. 459204076Spjd */ 460204076Spjd activemap_sync_rewind(amp); 461204076Spjd /* 462204076Spjd * We have dirty extents and we want them to stay that way until 463204076Spjd * we synchronize, so we set number of pending writes to number 464204076Spjd * of requests needed to synchronize one extent. 465204076Spjd */ 466204076Spjd amp->am_ndirty = 0; 467204076Spjd for (; ext < amp->am_nextents; ext++) { 468204076Spjd if (bit_test(amp->am_memmap, ext)) { 469204076Spjd amp->am_memtab[ext] = ext2reqs(amp, ext); 470204076Spjd amp->am_ndirty++; 471204076Spjd } 472204076Spjd } 473204076Spjd} 474204076Spjd 475204076Spjd/* 476220521Strociny * Function merges the given bitmap with existing one. 477204076Spjd */ 478204076Spjdvoid 479204076Spjdactivemap_merge(struct activemap *amp, const unsigned char *buf, size_t size) 480204076Spjd{ 481204076Spjd bitstr_t *remmap = __DECONST(bitstr_t *, buf); 482204076Spjd int ext; 483204076Spjd 484204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 485204076Spjd assert(size >= amp->am_mapsize); 486204076Spjd 487204076Spjd bit_ffs(remmap, amp->am_nextents, &ext); 488204076Spjd if (ext == -1) { 489204076Spjd /* There are no dirty extents, so we can leave now. */ 490204076Spjd return; 491204076Spjd } 492204076Spjd /* 493204076Spjd * We have dirty extents and we want them to stay that way until 494204076Spjd * we synchronize, so we set number of pending writes to number 495204076Spjd * of requests needed to synchronize one extent. 496204076Spjd */ 497204076Spjd for (; ext < amp->am_nextents; ext++) { 498204076Spjd /* Local extent already dirty. */ 499204076Spjd if (bit_test(amp->am_syncmap, ext)) 500204076Spjd continue; 501204076Spjd /* Remote extent isn't dirty. */ 502204076Spjd if (!bit_test(remmap, ext)) 503204076Spjd continue; 504204076Spjd bit_set(amp->am_syncmap, ext); 505204076Spjd bit_set(amp->am_memmap, ext); 506204076Spjd bit_set(amp->am_diskmap, ext); 507204076Spjd if (amp->am_memtab[ext] == 0) 508204076Spjd amp->am_ndirty++; 509204076Spjd amp->am_memtab[ext] = ext2reqs(amp, ext); 510204076Spjd } 511204076Spjd /* 512204076Spjd * Set synchronization offset to the first dirty extent. 513204076Spjd */ 514204076Spjd activemap_sync_rewind(amp); 515204076Spjd} 516204076Spjd 517204076Spjd/* 518204076Spjd * Function returns pointer to internal bitmap that should be written to disk. 519204076Spjd */ 520204076Spjdconst unsigned char * 521204076Spjdactivemap_bitmap(struct activemap *amp, size_t *sizep) 522204076Spjd{ 523204076Spjd 524204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 525204076Spjd 526204076Spjd if (sizep != NULL) 527204076Spjd *sizep = amp->am_diskmapsize; 528204076Spjd memcpy(amp->am_diskmap, amp->am_memmap, amp->am_mapsize); 529204076Spjd keepdirty_fill(amp); 530204076Spjd return ((const unsigned char *)amp->am_diskmap); 531204076Spjd} 532204076Spjd 533204076Spjd/* 534204076Spjd * Function calculates size needed to store bitmap on disk. 535204076Spjd */ 536204076Spjdsize_t 537204076Spjdactivemap_calc_ondisk_size(uint64_t mediasize, uint32_t extentsize, 538204076Spjd uint32_t sectorsize) 539204076Spjd{ 540204076Spjd uint64_t nextents, mapsize; 541204076Spjd 542204076Spjd assert(mediasize > 0); 543204076Spjd assert(extentsize > 0); 544204076Spjd assert(powerof2(extentsize)); 545204076Spjd assert(sectorsize > 0); 546204076Spjd assert(powerof2(sectorsize)); 547204076Spjd 548204076Spjd nextents = ((mediasize - 1) / extentsize) + 1; 549204076Spjd mapsize = sizeof(bitstr_t) * bitstr_size(nextents); 550204076Spjd return (roundup2(mapsize, sectorsize)); 551204076Spjd} 552204076Spjd 553204076Spjd/* 554204076Spjd * Set synchronization offset to the first dirty extent. 555204076Spjd */ 556204076Spjdvoid 557204076Spjdactivemap_sync_rewind(struct activemap *amp) 558204076Spjd{ 559204076Spjd int ext; 560204076Spjd 561204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 562204076Spjd 563204076Spjd bit_ffs(amp->am_syncmap, amp->am_nextents, &ext); 564204076Spjd if (ext == -1) { 565204076Spjd /* There are no extents to synchronize. */ 566204076Spjd amp->am_syncoff = -2; 567204076Spjd return; 568204076Spjd } 569204076Spjd /* 570204076Spjd * Mark that we want to start synchronization from the begining. 571204076Spjd */ 572204076Spjd amp->am_syncoff = -1; 573204076Spjd} 574204076Spjd 575204076Spjd/* 576204076Spjd * Return next offset of where we should synchronize. 577204076Spjd */ 578204076Spjdoff_t 579204076Spjdactivemap_sync_offset(struct activemap *amp, off_t *lengthp, int *syncextp) 580204076Spjd{ 581204076Spjd off_t syncoff, left; 582204076Spjd int ext; 583204076Spjd 584204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 585204076Spjd assert(lengthp != NULL); 586204076Spjd assert(syncextp != NULL); 587204076Spjd 588204076Spjd *syncextp = -1; 589204076Spjd 590204076Spjd if (amp->am_syncoff == -2) 591204076Spjd return (-1); 592204076Spjd 593204076Spjd if (amp->am_syncoff >= 0 && 594204076Spjd (amp->am_syncoff + MAXPHYS >= amp->am_mediasize || 595204076Spjd off2ext(amp, amp->am_syncoff) != 596204076Spjd off2ext(amp, amp->am_syncoff + MAXPHYS))) { 597204076Spjd /* 598204076Spjd * We are about to change extent, so mark previous one as clean. 599204076Spjd */ 600204076Spjd ext = off2ext(amp, amp->am_syncoff); 601204076Spjd bit_clear(amp->am_syncmap, ext); 602204076Spjd *syncextp = ext; 603204076Spjd amp->am_syncoff = -1; 604204076Spjd } 605204076Spjd 606204076Spjd if (amp->am_syncoff == -1) { 607204076Spjd /* 608204076Spjd * Let's find first extent to synchronize. 609204076Spjd */ 610204076Spjd bit_ffs(amp->am_syncmap, amp->am_nextents, &ext); 611204076Spjd if (ext == -1) { 612204076Spjd amp->am_syncoff = -2; 613204076Spjd return (-1); 614204076Spjd } 615204076Spjd amp->am_syncoff = ext2off(amp, ext); 616204076Spjd } else { 617204076Spjd /* 618204076Spjd * We don't change extent, so just increase offset. 619204076Spjd */ 620204076Spjd amp->am_syncoff += MAXPHYS; 621204076Spjd if (amp->am_syncoff >= amp->am_mediasize) { 622204076Spjd amp->am_syncoff = -2; 623204076Spjd return (-1); 624204076Spjd } 625204076Spjd } 626204076Spjd 627204076Spjd syncoff = amp->am_syncoff; 628204076Spjd left = ext2off(amp, off2ext(amp, syncoff)) + 629204076Spjd amp->am_extentsize - syncoff; 630204076Spjd if (syncoff + left > amp->am_mediasize) 631204076Spjd left = amp->am_mediasize - syncoff; 632204076Spjd if (left > MAXPHYS) 633204076Spjd left = MAXPHYS; 634204076Spjd 635204076Spjd assert(left >= 0 && left <= MAXPHYS); 636204076Spjd assert(syncoff >= 0 && syncoff < amp->am_mediasize); 637204076Spjd assert(syncoff + left >= 0 && syncoff + left <= amp->am_mediasize); 638204076Spjd 639204076Spjd *lengthp = left; 640204076Spjd return (syncoff); 641204076Spjd} 642204076Spjd 643204076Spjd/* 644204076Spjd * Mark extent(s) containing the given region for synchronization. 645204076Spjd * Most likely one of the components is unavailable. 646204076Spjd */ 647204076Spjdbool 648204076Spjdactivemap_need_sync(struct activemap *amp, off_t offset, off_t length) 649204076Spjd{ 650204076Spjd bool modified; 651204076Spjd off_t end; 652204076Spjd int ext; 653204076Spjd 654204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 655204076Spjd 656204076Spjd modified = false; 657204076Spjd end = offset + length - 1; 658204076Spjd 659204076Spjd for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 660204076Spjd if (bit_test(amp->am_syncmap, ext)) { 661204076Spjd /* Already marked for synchronization. */ 662204076Spjd assert(bit_test(amp->am_memmap, ext)); 663204076Spjd continue; 664204076Spjd } 665204076Spjd bit_set(amp->am_syncmap, ext); 666204076Spjd if (!bit_test(amp->am_memmap, ext)) { 667204076Spjd bit_set(amp->am_memmap, ext); 668204076Spjd amp->am_ndirty++; 669204076Spjd } 670204076Spjd amp->am_memtab[ext] += ext2reqs(amp, ext); 671204076Spjd modified = true; 672204076Spjd } 673204076Spjd 674204076Spjd return (modified); 675204076Spjd} 676204076Spjd 677204076Spjdvoid 678204076Spjdactivemap_dump(const struct activemap *amp) 679204076Spjd{ 680204076Spjd int bit; 681204076Spjd 682204076Spjd printf("M: "); 683204076Spjd for (bit = 0; bit < amp->am_nextents; bit++) 684204076Spjd printf("%d", bit_test(amp->am_memmap, bit) ? 1 : 0); 685204076Spjd printf("\n"); 686204076Spjd printf("D: "); 687204076Spjd for (bit = 0; bit < amp->am_nextents; bit++) 688204076Spjd printf("%d", bit_test(amp->am_diskmap, bit) ? 1 : 0); 689204076Spjd printf("\n"); 690204076Spjd printf("S: "); 691204076Spjd for (bit = 0; bit < amp->am_nextents; bit++) 692204076Spjd printf("%d", bit_test(amp->am_syncmap, bit) ? 1 : 0); 693204076Spjd printf("\n"); 694204076Spjd} 695