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