Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : /* Driver to sit on top of another disk and log writes, in order
32 : : * to track changed blocks
33 : : */
34 : :
35 : : #ifdef HAVE_CONFIG_H
36 : : #include "config.h"
37 : : #endif
38 : :
39 : : #include <errno.h>
40 : : #include <stdio.h>
41 : : #include <fcntl.h>
42 : : #include <unistd.h>
43 : : #include <stdlib.h>
44 : : #include <sys/mman.h>
45 : : #include <sys/socket.h>
46 : : #include <sys/un.h>
47 : :
48 : : #include "tapdisk.h"
49 : : #include "tapdisk-server.h"
50 : : #include "tapdisk-driver.h"
51 : : #include "tapdisk-interface.h"
52 : : #include "tapdisk-utils.h"
53 : : #include "timeout-math.h"
54 : : #include "log.h"
55 : : #include "block-log.h"
56 : :
57 : : #define BITS_PER_LONG (sizeof(unsigned long) * 8)
58 : : #define BITS_TO_LONGS(bits) (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
59 : :
60 : : #define BITMAP_ENTRY(_nr, _bmap) ((unsigned long*)(_bmap + sizeof(struct cbt_log_metadata)))[((_nr)/BITS_PER_LONG)]
61 : : #define BITMAP_SHIFT(_nr) ((_nr) % BITS_PER_LONG)
62 : :
63 : : static inline int test_bit(int nr, void* bmap)
64 : : {
65 : : return (BITMAP_ENTRY(nr, bmap) >> BITMAP_SHIFT(nr)) & 1;
66 : : }
67 : :
68 : : static inline void set_bit(int nr, void* bmap)
69 : : {
70 : 0 : BITMAP_ENTRY(nr, bmap) |= (1UL << BITMAP_SHIFT(nr));
71 : : }
72 : :
73 : : static inline uint64_t
74 : : get_bit_for_sec(td_sector_t sector)
75 : : {
76 : 0 : uint64_t block = (sector * SECTOR_SIZE) / CBT_BLOCK_SIZE;
77 : : return block;
78 : : }
79 : :
80 : 0 : static int bitmap_init(struct tdlog_data *data, char *name)
81 : : {
82 : : uint64_t bmsize;
83 : : int fd;
84 : 0 : int result = 0;
85 : :
86 : : /* Open on disk log file and map it into memory */
87 : 0 : fd = open(name, O_RDWR);
88 [ # # ]: 0 : if (fd == -1) {
89 : : EPRINTF("failed to open bitmap log file");
90 : 0 : result = -1;
91 : : }
92 : :
93 [ # # ]: 0 : if (result == 0) {
94 : : //data->size is in number of sectors, convert it to bytes
95 : 0 : bmsize = bitmap_size(data->size * SECTOR_SIZE) + sizeof(struct cbt_log_metadata);
96 : 0 : DPRINTF("CBT: allocating %"PRIu64" bytes (bitmap %"PRIu64" + header %lu) for dirty bitmap",
97 : : bmsize, bitmap_size(data->size * SECTOR_SIZE),
98 : : sizeof(struct cbt_log_metadata));
99 : :
100 : 0 : data->bitmap = mmap(NULL, bmsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
101 [ # # ]: 0 : if (!data->bitmap) {
102 : : EPRINTF("could not allocate dirty bitmap of size %"PRIu64, bmsize);
103 : 0 : result = -1;
104 : : }
105 : :
106 : 0 : close (fd);
107 : : }
108 : :
109 : 0 : return result;
110 : : }
111 : :
112 : 0 : static int bitmap_free(struct tdlog_data *data)
113 : : {
114 : : uint64_t bmsize;
115 : : int rc;
116 : 0 : bmsize = bitmap_size(data->size * SECTOR_SIZE) + sizeof(struct cbt_log_metadata);
117 [ # # ]: 0 : if (data->bitmap) {
118 : 0 : rc = munmap(data->bitmap, bmsize);
119 [ # # ]: 0 : if (rc != 0) {
120 : : EPRINTF("Failed to unmap the bitmap block");
121 : : }
122 : : }
123 : :
124 : 0 : return 0;
125 : : }
126 : :
127 : 0 : static int bitmap_set(struct tdlog_data* data, uint64_t block, int count)
128 : : {
129 : : int i;
130 : :
131 [ # # ]: 0 : for (i = 0; i < count; i++)
132 : 0 : set_bit(block + i, data->bitmap);
133 : :
134 : 0 : return 0;
135 : : }
136 : :
137 : :
138 : : /* -- interface -- */
139 : :
140 : 0 : static int tdlog_close(td_driver_t* driver)
141 : : {
142 : 0 : struct tdlog_data* data = (struct tdlog_data*)driver->data;
143 : 0 : bitmap_free(data);
144 : :
145 : 0 : return 0;
146 : : }
147 : :
148 : 0 : static int tdlog_open(td_driver_t* driver, const char *name,
149 : : struct td_vbd_encryption *encryption, td_flag_t flags)
150 : : {
151 : 0 : struct tdlog_data* data = (struct tdlog_data*)driver->data;
152 : : int rc;
153 : :
154 : : memset(data, 0, sizeof(*data));
155 : 0 : data->size = driver->info.size;
156 : :
157 [ # # ]: 0 : if ((rc = bitmap_init(data, driver->name))) {
158 : : tdlog_close(driver);
159 : 0 : return rc;
160 : : }
161 : :
162 : : return 0;
163 : : }
164 : :
165 : 0 : static void tdlog_queue_read(td_driver_t* driver, td_request_t treq)
166 : : {
167 : 0 : td_forward_request(treq);
168 : 0 : }
169 : :
170 : 0 : static void tdlog_queue_write(td_driver_t* driver, td_request_t treq)
171 : : {
172 : 0 : struct tdlog_data* data = (struct tdlog_data*)driver->data;
173 : : uint64_t start_bit, last_bit;
174 : :
175 : 0 : start_bit = get_bit_for_sec(treq.sec);
176 : 0 : last_bit = get_bit_for_sec(treq.sec + treq.secs - 1);
177 : :
178 : 0 : bitmap_set(data, start_bit, (last_bit - start_bit) + 1);
179 : 0 : td_forward_request(treq);
180 : 0 : }
181 : :
182 : 0 : static int tdlog_get_parent_id(td_driver_t* driver, td_disk_id_t* id)
183 : : {
184 : 0 : return -EINVAL;
185 : : }
186 : :
187 : 0 : static int tdlog_validate_parent(td_driver_t *driver,
188 : : td_driver_t *parent, td_flag_t flags)
189 : : {
190 : 0 : return 0;
191 : : }
192 : :
193 : : struct tap_disk tapdisk_log = {
194 : : .disk_type = "tapdisk_log",
195 : : .private_data_size = sizeof(struct tdlog_data),
196 : : .flags = 0,
197 : : .td_open = tdlog_open,
198 : : .td_close = tdlog_close,
199 : : .td_queue_read = tdlog_queue_read,
200 : : .td_queue_write = tdlog_queue_write,
201 : : .td_get_parent_id = tdlog_get_parent_id,
202 : : .td_validate_parent = tdlog_validate_parent,
203 : : };
|