activemap.c revision 219864
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 219864 2011-03-22 10:39:34Z pjd $"); 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 208204076Spjdstatic void 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); 220204076Spjd return; 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 } 241204076Spjd} 242204076Spjd 243204076Spjdstatic void 244204076Spjdkeepdirty_fill(struct activemap *amp) 245204076Spjd{ 246204076Spjd struct keepdirty *kd; 247204076Spjd 248204076Spjd TAILQ_FOREACH(kd, &->am_keepdirty, kd_next) 249204076Spjd bit_set(amp->am_diskmap, kd->kd_extent); 250204076Spjd} 251204076Spjd 252204076Spjdstatic void 253204076Spjdkeepdirty_free(struct activemap *amp) 254204076Spjd{ 255204076Spjd struct keepdirty *kd; 256204076Spjd 257204076Spjd while ((kd = TAILQ_FIRST(&->am_keepdirty)) != NULL) { 258204076Spjd TAILQ_REMOVE(&->am_keepdirty, kd, kd_next); 259204076Spjd amp->am_nkeepdirty--; 260204076Spjd free(kd); 261204076Spjd } 262204076Spjd assert(amp->am_nkeepdirty == 0); 263204076Spjd} 264204076Spjd 265204076Spjd/* 266204076Spjd * Function frees resources allocated by activemap_init() function. 267204076Spjd */ 268204076Spjdvoid 269204076Spjdactivemap_free(struct activemap *amp) 270204076Spjd{ 271204076Spjd 272204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 273204076Spjd 274204076Spjd amp->am_magic = 0; 275204076Spjd 276204076Spjd keepdirty_free(amp); 277204076Spjd free(amp->am_memtab); 278204076Spjd free(amp->am_diskmap); 279204076Spjd free(amp->am_memmap); 280204076Spjd free(amp->am_syncmap); 281204076Spjd} 282204076Spjd 283204076Spjd/* 284204076Spjd * Function should be called before we handle write requests. It updates 285204076Spjd * internal structures and returns true if on-disk metadata should be updated. 286204076Spjd */ 287204076Spjdbool 288204076Spjdactivemap_write_start(struct activemap *amp, off_t offset, off_t length) 289204076Spjd{ 290204076Spjd bool modified; 291204076Spjd off_t end; 292204076Spjd int ext; 293204076Spjd 294204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 295204076Spjd assert(length > 0); 296204076Spjd 297204076Spjd modified = false; 298204076Spjd end = offset + length - 1; 299204076Spjd 300204076Spjd for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 301204076Spjd /* 302204076Spjd * If the number of pending writes is increased from 0, 303204076Spjd * we have to mark the extent as dirty also in on-disk bitmap. 304204076Spjd * By returning true we inform the caller that on-disk bitmap 305204076Spjd * was modified and has to be flushed to disk. 306204076Spjd */ 307204076Spjd if (amp->am_memtab[ext]++ == 0) { 308204076Spjd assert(!bit_test(amp->am_memmap, ext)); 309204076Spjd bit_set(amp->am_memmap, ext); 310204076Spjd amp->am_ndirty++; 311204076Spjd modified = true; 312204076Spjd } 313204076Spjd keepdirty_add(amp, ext); 314204076Spjd } 315204076Spjd 316204076Spjd return (modified); 317204076Spjd} 318204076Spjd 319204076Spjd/* 320204076Spjd * Function should be called after receiving write confirmation. It updates 321204076Spjd * internal structures and returns true if on-disk metadata should be updated. 322204076Spjd */ 323204076Spjdbool 324204076Spjdactivemap_write_complete(struct activemap *amp, off_t offset, off_t length) 325204076Spjd{ 326204076Spjd bool modified; 327204076Spjd off_t end; 328204076Spjd int ext; 329204076Spjd 330204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 331204076Spjd assert(length > 0); 332204076Spjd 333204076Spjd modified = false; 334204076Spjd end = offset + length - 1; 335204076Spjd 336204076Spjd for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 337204076Spjd /* 338204076Spjd * If the number of pending writes goes down to 0, we have to 339204076Spjd * mark the extent as clean also in on-disk bitmap. 340204076Spjd * By returning true we inform the caller that on-disk bitmap 341204076Spjd * was modified and has to be flushed to disk. 342204076Spjd */ 343204076Spjd assert(amp->am_memtab[ext] > 0); 344204076Spjd assert(bit_test(amp->am_memmap, ext)); 345204076Spjd if (--amp->am_memtab[ext] == 0) { 346204076Spjd bit_clear(amp->am_memmap, ext); 347204076Spjd amp->am_ndirty--; 348204076Spjd modified = true; 349204076Spjd } 350204076Spjd } 351204076Spjd 352204076Spjd return (modified); 353204076Spjd} 354204076Spjd 355204076Spjd/* 356204076Spjd * Function should be called after finishing synchronization of one extent. 357204076Spjd * It returns true if on-disk metadata should be updated. 358204076Spjd */ 359204076Spjdbool 360204076Spjdactivemap_extent_complete(struct activemap *amp, int extent) 361204076Spjd{ 362204076Spjd bool modified; 363204076Spjd int reqs; 364204076Spjd 365204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 366204076Spjd assert(extent >= 0 && extent < amp->am_nextents); 367204076Spjd 368204076Spjd modified = false; 369204076Spjd 370204076Spjd reqs = ext2reqs(amp, extent); 371204076Spjd assert(amp->am_memtab[extent] >= reqs); 372204076Spjd amp->am_memtab[extent] -= reqs; 373204076Spjd assert(bit_test(amp->am_memmap, extent)); 374204076Spjd if (amp->am_memtab[extent] == 0) { 375204076Spjd bit_clear(amp->am_memmap, extent); 376204076Spjd amp->am_ndirty--; 377204076Spjd modified = true; 378204076Spjd } 379204076Spjd 380204076Spjd return (modified); 381204076Spjd} 382204076Spjd 383204076Spjd/* 384204076Spjd * Function returns number of dirty regions. 385204076Spjd */ 386204076Spjduint64_t 387204076Spjdactivemap_ndirty(const struct activemap *amp) 388204076Spjd{ 389204076Spjd 390204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 391204076Spjd 392204076Spjd return (amp->am_ndirty); 393204076Spjd} 394204076Spjd 395204076Spjd/* 396204076Spjd * Function compare on-disk bitmap and in-memory bitmap and returns true if 397204076Spjd * they differ and should be flushed to the disk. 398204076Spjd */ 399204076Spjdbool 400204076Spjdactivemap_differ(const struct activemap *amp) 401204076Spjd{ 402204076Spjd 403204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 404204076Spjd 405204076Spjd return (memcmp(amp->am_diskmap, amp->am_memmap, 406204076Spjd amp->am_mapsize) != 0); 407204076Spjd} 408204076Spjd 409204076Spjd/* 410204076Spjd * Function returns number of bytes used by bitmap. 411204076Spjd */ 412204076Spjdsize_t 413204076Spjdactivemap_size(const struct activemap *amp) 414204076Spjd{ 415204076Spjd 416204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 417204076Spjd 418204076Spjd return (amp->am_mapsize); 419204076Spjd} 420204076Spjd 421204076Spjd/* 422204076Spjd * Function returns number of bytes needed for storing on-disk bitmap. 423204076Spjd * This is the same as activemap_size(), but rounded up to sector size. 424204076Spjd */ 425204076Spjdsize_t 426204076Spjdactivemap_ondisk_size(const struct activemap *amp) 427204076Spjd{ 428204076Spjd 429204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 430204076Spjd 431204076Spjd return (amp->am_diskmapsize); 432204076Spjd} 433204076Spjd 434204076Spjd/* 435204076Spjd * Function copies the given buffer read from disk to the internal bitmap. 436204076Spjd */ 437204076Spjdvoid 438204076Spjdactivemap_copyin(struct activemap *amp, const unsigned char *buf, size_t size) 439204076Spjd{ 440204076Spjd int ext; 441204076Spjd 442204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 443204076Spjd assert(size >= amp->am_mapsize); 444204076Spjd 445204076Spjd memcpy(amp->am_diskmap, buf, amp->am_mapsize); 446204076Spjd memcpy(amp->am_memmap, buf, amp->am_mapsize); 447204076Spjd memcpy(amp->am_syncmap, buf, amp->am_mapsize); 448204076Spjd 449204076Spjd bit_ffs(amp->am_memmap, amp->am_nextents, &ext); 450204076Spjd if (ext == -1) { 451204076Spjd /* There are no dirty extents, so we can leave now. */ 452204076Spjd return; 453204076Spjd } 454204076Spjd /* 455204076Spjd * Set synchronization offset to the first dirty extent. 456204076Spjd */ 457204076Spjd activemap_sync_rewind(amp); 458204076Spjd /* 459204076Spjd * We have dirty extents and we want them to stay that way until 460204076Spjd * we synchronize, so we set number of pending writes to number 461204076Spjd * of requests needed to synchronize one extent. 462204076Spjd */ 463204076Spjd amp->am_ndirty = 0; 464204076Spjd for (; ext < amp->am_nextents; ext++) { 465204076Spjd if (bit_test(amp->am_memmap, ext)) { 466204076Spjd amp->am_memtab[ext] = ext2reqs(amp, ext); 467204076Spjd amp->am_ndirty++; 468204076Spjd } 469204076Spjd } 470204076Spjd} 471204076Spjd 472204076Spjd/* 473204076Spjd * Function merges the given bitmap with existng one. 474204076Spjd */ 475204076Spjdvoid 476204076Spjdactivemap_merge(struct activemap *amp, const unsigned char *buf, size_t size) 477204076Spjd{ 478204076Spjd bitstr_t *remmap = __DECONST(bitstr_t *, buf); 479204076Spjd int ext; 480204076Spjd 481204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 482204076Spjd assert(size >= amp->am_mapsize); 483204076Spjd 484204076Spjd bit_ffs(remmap, amp->am_nextents, &ext); 485204076Spjd if (ext == -1) { 486204076Spjd /* There are no dirty extents, so we can leave now. */ 487204076Spjd return; 488204076Spjd } 489204076Spjd /* 490204076Spjd * We have dirty extents and we want them to stay that way until 491204076Spjd * we synchronize, so we set number of pending writes to number 492204076Spjd * of requests needed to synchronize one extent. 493204076Spjd */ 494204076Spjd for (; ext < amp->am_nextents; ext++) { 495204076Spjd /* Local extent already dirty. */ 496204076Spjd if (bit_test(amp->am_syncmap, ext)) 497204076Spjd continue; 498204076Spjd /* Remote extent isn't dirty. */ 499204076Spjd if (!bit_test(remmap, ext)) 500204076Spjd continue; 501204076Spjd bit_set(amp->am_syncmap, ext); 502204076Spjd bit_set(amp->am_memmap, ext); 503204076Spjd bit_set(amp->am_diskmap, ext); 504204076Spjd if (amp->am_memtab[ext] == 0) 505204076Spjd amp->am_ndirty++; 506204076Spjd amp->am_memtab[ext] = ext2reqs(amp, ext); 507204076Spjd } 508204076Spjd /* 509204076Spjd * Set synchronization offset to the first dirty extent. 510204076Spjd */ 511204076Spjd activemap_sync_rewind(amp); 512204076Spjd} 513204076Spjd 514204076Spjd/* 515204076Spjd * Function returns pointer to internal bitmap that should be written to disk. 516204076Spjd */ 517204076Spjdconst unsigned char * 518204076Spjdactivemap_bitmap(struct activemap *amp, size_t *sizep) 519204076Spjd{ 520204076Spjd 521204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 522204076Spjd 523204076Spjd if (sizep != NULL) 524204076Spjd *sizep = amp->am_diskmapsize; 525204076Spjd memcpy(amp->am_diskmap, amp->am_memmap, amp->am_mapsize); 526204076Spjd keepdirty_fill(amp); 527204076Spjd return ((const unsigned char *)amp->am_diskmap); 528204076Spjd} 529204076Spjd 530204076Spjd/* 531204076Spjd * Function calculates size needed to store bitmap on disk. 532204076Spjd */ 533204076Spjdsize_t 534204076Spjdactivemap_calc_ondisk_size(uint64_t mediasize, uint32_t extentsize, 535204076Spjd uint32_t sectorsize) 536204076Spjd{ 537204076Spjd uint64_t nextents, mapsize; 538204076Spjd 539204076Spjd assert(mediasize > 0); 540204076Spjd assert(extentsize > 0); 541204076Spjd assert(powerof2(extentsize)); 542204076Spjd assert(sectorsize > 0); 543204076Spjd assert(powerof2(sectorsize)); 544204076Spjd 545204076Spjd nextents = ((mediasize - 1) / extentsize) + 1; 546204076Spjd mapsize = sizeof(bitstr_t) * bitstr_size(nextents); 547204076Spjd return (roundup2(mapsize, sectorsize)); 548204076Spjd} 549204076Spjd 550204076Spjd/* 551204076Spjd * Set synchronization offset to the first dirty extent. 552204076Spjd */ 553204076Spjdvoid 554204076Spjdactivemap_sync_rewind(struct activemap *amp) 555204076Spjd{ 556204076Spjd int ext; 557204076Spjd 558204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 559204076Spjd 560204076Spjd bit_ffs(amp->am_syncmap, amp->am_nextents, &ext); 561204076Spjd if (ext == -1) { 562204076Spjd /* There are no extents to synchronize. */ 563204076Spjd amp->am_syncoff = -2; 564204076Spjd return; 565204076Spjd } 566204076Spjd /* 567204076Spjd * Mark that we want to start synchronization from the begining. 568204076Spjd */ 569204076Spjd amp->am_syncoff = -1; 570204076Spjd} 571204076Spjd 572204076Spjd/* 573204076Spjd * Return next offset of where we should synchronize. 574204076Spjd */ 575204076Spjdoff_t 576204076Spjdactivemap_sync_offset(struct activemap *amp, off_t *lengthp, int *syncextp) 577204076Spjd{ 578204076Spjd off_t syncoff, left; 579204076Spjd int ext; 580204076Spjd 581204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 582204076Spjd assert(lengthp != NULL); 583204076Spjd assert(syncextp != NULL); 584204076Spjd 585204076Spjd *syncextp = -1; 586204076Spjd 587204076Spjd if (amp->am_syncoff == -2) 588204076Spjd return (-1); 589204076Spjd 590204076Spjd if (amp->am_syncoff >= 0 && 591204076Spjd (amp->am_syncoff + MAXPHYS >= amp->am_mediasize || 592204076Spjd off2ext(amp, amp->am_syncoff) != 593204076Spjd off2ext(amp, amp->am_syncoff + MAXPHYS))) { 594204076Spjd /* 595204076Spjd * We are about to change extent, so mark previous one as clean. 596204076Spjd */ 597204076Spjd ext = off2ext(amp, amp->am_syncoff); 598204076Spjd bit_clear(amp->am_syncmap, ext); 599204076Spjd *syncextp = ext; 600204076Spjd amp->am_syncoff = -1; 601204076Spjd } 602204076Spjd 603204076Spjd if (amp->am_syncoff == -1) { 604204076Spjd /* 605204076Spjd * Let's find first extent to synchronize. 606204076Spjd */ 607204076Spjd bit_ffs(amp->am_syncmap, amp->am_nextents, &ext); 608204076Spjd if (ext == -1) { 609204076Spjd amp->am_syncoff = -2; 610204076Spjd return (-1); 611204076Spjd } 612204076Spjd amp->am_syncoff = ext2off(amp, ext); 613204076Spjd } else { 614204076Spjd /* 615204076Spjd * We don't change extent, so just increase offset. 616204076Spjd */ 617204076Spjd amp->am_syncoff += MAXPHYS; 618204076Spjd if (amp->am_syncoff >= amp->am_mediasize) { 619204076Spjd amp->am_syncoff = -2; 620204076Spjd return (-1); 621204076Spjd } 622204076Spjd } 623204076Spjd 624204076Spjd syncoff = amp->am_syncoff; 625204076Spjd left = ext2off(amp, off2ext(amp, syncoff)) + 626204076Spjd amp->am_extentsize - syncoff; 627204076Spjd if (syncoff + left > amp->am_mediasize) 628204076Spjd left = amp->am_mediasize - syncoff; 629204076Spjd if (left > MAXPHYS) 630204076Spjd left = MAXPHYS; 631204076Spjd 632204076Spjd assert(left >= 0 && left <= MAXPHYS); 633204076Spjd assert(syncoff >= 0 && syncoff < amp->am_mediasize); 634204076Spjd assert(syncoff + left >= 0 && syncoff + left <= amp->am_mediasize); 635204076Spjd 636204076Spjd *lengthp = left; 637204076Spjd return (syncoff); 638204076Spjd} 639204076Spjd 640204076Spjd/* 641204076Spjd * Mark extent(s) containing the given region for synchronization. 642204076Spjd * Most likely one of the components is unavailable. 643204076Spjd */ 644204076Spjdbool 645204076Spjdactivemap_need_sync(struct activemap *amp, off_t offset, off_t length) 646204076Spjd{ 647204076Spjd bool modified; 648204076Spjd off_t end; 649204076Spjd int ext; 650204076Spjd 651204076Spjd assert(amp->am_magic == ACTIVEMAP_MAGIC); 652204076Spjd 653204076Spjd modified = false; 654204076Spjd end = offset + length - 1; 655204076Spjd 656204076Spjd for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 657204076Spjd if (bit_test(amp->am_syncmap, ext)) { 658204076Spjd /* Already marked for synchronization. */ 659204076Spjd assert(bit_test(amp->am_memmap, ext)); 660204076Spjd continue; 661204076Spjd } 662204076Spjd bit_set(amp->am_syncmap, ext); 663204076Spjd if (!bit_test(amp->am_memmap, ext)) { 664204076Spjd bit_set(amp->am_memmap, ext); 665204076Spjd amp->am_ndirty++; 666204076Spjd } 667204076Spjd amp->am_memtab[ext] += ext2reqs(amp, ext); 668204076Spjd modified = true; 669204076Spjd } 670204076Spjd 671204076Spjd return (modified); 672204076Spjd} 673204076Spjd 674204076Spjdvoid 675204076Spjdactivemap_dump(const struct activemap *amp) 676204076Spjd{ 677204076Spjd int bit; 678204076Spjd 679204076Spjd printf("M: "); 680204076Spjd for (bit = 0; bit < amp->am_nextents; bit++) 681204076Spjd printf("%d", bit_test(amp->am_memmap, bit) ? 1 : 0); 682204076Spjd printf("\n"); 683204076Spjd printf("D: "); 684204076Spjd for (bit = 0; bit < amp->am_nextents; bit++) 685204076Spjd printf("%d", bit_test(amp->am_diskmap, bit) ? 1 : 0); 686204076Spjd printf("\n"); 687204076Spjd printf("S: "); 688204076Spjd for (bit = 0; bit < amp->am_nextents; bit++) 689204076Spjd printf("%d", bit_test(amp->am_syncmap, bit) ? 1 : 0); 690204076Spjd printf("\n"); 691204076Spjd} 692