]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sbin/hastd/activemap.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sbin / hastd / activemap.c
1 /*-
2  * Copyright (c) 2009-2010 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Pawel Jakub Dawidek under sponsorship from
6  * the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>  /* powerof2() */
34 #include <sys/queue.h>
35
36 #include <assert.h>
37 #include <bitstring.h>
38 #include <errno.h>
39 #include <stdint.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include <activemap.h>
45
46 #define ACTIVEMAP_MAGIC 0xac71e4
47 struct activemap {
48         int              am_magic;      /* Magic value. */
49         off_t            am_mediasize;  /* Media size in bytes. */
50         uint32_t         am_extentsize; /* Extent size in bytes,
51                                            must be power of 2. */
52         uint8_t          am_extentshift;/* 2 ^ extentbits == extentsize */
53         int              am_nextents;   /* Number of extents. */
54         size_t           am_mapsize;    /* Bitmap size in bytes. */
55         uint16_t        *am_memtab;     /* An array that holds number of pending
56                                            writes per extent. */
57         bitstr_t        *am_diskmap;    /* On-disk bitmap of dirty extents. */
58         bitstr_t        *am_memmap;     /* In-memory bitmap of dirty extents. */
59         size_t           am_diskmapsize; /* Map size rounded up to sector size. */
60         uint64_t         am_ndirty;     /* Number of dirty regions. */
61         bitstr_t        *am_syncmap;    /* Bitmap of extents to sync. */
62         off_t            am_syncoff;    /* Next synchronization offset. */
63         TAILQ_HEAD(skeepdirty, keepdirty) am_keepdirty; /* List of extents that
64                                            we keep dirty to reduce bitmap
65                                            updates. */
66         int              am_nkeepdirty; /* Number of am_keepdirty elements. */
67         int              am_nkeepdirty_limit; /* Maximum number of am_keepdirty
68                                                  elements. */
69 };
70
71 struct keepdirty {
72         int     kd_extent;
73         TAILQ_ENTRY(keepdirty) kd_next;
74 };
75
76 /*
77  * Helper function taken from sys/systm.h to calculate extentshift.
78  */
79 static uint32_t
80 bitcount32(uint32_t x)
81 {
82
83         x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1);
84         x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2);
85         x = (x + (x >> 4)) & 0x0f0f0f0f;
86         x = (x + (x >> 8));
87         x = (x + (x >> 16)) & 0x000000ff;
88         return (x);
89 }
90
91 static __inline int
92 off2ext(const struct activemap *amp, off_t offset)
93 {
94         int extent;
95
96         assert(offset >= 0 && offset < amp->am_mediasize);
97         extent = (offset >> amp->am_extentshift);
98         assert(extent >= 0 && extent < amp->am_nextents);
99         return (extent);
100 }
101
102 static __inline off_t
103 ext2off(const struct activemap *amp, int extent)
104 {
105         off_t offset;
106
107         assert(extent >= 0 && extent < amp->am_nextents);
108         offset = ((off_t)extent << amp->am_extentshift);
109         assert(offset >= 0 && offset < amp->am_mediasize);
110         return (offset);
111 }
112
113 /*
114  * Function calculates number of requests needed to synchronize the given
115  * extent.
116  */
117 static __inline int
118 ext2reqs(const struct activemap *amp, int ext)
119 {
120         off_t left;
121
122         if (ext < amp->am_nextents - 1)
123                 return (((amp->am_extentsize - 1) / MAXPHYS) + 1);
124
125         assert(ext == amp->am_nextents - 1);
126         left = amp->am_mediasize % amp->am_extentsize;
127         if (left == 0)
128                 left = amp->am_extentsize;
129         return (((left - 1) / MAXPHYS) + 1);
130 }
131
132 /*
133  * Initialize activemap structure and allocate memory for internal needs.
134  * Function returns 0 on success and -1 if any of the allocations failed.
135  */
136 int
137 activemap_init(struct activemap **ampp, uint64_t mediasize, uint32_t extentsize,
138     uint32_t sectorsize, uint32_t keepdirty)
139 {
140         struct activemap *amp;
141
142         assert(ampp != NULL);
143         assert(mediasize > 0);
144         assert(extentsize > 0);
145         assert(powerof2(extentsize));
146         assert(sectorsize > 0);
147         assert(powerof2(sectorsize));
148         assert(keepdirty > 0);
149
150         amp = malloc(sizeof(*amp));
151         if (amp == NULL)
152                 return (-1);
153
154         amp->am_mediasize = mediasize;
155         amp->am_nkeepdirty_limit = keepdirty;
156         amp->am_extentsize = extentsize;
157         amp->am_extentshift = bitcount32(extentsize - 1);
158         amp->am_nextents = ((mediasize - 1) / extentsize) + 1;
159         amp->am_mapsize = sizeof(bitstr_t) * bitstr_size(amp->am_nextents);
160         amp->am_diskmapsize = roundup2(amp->am_mapsize, sectorsize);
161         amp->am_ndirty = 0;
162         amp->am_syncoff = -2;
163         TAILQ_INIT(&amp->am_keepdirty);
164         amp->am_nkeepdirty = 0;
165
166         amp->am_memtab = calloc(amp->am_nextents, sizeof(amp->am_memtab[0]));
167         amp->am_diskmap = calloc(1, amp->am_diskmapsize);
168         amp->am_memmap = bit_alloc(amp->am_nextents);
169         amp->am_syncmap = bit_alloc(amp->am_nextents);
170
171         /*
172          * Check to see if any of the allocations above failed.
173          */
174         if (amp->am_memtab == NULL || amp->am_diskmap == NULL ||
175             amp->am_memmap == NULL || amp->am_syncmap == NULL) {
176                 if (amp->am_memtab != NULL)
177                         free(amp->am_memtab);
178                 if (amp->am_diskmap != NULL)
179                         free(amp->am_diskmap);
180                 if (amp->am_memmap != NULL)
181                         free(amp->am_memmap);
182                 if (amp->am_syncmap != NULL)
183                         free(amp->am_syncmap);
184                 amp->am_magic = 0;
185                 free(amp);
186                 errno = ENOMEM;
187                 return (-1);
188         }
189
190         amp->am_magic = ACTIVEMAP_MAGIC;
191         *ampp = amp;
192
193         return (0);
194 }
195
196 static struct keepdirty *
197 keepdirty_find(struct activemap *amp, int extent)
198 {
199         struct keepdirty *kd;
200
201         TAILQ_FOREACH(kd, &amp->am_keepdirty, kd_next) {
202                 if (kd->kd_extent == extent)
203                         break;
204         }
205         return (kd);
206 }
207
208 static void
209 keepdirty_add(struct activemap *amp, int extent)
210 {
211         struct keepdirty *kd;
212
213         kd = keepdirty_find(amp, extent);
214         if (kd != NULL) {
215                 /*
216                  * Only move element at the begining.
217                  */
218                 TAILQ_REMOVE(&amp->am_keepdirty, kd, kd_next);
219                 TAILQ_INSERT_HEAD(&amp->am_keepdirty, kd, kd_next);
220                 return;
221         }
222         /*
223          * Add new element, but first remove the most unused one if
224          * we have too many.
225          */
226         if (amp->am_nkeepdirty >= amp->am_nkeepdirty_limit) {
227                 kd = TAILQ_LAST(&amp->am_keepdirty, skeepdirty);
228                 assert(kd != NULL);
229                 TAILQ_REMOVE(&amp->am_keepdirty, kd, kd_next);
230                 amp->am_nkeepdirty--;
231                 assert(amp->am_nkeepdirty > 0);
232         }
233         if (kd == NULL)
234                 kd = malloc(sizeof(*kd));
235         /* We can ignore allocation failure. */
236         if (kd != NULL) {
237                 kd->kd_extent = extent;
238                 amp->am_nkeepdirty++;
239                 TAILQ_INSERT_HEAD(&amp->am_keepdirty, kd, kd_next);
240         }
241 }
242
243 static void
244 keepdirty_fill(struct activemap *amp)
245 {
246         struct keepdirty *kd;
247
248         TAILQ_FOREACH(kd, &amp->am_keepdirty, kd_next)
249                 bit_set(amp->am_diskmap, kd->kd_extent);
250 }
251
252 static void
253 keepdirty_free(struct activemap *amp)
254 {
255         struct keepdirty *kd;
256
257         while ((kd = TAILQ_FIRST(&amp->am_keepdirty)) != NULL) {
258                 TAILQ_REMOVE(&amp->am_keepdirty, kd, kd_next);
259                 amp->am_nkeepdirty--;
260                 free(kd);
261         }
262         assert(amp->am_nkeepdirty == 0);
263 }
264
265 /*
266  * Function frees resources allocated by activemap_init() function.
267  */
268 void
269 activemap_free(struct activemap *amp)
270 {
271
272         assert(amp->am_magic == ACTIVEMAP_MAGIC);
273
274         amp->am_magic = 0;
275
276         keepdirty_free(amp);
277         free(amp->am_memtab);
278         free(amp->am_diskmap);
279         free(amp->am_memmap);
280         free(amp->am_syncmap);
281 }
282
283 /*
284  * Function should be called before we handle write requests. It updates
285  * internal structures and returns true if on-disk metadata should be updated.
286  */
287 bool
288 activemap_write_start(struct activemap *amp, off_t offset, off_t length)
289 {
290         bool modified;
291         off_t end;
292         int ext;
293
294         assert(amp->am_magic == ACTIVEMAP_MAGIC);
295         assert(length > 0);
296
297         modified = false;
298         end = offset + length - 1;
299
300         for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) {
301                 /*
302                  * If the number of pending writes is increased from 0,
303                  * we have to mark the extent as dirty also in on-disk bitmap.
304                  * By returning true we inform the caller that on-disk bitmap
305                  * was modified and has to be flushed to disk.
306                  */
307                 if (amp->am_memtab[ext]++ == 0) {
308                         assert(!bit_test(amp->am_memmap, ext));
309                         bit_set(amp->am_memmap, ext);
310                         amp->am_ndirty++;
311                         modified = true;
312                 }
313                 keepdirty_add(amp, ext);
314         }
315
316         return (modified);
317 }
318
319 /*
320  * Function should be called after receiving write confirmation. It updates
321  * internal structures and returns true if on-disk metadata should be updated.
322  */
323 bool
324 activemap_write_complete(struct activemap *amp, off_t offset, off_t length)
325 {
326         bool modified;
327         off_t end;
328         int ext;
329
330         assert(amp->am_magic == ACTIVEMAP_MAGIC);
331         assert(length > 0);
332
333         modified = false;
334         end = offset + length - 1;
335
336         for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) {
337                 /*
338                  * If the number of pending writes goes down to 0, we have to
339                  * mark the extent as clean also in on-disk bitmap.
340                  * By returning true we inform the caller that on-disk bitmap
341                  * was modified and has to be flushed to disk.
342                  */
343                 assert(amp->am_memtab[ext] > 0);
344                 assert(bit_test(amp->am_memmap, ext));
345                 if (--amp->am_memtab[ext] == 0) {
346                         bit_clear(amp->am_memmap, ext);
347                         amp->am_ndirty--;
348                         modified = true;
349                 }
350         }
351
352         return (modified);
353 }
354
355 /*
356  * Function should be called after finishing synchronization of one extent.
357  * It returns true if on-disk metadata should be updated.
358  */
359 bool
360 activemap_extent_complete(struct activemap *amp, int extent)
361 {
362         bool modified;
363         int reqs;
364
365         assert(amp->am_magic == ACTIVEMAP_MAGIC);
366         assert(extent >= 0 && extent < amp->am_nextents);
367
368         modified = false;
369
370         reqs = ext2reqs(amp, extent);
371         assert(amp->am_memtab[extent] >= reqs);
372         amp->am_memtab[extent] -= reqs;
373         assert(bit_test(amp->am_memmap, extent));
374         if (amp->am_memtab[extent] == 0) {
375                 bit_clear(amp->am_memmap, extent);
376                 amp->am_ndirty--;
377                 modified = true;
378         }
379
380         return (modified);
381 }
382
383 /*
384  * Function returns number of dirty regions.
385  */
386 uint64_t
387 activemap_ndirty(const struct activemap *amp)
388 {
389
390         assert(amp->am_magic == ACTIVEMAP_MAGIC);
391
392         return (amp->am_ndirty);
393 }
394
395 /*
396  * Function compare on-disk bitmap and in-memory bitmap and returns true if
397  * they differ and should be flushed to the disk.
398  */
399 bool
400 activemap_differ(const struct activemap *amp)
401 {
402
403         assert(amp->am_magic == ACTIVEMAP_MAGIC);
404
405         return (memcmp(amp->am_diskmap, amp->am_memmap,
406             amp->am_mapsize) != 0);
407 }
408
409 /*
410  * Function returns number of bytes used by bitmap.
411  */
412 size_t
413 activemap_size(const struct activemap *amp)
414 {
415
416         assert(amp->am_magic == ACTIVEMAP_MAGIC);
417
418         return (amp->am_mapsize);
419 }
420
421 /*
422  * Function returns number of bytes needed for storing on-disk bitmap.
423  * This is the same as activemap_size(), but rounded up to sector size.
424  */
425 size_t
426 activemap_ondisk_size(const struct activemap *amp)
427 {
428
429         assert(amp->am_magic == ACTIVEMAP_MAGIC);
430
431         return (amp->am_diskmapsize);
432 }
433
434 /*
435  * Function copies the given buffer read from disk to the internal bitmap.
436  */
437 void
438 activemap_copyin(struct activemap *amp, const unsigned char *buf, size_t size)
439 {
440         int ext;
441
442         assert(amp->am_magic == ACTIVEMAP_MAGIC);
443         assert(size >= amp->am_mapsize);
444
445         memcpy(amp->am_diskmap, buf, amp->am_mapsize);
446         memcpy(amp->am_memmap, buf, amp->am_mapsize);
447         memcpy(amp->am_syncmap, buf, amp->am_mapsize);
448
449         bit_ffs(amp->am_memmap, amp->am_nextents, &ext);
450         if (ext == -1) {
451                 /* There are no dirty extents, so we can leave now. */
452                 return;
453         }
454         /*
455          * Set synchronization offset to the first dirty extent.
456          */
457         activemap_sync_rewind(amp);
458         /*
459          * We have dirty extents and we want them to stay that way until
460          * we synchronize, so we set number of pending writes to number
461          * of requests needed to synchronize one extent.
462          */
463         amp->am_ndirty = 0;
464         for (; ext < amp->am_nextents; ext++) {
465                 if (bit_test(amp->am_memmap, ext)) {
466                         amp->am_memtab[ext] = ext2reqs(amp, ext);
467                         amp->am_ndirty++;
468                 }
469         }
470 }
471
472 /*
473  * Function merges the given bitmap with existng one.
474  */
475 void
476 activemap_merge(struct activemap *amp, const unsigned char *buf, size_t size)
477 {
478         bitstr_t *remmap = __DECONST(bitstr_t *, buf);
479         int ext;
480
481         assert(amp->am_magic == ACTIVEMAP_MAGIC);
482         assert(size >= amp->am_mapsize);
483
484         bit_ffs(remmap, amp->am_nextents, &ext);
485         if (ext == -1) {
486                 /* There are no dirty extents, so we can leave now. */
487                 return;
488         }
489         /*
490          * We have dirty extents and we want them to stay that way until
491          * we synchronize, so we set number of pending writes to number
492          * of requests needed to synchronize one extent.
493          */
494         for (; ext < amp->am_nextents; ext++) {
495                 /* Local extent already dirty. */
496                 if (bit_test(amp->am_syncmap, ext))
497                         continue;
498                 /* Remote extent isn't dirty. */
499                 if (!bit_test(remmap, ext))
500                         continue;
501                 bit_set(amp->am_syncmap, ext);
502                 bit_set(amp->am_memmap, ext);
503                 bit_set(amp->am_diskmap, ext);
504                 if (amp->am_memtab[ext] == 0)
505                         amp->am_ndirty++;
506                 amp->am_memtab[ext] = ext2reqs(amp, ext);
507         }
508         /*
509          * Set synchronization offset to the first dirty extent.
510          */
511         activemap_sync_rewind(amp);
512 }
513
514 /*
515  * Function returns pointer to internal bitmap that should be written to disk.
516  */
517 const unsigned char *
518 activemap_bitmap(struct activemap *amp, size_t *sizep)
519 {
520
521         assert(amp->am_magic == ACTIVEMAP_MAGIC);
522
523         if (sizep != NULL)
524                 *sizep = amp->am_diskmapsize;
525         memcpy(amp->am_diskmap, amp->am_memmap, amp->am_mapsize);
526         keepdirty_fill(amp);
527         return ((const unsigned char *)amp->am_diskmap);
528 }
529
530 /*
531  * Function calculates size needed to store bitmap on disk.
532  */
533 size_t
534 activemap_calc_ondisk_size(uint64_t mediasize, uint32_t extentsize,
535     uint32_t sectorsize)
536 {
537         uint64_t nextents, mapsize;
538
539         assert(mediasize > 0);
540         assert(extentsize > 0);
541         assert(powerof2(extentsize));
542         assert(sectorsize > 0);
543         assert(powerof2(sectorsize));
544
545         nextents = ((mediasize - 1) / extentsize) + 1;
546         mapsize = sizeof(bitstr_t) * bitstr_size(nextents);
547         return (roundup2(mapsize, sectorsize));
548 }
549
550 /*
551  * Set synchronization offset to the first dirty extent.
552  */
553 void
554 activemap_sync_rewind(struct activemap *amp)
555 {
556         int ext;
557
558         assert(amp->am_magic == ACTIVEMAP_MAGIC);
559
560         bit_ffs(amp->am_syncmap, amp->am_nextents, &ext);
561         if (ext == -1) {
562                 /* There are no extents to synchronize. */
563                 amp->am_syncoff = -2;
564                 return;
565         }
566         /*
567          * Mark that we want to start synchronization from the begining.
568          */
569         amp->am_syncoff = -1;
570 }
571
572 /*
573  * Return next offset of where we should synchronize.
574  */
575 off_t
576 activemap_sync_offset(struct activemap *amp, off_t *lengthp, int *syncextp)
577 {
578         off_t syncoff, left;
579         int ext;
580
581         assert(amp->am_magic == ACTIVEMAP_MAGIC);
582         assert(lengthp != NULL);
583         assert(syncextp != NULL);
584
585         *syncextp = -1;
586
587         if (amp->am_syncoff == -2)
588                 return (-1);
589
590         if (amp->am_syncoff >= 0 &&
591             (amp->am_syncoff + MAXPHYS >= amp->am_mediasize ||
592              off2ext(amp, amp->am_syncoff) !=
593              off2ext(amp, amp->am_syncoff + MAXPHYS))) {
594                 /*
595                  * We are about to change extent, so mark previous one as clean.
596                  */
597                 ext = off2ext(amp, amp->am_syncoff);
598                 bit_clear(amp->am_syncmap, ext);
599                 *syncextp = ext;
600                 amp->am_syncoff = -1;
601         }
602
603         if (amp->am_syncoff == -1) {
604                 /*
605                  * Let's find first extent to synchronize.
606                  */
607                 bit_ffs(amp->am_syncmap, amp->am_nextents, &ext);
608                 if (ext == -1) {
609                         amp->am_syncoff = -2;
610                         return (-1);
611                 }
612                 amp->am_syncoff = ext2off(amp, ext);
613         } else {
614                 /*
615                  * We don't change extent, so just increase offset.
616                  */
617                 amp->am_syncoff += MAXPHYS;
618                 if (amp->am_syncoff >= amp->am_mediasize) {
619                         amp->am_syncoff = -2;
620                         return (-1);
621                 }
622         }
623
624         syncoff = amp->am_syncoff;
625         left = ext2off(amp, off2ext(amp, syncoff)) +
626             amp->am_extentsize - syncoff;
627         if (syncoff + left > amp->am_mediasize)
628                 left = amp->am_mediasize - syncoff;
629         if (left > MAXPHYS)
630                 left = MAXPHYS;
631
632         assert(left >= 0 && left <= MAXPHYS);
633         assert(syncoff >= 0 && syncoff < amp->am_mediasize);
634         assert(syncoff + left >= 0 && syncoff + left <= amp->am_mediasize);
635
636         *lengthp = left;
637         return (syncoff);
638 }
639
640 /*
641  * Mark extent(s) containing the given region for synchronization.
642  * Most likely one of the components is unavailable.
643  */
644 bool
645 activemap_need_sync(struct activemap *amp, off_t offset, off_t length)
646 {
647         bool modified;
648         off_t end;
649         int ext;
650
651         assert(amp->am_magic == ACTIVEMAP_MAGIC);
652
653         modified = false;
654         end = offset + length - 1;
655
656         for (ext = off2ext(amp, offset); ext <= off2ext(amp, end); ext++) {
657                 if (bit_test(amp->am_syncmap, ext)) {
658                         /* Already marked for synchronization. */
659                         assert(bit_test(amp->am_memmap, ext));
660                         continue;
661                 }
662                 bit_set(amp->am_syncmap, ext);
663                 if (!bit_test(amp->am_memmap, ext)) {
664                         bit_set(amp->am_memmap, ext);
665                         amp->am_ndirty++;
666                 }
667                 amp->am_memtab[ext] += ext2reqs(amp, ext);
668                 modified = true;
669         }
670
671         return (modified);
672 }
673
674 void
675 activemap_dump(const struct activemap *amp)
676 {
677         int bit;
678
679         printf("M: ");
680         for (bit = 0; bit < amp->am_nextents; bit++)
681                 printf("%d", bit_test(amp->am_memmap, bit) ? 1 : 0);
682         printf("\n");
683         printf("D: ");
684         for (bit = 0; bit < amp->am_nextents; bit++)
685                 printf("%d", bit_test(amp->am_diskmap, bit) ? 1 : 0);
686         printf("\n");
687         printf("S: ");
688         for (bit = 0; bit < amp->am_nextents; bit++)
689                 printf("%d", bit_test(amp->am_syncmap, bit) ? 1 : 0);
690         printf("\n");
691 }