132115b10SPawel Jakub Dawidek /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro F. Giffuni * 432115b10SPawel Jakub Dawidek * Copyright (c) 2009-2010 The FreeBSD Foundation 532115b10SPawel Jakub Dawidek * 632115b10SPawel Jakub Dawidek * This software was developed by Pawel Jakub Dawidek under sponsorship from 732115b10SPawel Jakub Dawidek * the FreeBSD Foundation. 832115b10SPawel Jakub Dawidek * 932115b10SPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 1032115b10SPawel Jakub Dawidek * modification, are permitted provided that the following conditions 1132115b10SPawel Jakub Dawidek * are met: 1232115b10SPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 1332115b10SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 1432115b10SPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 1532115b10SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 1632115b10SPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 1732115b10SPawel Jakub Dawidek * 1832115b10SPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1932115b10SPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2032115b10SPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2132115b10SPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 2232115b10SPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2332115b10SPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2432115b10SPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2532115b10SPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2632115b10SPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2732115b10SPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2832115b10SPawel Jakub Dawidek * SUCH DAMAGE. 2932115b10SPawel Jakub Dawidek */ 3032115b10SPawel Jakub Dawidek 3132115b10SPawel Jakub Dawidek #include <sys/param.h> /* powerof2() */ 3232115b10SPawel Jakub Dawidek #include <sys/queue.h> 3332115b10SPawel Jakub Dawidek 3432115b10SPawel Jakub Dawidek #include <bitstring.h> 3532115b10SPawel Jakub Dawidek #include <errno.h> 3632115b10SPawel Jakub Dawidek #include <stdint.h> 3732115b10SPawel Jakub Dawidek #include <stdio.h> 3832115b10SPawel Jakub Dawidek #include <stdlib.h> 3932115b10SPawel Jakub Dawidek #include <string.h> 4032115b10SPawel Jakub Dawidek 41adf8002bSPawel Jakub Dawidek #include <pjdlog.h> 42adf8002bSPawel Jakub Dawidek 43adf8002bSPawel Jakub Dawidek #include "activemap.h" 44adf8002bSPawel Jakub Dawidek 45adf8002bSPawel Jakub Dawidek #ifndef PJDLOG_ASSERT 46adf8002bSPawel Jakub Dawidek #include <assert.h> 47adf8002bSPawel Jakub Dawidek #define PJDLOG_ASSERT(...) assert(__VA_ARGS__) 48adf8002bSPawel Jakub Dawidek #endif 4932115b10SPawel Jakub Dawidek 5032115b10SPawel Jakub Dawidek #define ACTIVEMAP_MAGIC 0xac71e4 5132115b10SPawel Jakub Dawidek struct activemap { 5232115b10SPawel Jakub Dawidek int am_magic; /* Magic value. */ 5332115b10SPawel Jakub Dawidek off_t am_mediasize; /* Media size in bytes. */ 5432115b10SPawel Jakub Dawidek uint32_t am_extentsize; /* Extent size in bytes, 5532115b10SPawel Jakub Dawidek must be power of 2. */ 5632115b10SPawel Jakub Dawidek uint8_t am_extentshift;/* 2 ^ extentbits == extentsize */ 5732115b10SPawel Jakub Dawidek int am_nextents; /* Number of extents. */ 5832115b10SPawel Jakub Dawidek size_t am_mapsize; /* Bitmap size in bytes. */ 5932115b10SPawel Jakub Dawidek uint16_t *am_memtab; /* An array that holds number of pending 6032115b10SPawel Jakub Dawidek writes per extent. */ 6132115b10SPawel Jakub Dawidek bitstr_t *am_diskmap; /* On-disk bitmap of dirty extents. */ 6232115b10SPawel Jakub Dawidek bitstr_t *am_memmap; /* In-memory bitmap of dirty extents. */ 6332115b10SPawel Jakub Dawidek size_t am_diskmapsize; /* Map size rounded up to sector size. */ 6432115b10SPawel Jakub Dawidek uint64_t am_ndirty; /* Number of dirty regions. */ 6532115b10SPawel Jakub Dawidek bitstr_t *am_syncmap; /* Bitmap of extents to sync. */ 6632115b10SPawel Jakub Dawidek off_t am_syncoff; /* Next synchronization offset. */ 6732115b10SPawel Jakub Dawidek TAILQ_HEAD(skeepdirty, keepdirty) am_keepdirty; /* List of extents that 6832115b10SPawel Jakub Dawidek we keep dirty to reduce bitmap 6932115b10SPawel Jakub Dawidek updates. */ 7032115b10SPawel Jakub Dawidek int am_nkeepdirty; /* Number of am_keepdirty elements. */ 7132115b10SPawel Jakub Dawidek int am_nkeepdirty_limit; /* Maximum number of am_keepdirty 7232115b10SPawel Jakub Dawidek elements. */ 7332115b10SPawel Jakub Dawidek }; 7432115b10SPawel Jakub Dawidek 7532115b10SPawel Jakub Dawidek struct keepdirty { 7632115b10SPawel Jakub Dawidek int kd_extent; 7732115b10SPawel Jakub Dawidek TAILQ_ENTRY(keepdirty) kd_next; 7832115b10SPawel Jakub Dawidek }; 7932115b10SPawel Jakub Dawidek 8032115b10SPawel Jakub Dawidek /* 8132115b10SPawel Jakub Dawidek * Helper function taken from sys/systm.h to calculate extentshift. 8232115b10SPawel Jakub Dawidek */ 8332115b10SPawel Jakub Dawidek static uint32_t 8432115b10SPawel Jakub Dawidek bitcount32(uint32_t x) 8532115b10SPawel Jakub Dawidek { 8632115b10SPawel Jakub Dawidek 8732115b10SPawel Jakub Dawidek x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 8832115b10SPawel Jakub Dawidek x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 8932115b10SPawel Jakub Dawidek x = (x + (x >> 4)) & 0x0f0f0f0f; 9032115b10SPawel Jakub Dawidek x = (x + (x >> 8)); 9132115b10SPawel Jakub Dawidek x = (x + (x >> 16)) & 0x000000ff; 9232115b10SPawel Jakub Dawidek return (x); 9332115b10SPawel Jakub Dawidek } 9432115b10SPawel Jakub Dawidek 9532115b10SPawel Jakub Dawidek static __inline int 9632115b10SPawel Jakub Dawidek off2ext(const struct activemap *amp, off_t offset) 9732115b10SPawel Jakub Dawidek { 9832115b10SPawel Jakub Dawidek int extent; 9932115b10SPawel Jakub Dawidek 100adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(offset >= 0 && offset < amp->am_mediasize); 10132115b10SPawel Jakub Dawidek extent = (offset >> amp->am_extentshift); 102adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(extent >= 0 && extent < amp->am_nextents); 10332115b10SPawel Jakub Dawidek return (extent); 10432115b10SPawel Jakub Dawidek } 10532115b10SPawel Jakub Dawidek 10632115b10SPawel Jakub Dawidek static __inline off_t 10732115b10SPawel Jakub Dawidek ext2off(const struct activemap *amp, int extent) 10832115b10SPawel Jakub Dawidek { 10932115b10SPawel Jakub Dawidek off_t offset; 11032115b10SPawel Jakub Dawidek 111adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(extent >= 0 && extent < amp->am_nextents); 11232115b10SPawel Jakub Dawidek offset = ((off_t)extent << amp->am_extentshift); 113adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(offset >= 0 && offset < amp->am_mediasize); 11432115b10SPawel Jakub Dawidek return (offset); 11532115b10SPawel Jakub Dawidek } 11632115b10SPawel Jakub Dawidek 11732115b10SPawel Jakub Dawidek /* 11832115b10SPawel Jakub Dawidek * Function calculates number of requests needed to synchronize the given 11932115b10SPawel Jakub Dawidek * extent. 12032115b10SPawel Jakub Dawidek */ 12132115b10SPawel Jakub Dawidek static __inline int 12232115b10SPawel Jakub Dawidek ext2reqs(const struct activemap *amp, int ext) 12332115b10SPawel Jakub Dawidek { 12432115b10SPawel Jakub Dawidek off_t left; 12532115b10SPawel Jakub Dawidek 12632115b10SPawel Jakub Dawidek if (ext < amp->am_nextents - 1) 12732115b10SPawel Jakub Dawidek return (((amp->am_extentsize - 1) / MAXPHYS) + 1); 12832115b10SPawel Jakub Dawidek 129adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(ext == amp->am_nextents - 1); 13032115b10SPawel Jakub Dawidek left = amp->am_mediasize % amp->am_extentsize; 13132115b10SPawel Jakub Dawidek if (left == 0) 13232115b10SPawel Jakub Dawidek left = amp->am_extentsize; 13332115b10SPawel Jakub Dawidek return (((left - 1) / MAXPHYS) + 1); 13432115b10SPawel Jakub Dawidek } 13532115b10SPawel Jakub Dawidek 13632115b10SPawel Jakub Dawidek /* 13732115b10SPawel Jakub Dawidek * Initialize activemap structure and allocate memory for internal needs. 13832115b10SPawel Jakub Dawidek * Function returns 0 on success and -1 if any of the allocations failed. 13932115b10SPawel Jakub Dawidek */ 14032115b10SPawel Jakub Dawidek int 14132115b10SPawel Jakub Dawidek activemap_init(struct activemap **ampp, uint64_t mediasize, uint32_t extentsize, 14232115b10SPawel Jakub Dawidek uint32_t sectorsize, uint32_t keepdirty) 14332115b10SPawel Jakub Dawidek { 14432115b10SPawel Jakub Dawidek struct activemap *amp; 14532115b10SPawel Jakub Dawidek 146adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(ampp != NULL); 147adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(mediasize > 0); 148adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(extentsize > 0); 149adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(powerof2(extentsize)); 150adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(sectorsize > 0); 151adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(powerof2(sectorsize)); 152adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(keepdirty > 0); 15332115b10SPawel Jakub Dawidek 15432115b10SPawel Jakub Dawidek amp = malloc(sizeof(*amp)); 15532115b10SPawel Jakub Dawidek if (amp == NULL) 15632115b10SPawel Jakub Dawidek return (-1); 15732115b10SPawel Jakub Dawidek 15832115b10SPawel Jakub Dawidek amp->am_mediasize = mediasize; 15932115b10SPawel Jakub Dawidek amp->am_nkeepdirty_limit = keepdirty; 16032115b10SPawel Jakub Dawidek amp->am_extentsize = extentsize; 16132115b10SPawel Jakub Dawidek amp->am_extentshift = bitcount32(extentsize - 1); 16232115b10SPawel Jakub Dawidek amp->am_nextents = ((mediasize - 1) / extentsize) + 1; 1638907f744SAlan Somers amp->am_mapsize = bitstr_size(amp->am_nextents); 16432115b10SPawel Jakub Dawidek amp->am_diskmapsize = roundup2(amp->am_mapsize, sectorsize); 16532115b10SPawel Jakub Dawidek amp->am_ndirty = 0; 16632115b10SPawel Jakub Dawidek amp->am_syncoff = -2; 16732115b10SPawel Jakub Dawidek TAILQ_INIT(&->am_keepdirty); 16832115b10SPawel Jakub Dawidek amp->am_nkeepdirty = 0; 16932115b10SPawel Jakub Dawidek 17032115b10SPawel Jakub Dawidek amp->am_memtab = calloc(amp->am_nextents, sizeof(amp->am_memtab[0])); 17132115b10SPawel Jakub Dawidek amp->am_diskmap = calloc(1, amp->am_diskmapsize); 17232115b10SPawel Jakub Dawidek amp->am_memmap = bit_alloc(amp->am_nextents); 17332115b10SPawel Jakub Dawidek amp->am_syncmap = bit_alloc(amp->am_nextents); 17432115b10SPawel Jakub Dawidek 17532115b10SPawel Jakub Dawidek /* 17632115b10SPawel Jakub Dawidek * Check to see if any of the allocations above failed. 17732115b10SPawel Jakub Dawidek */ 17832115b10SPawel Jakub Dawidek if (amp->am_memtab == NULL || amp->am_diskmap == NULL || 17932115b10SPawel Jakub Dawidek amp->am_memmap == NULL || amp->am_syncmap == NULL) { 18032115b10SPawel Jakub Dawidek if (amp->am_memtab != NULL) 18132115b10SPawel Jakub Dawidek free(amp->am_memtab); 18232115b10SPawel Jakub Dawidek if (amp->am_diskmap != NULL) 18332115b10SPawel Jakub Dawidek free(amp->am_diskmap); 18432115b10SPawel Jakub Dawidek if (amp->am_memmap != NULL) 18532115b10SPawel Jakub Dawidek free(amp->am_memmap); 18632115b10SPawel Jakub Dawidek if (amp->am_syncmap != NULL) 18732115b10SPawel Jakub Dawidek free(amp->am_syncmap); 18832115b10SPawel Jakub Dawidek amp->am_magic = 0; 18932115b10SPawel Jakub Dawidek free(amp); 19032115b10SPawel Jakub Dawidek errno = ENOMEM; 19132115b10SPawel Jakub Dawidek return (-1); 19232115b10SPawel Jakub Dawidek } 19332115b10SPawel Jakub Dawidek 19432115b10SPawel Jakub Dawidek amp->am_magic = ACTIVEMAP_MAGIC; 19532115b10SPawel Jakub Dawidek *ampp = amp; 19632115b10SPawel Jakub Dawidek 19732115b10SPawel Jakub Dawidek return (0); 19832115b10SPawel Jakub Dawidek } 19932115b10SPawel Jakub Dawidek 20032115b10SPawel Jakub Dawidek static struct keepdirty * 20132115b10SPawel Jakub Dawidek keepdirty_find(struct activemap *amp, int extent) 20232115b10SPawel Jakub Dawidek { 20332115b10SPawel Jakub Dawidek struct keepdirty *kd; 20432115b10SPawel Jakub Dawidek 20532115b10SPawel Jakub Dawidek TAILQ_FOREACH(kd, &->am_keepdirty, kd_next) { 20632115b10SPawel Jakub Dawidek if (kd->kd_extent == extent) 20732115b10SPawel Jakub Dawidek break; 20832115b10SPawel Jakub Dawidek } 20932115b10SPawel Jakub Dawidek return (kd); 21032115b10SPawel Jakub Dawidek } 21132115b10SPawel Jakub Dawidek 212aa64b2f4SMikolaj Golub static bool 21332115b10SPawel Jakub Dawidek keepdirty_add(struct activemap *amp, int extent) 21432115b10SPawel Jakub Dawidek { 21532115b10SPawel Jakub Dawidek struct keepdirty *kd; 21632115b10SPawel Jakub Dawidek 21732115b10SPawel Jakub Dawidek kd = keepdirty_find(amp, extent); 21832115b10SPawel Jakub Dawidek if (kd != NULL) { 21932115b10SPawel Jakub Dawidek /* 2204b85a12fSUlrich Spörlein * Only move element at the beginning. 22132115b10SPawel Jakub Dawidek */ 22232115b10SPawel Jakub Dawidek TAILQ_REMOVE(&->am_keepdirty, kd, kd_next); 22332115b10SPawel Jakub Dawidek TAILQ_INSERT_HEAD(&->am_keepdirty, kd, kd_next); 224aa64b2f4SMikolaj Golub return (false); 22532115b10SPawel Jakub Dawidek } 22632115b10SPawel Jakub Dawidek /* 22732115b10SPawel Jakub Dawidek * Add new element, but first remove the most unused one if 22832115b10SPawel Jakub Dawidek * we have too many. 22932115b10SPawel Jakub Dawidek */ 23032115b10SPawel Jakub Dawidek if (amp->am_nkeepdirty >= amp->am_nkeepdirty_limit) { 23132115b10SPawel Jakub Dawidek kd = TAILQ_LAST(&->am_keepdirty, skeepdirty); 232adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(kd != NULL); 23332115b10SPawel Jakub Dawidek TAILQ_REMOVE(&->am_keepdirty, kd, kd_next); 23432115b10SPawel Jakub Dawidek amp->am_nkeepdirty--; 235adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_nkeepdirty > 0); 23632115b10SPawel Jakub Dawidek } 23732115b10SPawel Jakub Dawidek if (kd == NULL) 23832115b10SPawel Jakub Dawidek kd = malloc(sizeof(*kd)); 23932115b10SPawel Jakub Dawidek /* We can ignore allocation failure. */ 24032115b10SPawel Jakub Dawidek if (kd != NULL) { 24132115b10SPawel Jakub Dawidek kd->kd_extent = extent; 24232115b10SPawel Jakub Dawidek amp->am_nkeepdirty++; 24332115b10SPawel Jakub Dawidek TAILQ_INSERT_HEAD(&->am_keepdirty, kd, kd_next); 24432115b10SPawel Jakub Dawidek } 245aa64b2f4SMikolaj Golub 246aa64b2f4SMikolaj Golub return (true); 24732115b10SPawel Jakub Dawidek } 24832115b10SPawel Jakub Dawidek 24932115b10SPawel Jakub Dawidek static void 25032115b10SPawel Jakub Dawidek keepdirty_fill(struct activemap *amp) 25132115b10SPawel Jakub Dawidek { 25232115b10SPawel Jakub Dawidek struct keepdirty *kd; 25332115b10SPawel Jakub Dawidek 25432115b10SPawel Jakub Dawidek TAILQ_FOREACH(kd, &->am_keepdirty, kd_next) 25532115b10SPawel Jakub Dawidek bit_set(amp->am_diskmap, kd->kd_extent); 25632115b10SPawel Jakub Dawidek } 25732115b10SPawel Jakub Dawidek 25832115b10SPawel Jakub Dawidek static void 25932115b10SPawel Jakub Dawidek keepdirty_free(struct activemap *amp) 26032115b10SPawel Jakub Dawidek { 26132115b10SPawel Jakub Dawidek struct keepdirty *kd; 26232115b10SPawel Jakub Dawidek 26332115b10SPawel Jakub Dawidek while ((kd = TAILQ_FIRST(&->am_keepdirty)) != NULL) { 26432115b10SPawel Jakub Dawidek TAILQ_REMOVE(&->am_keepdirty, kd, kd_next); 26532115b10SPawel Jakub Dawidek amp->am_nkeepdirty--; 26632115b10SPawel Jakub Dawidek free(kd); 26732115b10SPawel Jakub Dawidek } 268adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_nkeepdirty == 0); 26932115b10SPawel Jakub Dawidek } 27032115b10SPawel Jakub Dawidek 27132115b10SPawel Jakub Dawidek /* 27232115b10SPawel Jakub Dawidek * Function frees resources allocated by activemap_init() function. 27332115b10SPawel Jakub Dawidek */ 27432115b10SPawel Jakub Dawidek void 27532115b10SPawel Jakub Dawidek activemap_free(struct activemap *amp) 27632115b10SPawel Jakub Dawidek { 27732115b10SPawel Jakub Dawidek 278adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 27932115b10SPawel Jakub Dawidek 28032115b10SPawel Jakub Dawidek amp->am_magic = 0; 28132115b10SPawel Jakub Dawidek 28232115b10SPawel Jakub Dawidek keepdirty_free(amp); 28332115b10SPawel Jakub Dawidek free(amp->am_memtab); 28432115b10SPawel Jakub Dawidek free(amp->am_diskmap); 28532115b10SPawel Jakub Dawidek free(amp->am_memmap); 28632115b10SPawel Jakub Dawidek free(amp->am_syncmap); 28732115b10SPawel Jakub Dawidek } 28832115b10SPawel Jakub Dawidek 28932115b10SPawel Jakub Dawidek /* 29032115b10SPawel Jakub Dawidek * Function should be called before we handle write requests. It updates 29132115b10SPawel Jakub Dawidek * internal structures and returns true if on-disk metadata should be updated. 29232115b10SPawel Jakub Dawidek */ 29332115b10SPawel Jakub Dawidek bool 29432115b10SPawel Jakub Dawidek activemap_write_start(struct activemap *amp, off_t offset, off_t length) 29532115b10SPawel Jakub Dawidek { 29632115b10SPawel Jakub Dawidek bool modified; 29732115b10SPawel Jakub Dawidek off_t end; 29832115b10SPawel Jakub Dawidek int ext; 29932115b10SPawel Jakub Dawidek 300adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 301adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(length > 0); 30232115b10SPawel Jakub Dawidek 30332115b10SPawel Jakub Dawidek modified = false; 30432115b10SPawel Jakub Dawidek end = offset + length - 1; 30532115b10SPawel Jakub Dawidek 30632115b10SPawel Jakub Dawidek for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 30732115b10SPawel Jakub Dawidek /* 30832115b10SPawel Jakub Dawidek * If the number of pending writes is increased from 0, 30932115b10SPawel Jakub Dawidek * we have to mark the extent as dirty also in on-disk bitmap. 31032115b10SPawel Jakub Dawidek * By returning true we inform the caller that on-disk bitmap 31132115b10SPawel Jakub Dawidek * was modified and has to be flushed to disk. 31232115b10SPawel Jakub Dawidek */ 31332115b10SPawel Jakub Dawidek if (amp->am_memtab[ext]++ == 0) { 314adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(!bit_test(amp->am_memmap, ext)); 31532115b10SPawel Jakub Dawidek bit_set(amp->am_memmap, ext); 31632115b10SPawel Jakub Dawidek amp->am_ndirty++; 31732115b10SPawel Jakub Dawidek } 318aa64b2f4SMikolaj Golub if (keepdirty_add(amp, ext)) 319aa64b2f4SMikolaj Golub modified = true; 32032115b10SPawel Jakub Dawidek } 32132115b10SPawel Jakub Dawidek 32232115b10SPawel Jakub Dawidek return (modified); 32332115b10SPawel Jakub Dawidek } 32432115b10SPawel Jakub Dawidek 32532115b10SPawel Jakub Dawidek /* 32632115b10SPawel Jakub Dawidek * Function should be called after receiving write confirmation. It updates 32732115b10SPawel Jakub Dawidek * internal structures and returns true if on-disk metadata should be updated. 32832115b10SPawel Jakub Dawidek */ 32932115b10SPawel Jakub Dawidek bool 33032115b10SPawel Jakub Dawidek activemap_write_complete(struct activemap *amp, off_t offset, off_t length) 33132115b10SPawel Jakub Dawidek { 33232115b10SPawel Jakub Dawidek bool modified; 33332115b10SPawel Jakub Dawidek off_t end; 33432115b10SPawel Jakub Dawidek int ext; 33532115b10SPawel Jakub Dawidek 336adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 337adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(length > 0); 33832115b10SPawel Jakub Dawidek 33932115b10SPawel Jakub Dawidek modified = false; 34032115b10SPawel Jakub Dawidek end = offset + length - 1; 34132115b10SPawel Jakub Dawidek 34232115b10SPawel Jakub Dawidek for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 34332115b10SPawel Jakub Dawidek /* 34432115b10SPawel Jakub Dawidek * If the number of pending writes goes down to 0, we have to 34532115b10SPawel Jakub Dawidek * mark the extent as clean also in on-disk bitmap. 34632115b10SPawel Jakub Dawidek * By returning true we inform the caller that on-disk bitmap 34732115b10SPawel Jakub Dawidek * was modified and has to be flushed to disk. 34832115b10SPawel Jakub Dawidek */ 349adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_memtab[ext] > 0); 350adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(bit_test(amp->am_memmap, ext)); 35132115b10SPawel Jakub Dawidek if (--amp->am_memtab[ext] == 0) { 35232115b10SPawel Jakub Dawidek bit_clear(amp->am_memmap, ext); 35332115b10SPawel Jakub Dawidek amp->am_ndirty--; 354aa64b2f4SMikolaj Golub if (keepdirty_find(amp, ext) == NULL) 35532115b10SPawel Jakub Dawidek modified = true; 35632115b10SPawel Jakub Dawidek } 35732115b10SPawel Jakub Dawidek } 35832115b10SPawel Jakub Dawidek 35932115b10SPawel Jakub Dawidek return (modified); 36032115b10SPawel Jakub Dawidek } 36132115b10SPawel Jakub Dawidek 36232115b10SPawel Jakub Dawidek /* 36332115b10SPawel Jakub Dawidek * Function should be called after finishing synchronization of one extent. 36432115b10SPawel Jakub Dawidek * It returns true if on-disk metadata should be updated. 36532115b10SPawel Jakub Dawidek */ 36632115b10SPawel Jakub Dawidek bool 36732115b10SPawel Jakub Dawidek activemap_extent_complete(struct activemap *amp, int extent) 36832115b10SPawel Jakub Dawidek { 36932115b10SPawel Jakub Dawidek bool modified; 37032115b10SPawel Jakub Dawidek int reqs; 37132115b10SPawel Jakub Dawidek 372adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 373adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(extent >= 0 && extent < amp->am_nextents); 37432115b10SPawel Jakub Dawidek 37532115b10SPawel Jakub Dawidek modified = false; 37632115b10SPawel Jakub Dawidek 37732115b10SPawel Jakub Dawidek reqs = ext2reqs(amp, extent); 378adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_memtab[extent] >= reqs); 37932115b10SPawel Jakub Dawidek amp->am_memtab[extent] -= reqs; 380adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(bit_test(amp->am_memmap, extent)); 38132115b10SPawel Jakub Dawidek if (amp->am_memtab[extent] == 0) { 38232115b10SPawel Jakub Dawidek bit_clear(amp->am_memmap, extent); 38332115b10SPawel Jakub Dawidek amp->am_ndirty--; 38432115b10SPawel Jakub Dawidek modified = true; 38532115b10SPawel Jakub Dawidek } 38632115b10SPawel Jakub Dawidek 38732115b10SPawel Jakub Dawidek return (modified); 38832115b10SPawel Jakub Dawidek } 38932115b10SPawel Jakub Dawidek 39032115b10SPawel Jakub Dawidek /* 39132115b10SPawel Jakub Dawidek * Function returns number of dirty regions. 39232115b10SPawel Jakub Dawidek */ 39332115b10SPawel Jakub Dawidek uint64_t 39432115b10SPawel Jakub Dawidek activemap_ndirty(const struct activemap *amp) 39532115b10SPawel Jakub Dawidek { 39632115b10SPawel Jakub Dawidek 397adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 39832115b10SPawel Jakub Dawidek 39932115b10SPawel Jakub Dawidek return (amp->am_ndirty); 40032115b10SPawel Jakub Dawidek } 40132115b10SPawel Jakub Dawidek 40232115b10SPawel Jakub Dawidek /* 40332115b10SPawel Jakub Dawidek * Function compare on-disk bitmap and in-memory bitmap and returns true if 40432115b10SPawel Jakub Dawidek * they differ and should be flushed to the disk. 40532115b10SPawel Jakub Dawidek */ 40632115b10SPawel Jakub Dawidek bool 40732115b10SPawel Jakub Dawidek activemap_differ(const struct activemap *amp) 40832115b10SPawel Jakub Dawidek { 40932115b10SPawel Jakub Dawidek 410adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 41132115b10SPawel Jakub Dawidek 41232115b10SPawel Jakub Dawidek return (memcmp(amp->am_diskmap, amp->am_memmap, 41332115b10SPawel Jakub Dawidek amp->am_mapsize) != 0); 41432115b10SPawel Jakub Dawidek } 41532115b10SPawel Jakub Dawidek 41632115b10SPawel Jakub Dawidek /* 41732115b10SPawel Jakub Dawidek * Function returns number of bytes used by bitmap. 41832115b10SPawel Jakub Dawidek */ 41932115b10SPawel Jakub Dawidek size_t 42032115b10SPawel Jakub Dawidek activemap_size(const struct activemap *amp) 42132115b10SPawel Jakub Dawidek { 42232115b10SPawel Jakub Dawidek 423adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 42432115b10SPawel Jakub Dawidek 42532115b10SPawel Jakub Dawidek return (amp->am_mapsize); 42632115b10SPawel Jakub Dawidek } 42732115b10SPawel Jakub Dawidek 42832115b10SPawel Jakub Dawidek /* 42932115b10SPawel Jakub Dawidek * Function returns number of bytes needed for storing on-disk bitmap. 43032115b10SPawel Jakub Dawidek * This is the same as activemap_size(), but rounded up to sector size. 43132115b10SPawel Jakub Dawidek */ 43232115b10SPawel Jakub Dawidek size_t 43332115b10SPawel Jakub Dawidek activemap_ondisk_size(const struct activemap *amp) 43432115b10SPawel Jakub Dawidek { 43532115b10SPawel Jakub Dawidek 436adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 43732115b10SPawel Jakub Dawidek 43832115b10SPawel Jakub Dawidek return (amp->am_diskmapsize); 43932115b10SPawel Jakub Dawidek } 44032115b10SPawel Jakub Dawidek 44132115b10SPawel Jakub Dawidek /* 44232115b10SPawel Jakub Dawidek * Function copies the given buffer read from disk to the internal bitmap. 44332115b10SPawel Jakub Dawidek */ 44432115b10SPawel Jakub Dawidek void 44532115b10SPawel Jakub Dawidek activemap_copyin(struct activemap *amp, const unsigned char *buf, size_t size) 44632115b10SPawel Jakub Dawidek { 44732115b10SPawel Jakub Dawidek int ext; 44832115b10SPawel Jakub Dawidek 449adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 450adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(size >= amp->am_mapsize); 45132115b10SPawel Jakub Dawidek 45232115b10SPawel Jakub Dawidek memcpy(amp->am_diskmap, buf, amp->am_mapsize); 45332115b10SPawel Jakub Dawidek memcpy(amp->am_memmap, buf, amp->am_mapsize); 45432115b10SPawel Jakub Dawidek memcpy(amp->am_syncmap, buf, amp->am_mapsize); 45532115b10SPawel Jakub Dawidek 45632115b10SPawel Jakub Dawidek bit_ffs(amp->am_memmap, amp->am_nextents, &ext); 45732115b10SPawel Jakub Dawidek if (ext == -1) { 45832115b10SPawel Jakub Dawidek /* There are no dirty extents, so we can leave now. */ 45932115b10SPawel Jakub Dawidek return; 46032115b10SPawel Jakub Dawidek } 46132115b10SPawel Jakub Dawidek /* 46232115b10SPawel Jakub Dawidek * Set synchronization offset to the first dirty extent. 46332115b10SPawel Jakub Dawidek */ 46432115b10SPawel Jakub Dawidek activemap_sync_rewind(amp); 46532115b10SPawel Jakub Dawidek /* 46632115b10SPawel Jakub Dawidek * We have dirty extents and we want them to stay that way until 46732115b10SPawel Jakub Dawidek * we synchronize, so we set number of pending writes to number 46832115b10SPawel Jakub Dawidek * of requests needed to synchronize one extent. 46932115b10SPawel Jakub Dawidek */ 47032115b10SPawel Jakub Dawidek amp->am_ndirty = 0; 47132115b10SPawel Jakub Dawidek for (; ext < amp->am_nextents; ext++) { 47232115b10SPawel Jakub Dawidek if (bit_test(amp->am_memmap, ext)) { 47332115b10SPawel Jakub Dawidek amp->am_memtab[ext] = ext2reqs(amp, ext); 47432115b10SPawel Jakub Dawidek amp->am_ndirty++; 47532115b10SPawel Jakub Dawidek } 47632115b10SPawel Jakub Dawidek } 47732115b10SPawel Jakub Dawidek } 47832115b10SPawel Jakub Dawidek 47932115b10SPawel Jakub Dawidek /* 48047f1eb5cSMikolaj Golub * Function merges the given bitmap with existing one. 48132115b10SPawel Jakub Dawidek */ 48232115b10SPawel Jakub Dawidek void 48332115b10SPawel Jakub Dawidek activemap_merge(struct activemap *amp, const unsigned char *buf, size_t size) 48432115b10SPawel Jakub Dawidek { 48532115b10SPawel Jakub Dawidek bitstr_t *remmap = __DECONST(bitstr_t *, buf); 48632115b10SPawel Jakub Dawidek int ext; 48732115b10SPawel Jakub Dawidek 488adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 489adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(size >= amp->am_mapsize); 49032115b10SPawel Jakub Dawidek 49132115b10SPawel Jakub Dawidek bit_ffs(remmap, amp->am_nextents, &ext); 49232115b10SPawel Jakub Dawidek if (ext == -1) { 49332115b10SPawel Jakub Dawidek /* There are no dirty extents, so we can leave now. */ 49432115b10SPawel Jakub Dawidek return; 49532115b10SPawel Jakub Dawidek } 49632115b10SPawel Jakub Dawidek /* 49732115b10SPawel Jakub Dawidek * We have dirty extents and we want them to stay that way until 49832115b10SPawel Jakub Dawidek * we synchronize, so we set number of pending writes to number 49932115b10SPawel Jakub Dawidek * of requests needed to synchronize one extent. 50032115b10SPawel Jakub Dawidek */ 50132115b10SPawel Jakub Dawidek for (; ext < amp->am_nextents; ext++) { 50232115b10SPawel Jakub Dawidek /* Local extent already dirty. */ 50332115b10SPawel Jakub Dawidek if (bit_test(amp->am_syncmap, ext)) 50432115b10SPawel Jakub Dawidek continue; 50532115b10SPawel Jakub Dawidek /* Remote extent isn't dirty. */ 50632115b10SPawel Jakub Dawidek if (!bit_test(remmap, ext)) 50732115b10SPawel Jakub Dawidek continue; 50832115b10SPawel Jakub Dawidek bit_set(amp->am_syncmap, ext); 50932115b10SPawel Jakub Dawidek bit_set(amp->am_memmap, ext); 51032115b10SPawel Jakub Dawidek bit_set(amp->am_diskmap, ext); 51132115b10SPawel Jakub Dawidek if (amp->am_memtab[ext] == 0) 51232115b10SPawel Jakub Dawidek amp->am_ndirty++; 51332115b10SPawel Jakub Dawidek amp->am_memtab[ext] = ext2reqs(amp, ext); 51432115b10SPawel Jakub Dawidek } 51532115b10SPawel Jakub Dawidek /* 51632115b10SPawel Jakub Dawidek * Set synchronization offset to the first dirty extent. 51732115b10SPawel Jakub Dawidek */ 51832115b10SPawel Jakub Dawidek activemap_sync_rewind(amp); 51932115b10SPawel Jakub Dawidek } 52032115b10SPawel Jakub Dawidek 52132115b10SPawel Jakub Dawidek /* 52232115b10SPawel Jakub Dawidek * Function returns pointer to internal bitmap that should be written to disk. 52332115b10SPawel Jakub Dawidek */ 52432115b10SPawel Jakub Dawidek const unsigned char * 52532115b10SPawel Jakub Dawidek activemap_bitmap(struct activemap *amp, size_t *sizep) 52632115b10SPawel Jakub Dawidek { 52732115b10SPawel Jakub Dawidek 528adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 52932115b10SPawel Jakub Dawidek 53032115b10SPawel Jakub Dawidek if (sizep != NULL) 53132115b10SPawel Jakub Dawidek *sizep = amp->am_diskmapsize; 53232115b10SPawel Jakub Dawidek memcpy(amp->am_diskmap, amp->am_memmap, amp->am_mapsize); 53332115b10SPawel Jakub Dawidek keepdirty_fill(amp); 53432115b10SPawel Jakub Dawidek return ((const unsigned char *)amp->am_diskmap); 53532115b10SPawel Jakub Dawidek } 53632115b10SPawel Jakub Dawidek 53732115b10SPawel Jakub Dawidek /* 53832115b10SPawel Jakub Dawidek * Function calculates size needed to store bitmap on disk. 53932115b10SPawel Jakub Dawidek */ 54032115b10SPawel Jakub Dawidek size_t 54132115b10SPawel Jakub Dawidek activemap_calc_ondisk_size(uint64_t mediasize, uint32_t extentsize, 54232115b10SPawel Jakub Dawidek uint32_t sectorsize) 54332115b10SPawel Jakub Dawidek { 54432115b10SPawel Jakub Dawidek uint64_t nextents, mapsize; 54532115b10SPawel Jakub Dawidek 546adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(mediasize > 0); 547adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(extentsize > 0); 548adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(powerof2(extentsize)); 549adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(sectorsize > 0); 550adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(powerof2(sectorsize)); 55132115b10SPawel Jakub Dawidek 55232115b10SPawel Jakub Dawidek nextents = ((mediasize - 1) / extentsize) + 1; 5538907f744SAlan Somers mapsize = bitstr_size(nextents); 55432115b10SPawel Jakub Dawidek return (roundup2(mapsize, sectorsize)); 55532115b10SPawel Jakub Dawidek } 55632115b10SPawel Jakub Dawidek 55732115b10SPawel Jakub Dawidek /* 55832115b10SPawel Jakub Dawidek * Set synchronization offset to the first dirty extent. 55932115b10SPawel Jakub Dawidek */ 56032115b10SPawel Jakub Dawidek void 56132115b10SPawel Jakub Dawidek activemap_sync_rewind(struct activemap *amp) 56232115b10SPawel Jakub Dawidek { 56332115b10SPawel Jakub Dawidek int ext; 56432115b10SPawel Jakub Dawidek 565adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 56632115b10SPawel Jakub Dawidek 56732115b10SPawel Jakub Dawidek bit_ffs(amp->am_syncmap, amp->am_nextents, &ext); 56832115b10SPawel Jakub Dawidek if (ext == -1) { 56932115b10SPawel Jakub Dawidek /* There are no extents to synchronize. */ 57032115b10SPawel Jakub Dawidek amp->am_syncoff = -2; 57132115b10SPawel Jakub Dawidek return; 57232115b10SPawel Jakub Dawidek } 57332115b10SPawel Jakub Dawidek /* 5744b85a12fSUlrich Spörlein * Mark that we want to start synchronization from the beginning. 57532115b10SPawel Jakub Dawidek */ 57632115b10SPawel Jakub Dawidek amp->am_syncoff = -1; 57732115b10SPawel Jakub Dawidek } 57832115b10SPawel Jakub Dawidek 57932115b10SPawel Jakub Dawidek /* 58032115b10SPawel Jakub Dawidek * Return next offset of where we should synchronize. 58132115b10SPawel Jakub Dawidek */ 58232115b10SPawel Jakub Dawidek off_t 58332115b10SPawel Jakub Dawidek activemap_sync_offset(struct activemap *amp, off_t *lengthp, int *syncextp) 58432115b10SPawel Jakub Dawidek { 58532115b10SPawel Jakub Dawidek off_t syncoff, left; 58632115b10SPawel Jakub Dawidek int ext; 58732115b10SPawel Jakub Dawidek 588adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 589adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(lengthp != NULL); 590adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(syncextp != NULL); 59132115b10SPawel Jakub Dawidek 59232115b10SPawel Jakub Dawidek *syncextp = -1; 59332115b10SPawel Jakub Dawidek 59432115b10SPawel Jakub Dawidek if (amp->am_syncoff == -2) 59532115b10SPawel Jakub Dawidek return (-1); 59632115b10SPawel Jakub Dawidek 59732115b10SPawel Jakub Dawidek if (amp->am_syncoff >= 0 && 59832115b10SPawel Jakub Dawidek (amp->am_syncoff + MAXPHYS >= amp->am_mediasize || 59932115b10SPawel Jakub Dawidek off2ext(amp, amp->am_syncoff) != 60032115b10SPawel Jakub Dawidek off2ext(amp, amp->am_syncoff + MAXPHYS))) { 60132115b10SPawel Jakub Dawidek /* 60232115b10SPawel Jakub Dawidek * We are about to change extent, so mark previous one as clean. 60332115b10SPawel Jakub Dawidek */ 60432115b10SPawel Jakub Dawidek ext = off2ext(amp, amp->am_syncoff); 60532115b10SPawel Jakub Dawidek bit_clear(amp->am_syncmap, ext); 60632115b10SPawel Jakub Dawidek *syncextp = ext; 60732115b10SPawel Jakub Dawidek amp->am_syncoff = -1; 60832115b10SPawel Jakub Dawidek } 60932115b10SPawel Jakub Dawidek 61032115b10SPawel Jakub Dawidek if (amp->am_syncoff == -1) { 61132115b10SPawel Jakub Dawidek /* 61232115b10SPawel Jakub Dawidek * Let's find first extent to synchronize. 61332115b10SPawel Jakub Dawidek */ 61432115b10SPawel Jakub Dawidek bit_ffs(amp->am_syncmap, amp->am_nextents, &ext); 61532115b10SPawel Jakub Dawidek if (ext == -1) { 61632115b10SPawel Jakub Dawidek amp->am_syncoff = -2; 61732115b10SPawel Jakub Dawidek return (-1); 61832115b10SPawel Jakub Dawidek } 61932115b10SPawel Jakub Dawidek amp->am_syncoff = ext2off(amp, ext); 62032115b10SPawel Jakub Dawidek } else { 62132115b10SPawel Jakub Dawidek /* 62232115b10SPawel Jakub Dawidek * We don't change extent, so just increase offset. 62332115b10SPawel Jakub Dawidek */ 62432115b10SPawel Jakub Dawidek amp->am_syncoff += MAXPHYS; 62532115b10SPawel Jakub Dawidek if (amp->am_syncoff >= amp->am_mediasize) { 62632115b10SPawel Jakub Dawidek amp->am_syncoff = -2; 62732115b10SPawel Jakub Dawidek return (-1); 62832115b10SPawel Jakub Dawidek } 62932115b10SPawel Jakub Dawidek } 63032115b10SPawel Jakub Dawidek 63132115b10SPawel Jakub Dawidek syncoff = amp->am_syncoff; 63232115b10SPawel Jakub Dawidek left = ext2off(amp, off2ext(amp, syncoff)) + 63332115b10SPawel Jakub Dawidek amp->am_extentsize - syncoff; 63432115b10SPawel Jakub Dawidek if (syncoff + left > amp->am_mediasize) 63532115b10SPawel Jakub Dawidek left = amp->am_mediasize - syncoff; 63632115b10SPawel Jakub Dawidek if (left > MAXPHYS) 63732115b10SPawel Jakub Dawidek left = MAXPHYS; 63832115b10SPawel Jakub Dawidek 639adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(left >= 0 && left <= MAXPHYS); 640adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(syncoff >= 0 && syncoff < amp->am_mediasize); 641adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(syncoff + left >= 0 && 642adf8002bSPawel Jakub Dawidek syncoff + left <= amp->am_mediasize); 64332115b10SPawel Jakub Dawidek 64432115b10SPawel Jakub Dawidek *lengthp = left; 64532115b10SPawel Jakub Dawidek return (syncoff); 64632115b10SPawel Jakub Dawidek } 64732115b10SPawel Jakub Dawidek 64832115b10SPawel Jakub Dawidek /* 64932115b10SPawel Jakub Dawidek * Mark extent(s) containing the given region for synchronization. 65032115b10SPawel Jakub Dawidek * Most likely one of the components is unavailable. 65132115b10SPawel Jakub Dawidek */ 65232115b10SPawel Jakub Dawidek bool 65332115b10SPawel Jakub Dawidek activemap_need_sync(struct activemap *amp, off_t offset, off_t length) 65432115b10SPawel Jakub Dawidek { 65532115b10SPawel Jakub Dawidek bool modified; 65632115b10SPawel Jakub Dawidek off_t end; 65732115b10SPawel Jakub Dawidek int ext; 65832115b10SPawel Jakub Dawidek 659adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(amp->am_magic == ACTIVEMAP_MAGIC); 66032115b10SPawel Jakub Dawidek 66132115b10SPawel Jakub Dawidek modified = false; 66232115b10SPawel Jakub Dawidek end = offset + length - 1; 66332115b10SPawel Jakub Dawidek 66432115b10SPawel Jakub Dawidek for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) { 66532115b10SPawel Jakub Dawidek if (bit_test(amp->am_syncmap, ext)) { 66632115b10SPawel Jakub Dawidek /* Already marked for synchronization. */ 667adf8002bSPawel Jakub Dawidek PJDLOG_ASSERT(bit_test(amp->am_memmap, ext)); 66832115b10SPawel Jakub Dawidek continue; 66932115b10SPawel Jakub Dawidek } 67032115b10SPawel Jakub Dawidek bit_set(amp->am_syncmap, ext); 67132115b10SPawel Jakub Dawidek if (!bit_test(amp->am_memmap, ext)) { 67232115b10SPawel Jakub Dawidek bit_set(amp->am_memmap, ext); 67332115b10SPawel Jakub Dawidek amp->am_ndirty++; 67432115b10SPawel Jakub Dawidek } 67532115b10SPawel Jakub Dawidek amp->am_memtab[ext] += ext2reqs(amp, ext); 67632115b10SPawel Jakub Dawidek modified = true; 67732115b10SPawel Jakub Dawidek } 67832115b10SPawel Jakub Dawidek 67932115b10SPawel Jakub Dawidek return (modified); 68032115b10SPawel Jakub Dawidek } 68132115b10SPawel Jakub Dawidek 68232115b10SPawel Jakub Dawidek void 68332115b10SPawel Jakub Dawidek activemap_dump(const struct activemap *amp) 68432115b10SPawel Jakub Dawidek { 68532115b10SPawel Jakub Dawidek int bit; 68632115b10SPawel Jakub Dawidek 68732115b10SPawel Jakub Dawidek printf("M: "); 68832115b10SPawel Jakub Dawidek for (bit = 0; bit < amp->am_nextents; bit++) 68932115b10SPawel Jakub Dawidek printf("%d", bit_test(amp->am_memmap, bit) ? 1 : 0); 69032115b10SPawel Jakub Dawidek printf("\n"); 69132115b10SPawel Jakub Dawidek printf("D: "); 69232115b10SPawel Jakub Dawidek for (bit = 0; bit < amp->am_nextents; bit++) 69332115b10SPawel Jakub Dawidek printf("%d", bit_test(amp->am_diskmap, bit) ? 1 : 0); 69432115b10SPawel Jakub Dawidek printf("\n"); 69532115b10SPawel Jakub Dawidek printf("S: "); 69632115b10SPawel Jakub Dawidek for (bit = 0; bit < amp->am_nextents; bit++) 69732115b10SPawel Jakub Dawidek printf("%d", bit_test(amp->am_syncmap, bit) ? 1 : 0); 69832115b10SPawel Jakub Dawidek printf("\n"); 69932115b10SPawel Jakub Dawidek } 700