xref: /freebsd-src/sbin/hastd/activemap.c (revision 5c2bc3db201a4fe8d7911cf816bea104d5dc2138)
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(&amp->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, &amp->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(&amp->am_keepdirty, kd, kd_next);
22332115b10SPawel Jakub Dawidek 		TAILQ_INSERT_HEAD(&amp->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(&amp->am_keepdirty, skeepdirty);
232adf8002bSPawel Jakub Dawidek 		PJDLOG_ASSERT(kd != NULL);
23332115b10SPawel Jakub Dawidek 		TAILQ_REMOVE(&amp->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(&amp->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, &amp->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(&amp->am_keepdirty)) != NULL) {
26432115b10SPawel Jakub Dawidek 		TAILQ_REMOVE(&amp->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