1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #ifndef _G_JOURNAL_H_
30 #define _G_JOURNAL_H_
31
32 #include <sys/endian.h>
33 #include <sys/md5.h>
34 #ifdef _KERNEL
35 #include <sys/bio.h>
36 #endif
37
38 #define G_JOURNAL_CLASS_NAME "JOURNAL"
39
40 #define G_JOURNAL_MAGIC "GEOM::JOURNAL"
41 /*
42 * Version history:
43 * 0 - Initial version number.
44 */
45 #define G_JOURNAL_VERSION 0
46
47 #ifdef _KERNEL
48 extern int g_journal_debug;
49
50 #define GJ_DEBUG(lvl, ...) \
51 _GEOM_DEBUG("GEOM_JOURNAL", g_journal_debug, (lvl), NULL, __VA_ARGS__)
52 #define GJ_LOGREQ(lvl, bp, ...) \
53 _GEOM_DEBUG("GEOM_JOURNAL", g_journal_debug, (lvl), (bp), __VA_ARGS__)
54
55 #define JEMPTY(sc) ((sc)->sc_journal_offset - \
56 (sc)->sc_jprovider->sectorsize == \
57 (sc)->sc_active.jj_offset && \
58 (sc)->sc_current_count == 0)
59
60 #define GJ_BIO_REGULAR 0x00
61 #define GJ_BIO_READ 0x01
62 #define GJ_BIO_JOURNAL 0x02
63 #define GJ_BIO_COPY 0x03
64 #define GJ_BIO_MASK 0x0f
65
66 #if 0
67 #define GJF_BIO_DONT_FREE 0x10
68 #define GJF_BIO_MASK 0xf0
69 #endif
70
71 #define GJF_DEVICE_HARDCODED 0x0001
72 #define GJF_DEVICE_DESTROY 0x0010
73 #define GJF_DEVICE_SWITCH 0x0020
74 #define GJF_DEVICE_BEFORE_SWITCH 0x0040
75 #define GJF_DEVICE_CLEAN 0x0080
76 #define GJF_DEVICE_CHECKSUM 0x0100
77
78 #define GJ_HARD_LIMIT 64
79
80 /*
81 * We keep pointers to journaled data in bio structure and because we
82 * need to store two off_t values (offset in data provider and offset in
83 * journal), we have to borrow bio_completed field for this.
84 */
85 #define bio_joffset bio_completed
86 /*
87 * Use bio_caller1 field as a pointer in queue.
88 */
89 #define bio_next bio_caller1
90
91 /*
92 * There are two such structures maintained inside each journaled device.
93 * One describes active part of the journal, were recent requests are stored.
94 * The second describes the last consistent part of the journal with requests
95 * that are copied to the destination provider.
96 */
97 struct g_journal_journal {
98 struct bio *jj_queue; /* Cached journal entries. */
99 off_t jj_offset; /* Journal's start offset. */
100 };
101
102 struct g_journal_softc {
103 uint32_t sc_id;
104 uint8_t sc_type;
105 uint8_t sc_orig_type;
106 struct g_geom *sc_geom;
107 u_int sc_flags;
108 struct mtx sc_mtx;
109 off_t sc_mediasize;
110 u_int sc_sectorsize;
111 #define GJ_FLUSH_DATA 0x01
112 #define GJ_FLUSH_JOURNAL 0x02
113 u_int sc_bio_flush;
114
115 uint32_t sc_journal_id;
116 uint32_t sc_journal_next_id;
117 int sc_journal_copying;
118 off_t sc_journal_offset;
119 off_t sc_journal_previous_id;
120
121 struct bio_queue_head sc_back_queue;
122 struct bio_queue_head sc_regular_queue;
123
124 struct bio_queue_head sc_delayed_queue;
125 int sc_delayed_count;
126
127 struct bio *sc_current_queue;
128 int sc_current_count;
129
130 struct bio *sc_flush_queue;
131 int sc_flush_count;
132 int sc_flush_in_progress;
133
134 struct bio *sc_copy_queue;
135 int sc_copy_in_progress;
136
137 struct g_consumer *sc_dconsumer;
138 struct g_consumer *sc_jconsumer;
139
140 struct g_journal_journal sc_inactive;
141 struct g_journal_journal sc_active;
142
143 off_t sc_jstart; /* Journal space start offset. */
144 off_t sc_jend; /* Journal space end offset. */
145
146 struct callout sc_callout;
147 struct proc *sc_worker;
148
149 struct root_hold_token *sc_rootmount;
150 };
151 #define sc_dprovider sc_dconsumer->provider
152 #define sc_jprovider sc_jconsumer->provider
153 #define sc_name sc_dprovider->name
154
155 #define GJQ_INSERT_HEAD(head, bp) do { \
156 (bp)->bio_next = (head); \
157 (head) = (bp); \
158 } while (0)
159 #define GJQ_INSERT_AFTER(head, bp, pbp) do { \
160 if ((pbp) == NULL) \
161 GJQ_INSERT_HEAD(head, bp); \
162 else { \
163 (bp)->bio_next = (pbp)->bio_next; \
164 (pbp)->bio_next = (bp); \
165 } \
166 } while (0)
167 #define GJQ_LAST(head, bp) do { \
168 struct bio *_bp; \
169 \
170 if ((head) == NULL) { \
171 (bp) = (head); \
172 break; \
173 } \
174 for (_bp = (head); _bp->bio_next != NULL; _bp = _bp->bio_next) \
175 continue; \
176 (bp) = (_bp); \
177 } while (0)
178 #define GJQ_FIRST(head) (head)
179 #define GJQ_REMOVE(head, bp) do { \
180 struct bio *_bp; \
181 \
182 if ((head) == (bp)) { \
183 (head) = (bp)->bio_next; \
184 (bp)->bio_next = NULL; \
185 break; \
186 } \
187 for (_bp = (head); _bp->bio_next != NULL; _bp = _bp->bio_next) {\
188 if (_bp->bio_next == (bp)) \
189 break; \
190 } \
191 KASSERT(_bp->bio_next != NULL, ("NULL bio_next")); \
192 KASSERT(_bp->bio_next == (bp), ("bio_next != bp")); \
193 _bp->bio_next = (bp)->bio_next; \
194 (bp)->bio_next = NULL; \
195 } while (0)
196 #define GJQ_FOREACH(head, bp) \
197 for ((bp) = (head); (bp) != NULL; (bp) = (bp)->bio_next)
198
199 #define GJ_HEADER_MAGIC "GJHDR"
200
201 struct g_journal_header {
202 char jh_magic[sizeof(GJ_HEADER_MAGIC)];
203 uint32_t jh_journal_id;
204 uint32_t jh_journal_next_id;
205 } __packed;
206
207 struct g_journal_entry {
208 uint64_t je_joffset;
209 uint64_t je_offset;
210 uint64_t je_length;
211 } __packed;
212
213 #define GJ_RECORD_HEADER_MAGIC "GJRHDR"
214 #define GJ_RECORD_HEADER_NENTRIES (20)
215 #define GJ_RECORD_MAX_SIZE(sc) \
216 ((sc)->sc_jprovider->sectorsize + GJ_RECORD_HEADER_NENTRIES * maxphys)
217 #define GJ_VALIDATE_OFFSET(offset, sc) do { \
218 if ((offset) + GJ_RECORD_MAX_SIZE(sc) >= (sc)->sc_jend) { \
219 (offset) = (sc)->sc_jstart; \
220 GJ_DEBUG(2, "Starting from the beginning (%s).", \
221 (sc)->sc_name); \
222 } \
223 } while (0)
224
225 struct g_journal_record_header {
226 char jrh_magic[sizeof(GJ_RECORD_HEADER_MAGIC)];
227 uint32_t jrh_journal_id;
228 uint16_t jrh_nentries;
229 u_char jrh_sum[8];
230 struct g_journal_entry jrh_entries[GJ_RECORD_HEADER_NENTRIES];
231 } __packed;
232
233 typedef int (g_journal_clean_t)(struct mount *mp);
234 typedef void (g_journal_dirty_t)(struct g_consumer *cp);
235
236 struct g_journal_desc {
237 const char *jd_fstype;
238 g_journal_clean_t *jd_clean;
239 g_journal_dirty_t *jd_dirty;
240 };
241
242 /* Supported file systems. */
243 extern const struct g_journal_desc g_journal_ufs;
244
245 #define GJ_TIMER_START(lvl, bt) do { \
246 if (g_journal_debug >= (lvl)) \
247 binuptime(bt); \
248 } while (0)
249 #define GJ_TIMER_STOP(lvl, bt, ...) do { \
250 if (g_journal_debug >= (lvl)) { \
251 struct bintime _bt2; \
252 struct timeval _tv; \
253 \
254 binuptime(&_bt2); \
255 bintime_sub(&_bt2, bt); \
256 bintime2timeval(&_bt2, &_tv); \
257 printf("GEOM_JOURNAL"); \
258 if (g_journal_debug > 0) \
259 printf("[%u]", lvl); \
260 printf(": "); \
261 printf(__VA_ARGS__); \
262 printf(": %jd.%06jds\n", (intmax_t)_tv.tv_sec, \
263 (intmax_t)_tv.tv_usec); \
264 } \
265 } while (0)
266 #endif /* _KERNEL */
267
268 #define GJ_TYPE_DATA 0x01
269 #define GJ_TYPE_JOURNAL 0x02
270 #define GJ_TYPE_COMPLETE (GJ_TYPE_DATA|GJ_TYPE_JOURNAL)
271
272 #define GJ_FLAG_CLEAN 0x01
273 #define GJ_FLAG_CHECKSUM 0x02
274
275 struct g_journal_metadata {
276 char md_magic[16]; /* Magic value. */
277 uint32_t md_version; /* Version number. */
278 uint32_t md_id; /* Journal unique ID. */
279 uint8_t md_type; /* Provider type. */
280 uint64_t md_jstart; /* Journal space start offset. */
281 uint64_t md_jend; /* Journal space end offset. */
282 uint64_t md_joffset; /* Last known consistent journal offset. */
283 uint32_t md_jid; /* Last known consistent journal ID. */
284 uint64_t md_flags; /* Journal flags. */
285 char md_provider[16]; /* Hardcoded provider. */
286 uint64_t md_provsize; /* Provider's size. */
287 u_char md_hash[16]; /* MD5 hash. */
288 };
289 static __inline void
journal_metadata_encode(struct g_journal_metadata * md,u_char * data)290 journal_metadata_encode(struct g_journal_metadata *md, u_char *data)
291 {
292 MD5_CTX ctx;
293
294 bcopy(md->md_magic, data, 16);
295 le32enc(data + 16, md->md_version);
296 le32enc(data + 20, md->md_id);
297 *(data + 24) = md->md_type;
298 le64enc(data + 25, md->md_jstart);
299 le64enc(data + 33, md->md_jend);
300 le64enc(data + 41, md->md_joffset);
301 le32enc(data + 49, md->md_jid);
302 le64enc(data + 53, md->md_flags);
303 bcopy(md->md_provider, data + 61, 16);
304 le64enc(data + 77, md->md_provsize);
305 MD5Init(&ctx);
306 MD5Update(&ctx, data, 85);
307 MD5Final(md->md_hash, &ctx);
308 bcopy(md->md_hash, data + 85, 16);
309 }
310 static __inline int
journal_metadata_decode_v0(const u_char * data,struct g_journal_metadata * md)311 journal_metadata_decode_v0(const u_char *data, struct g_journal_metadata *md)
312 {
313 MD5_CTX ctx;
314
315 md->md_id = le32dec(data + 20);
316 md->md_type = *(data + 24);
317 md->md_jstart = le64dec(data + 25);
318 md->md_jend = le64dec(data + 33);
319 md->md_joffset = le64dec(data + 41);
320 md->md_jid = le32dec(data + 49);
321 md->md_flags = le64dec(data + 53);
322 bcopy(data + 61, md->md_provider, 16);
323 md->md_provsize = le64dec(data + 77);
324 MD5Init(&ctx);
325 MD5Update(&ctx, data, 85);
326 MD5Final(md->md_hash, &ctx);
327 if (bcmp(md->md_hash, data + 85, 16) != 0)
328 return (EINVAL);
329 return (0);
330 }
331 static __inline int
journal_metadata_decode(const u_char * data,struct g_journal_metadata * md)332 journal_metadata_decode(const u_char *data, struct g_journal_metadata *md)
333 {
334 int error;
335
336 bcopy(data, md->md_magic, 16);
337 md->md_version = le32dec(data + 16);
338 switch (md->md_version) {
339 case 0:
340 error = journal_metadata_decode_v0(data, md);
341 break;
342 default:
343 error = EINVAL;
344 break;
345 }
346 return (error);
347 }
348
349 static __inline void
journal_metadata_dump(const struct g_journal_metadata * md)350 journal_metadata_dump(const struct g_journal_metadata *md)
351 {
352 static const char hex[] = "0123456789abcdef";
353 char hash[16 * 2 + 1];
354 u_int i;
355
356 printf(" magic: %s\n", md->md_magic);
357 printf(" version: %u\n", (u_int)md->md_version);
358 printf(" id: %u\n", (u_int)md->md_id);
359 printf(" type: %u\n", (u_int)md->md_type);
360 printf(" start: %ju\n", (uintmax_t)md->md_jstart);
361 printf(" end: %ju\n", (uintmax_t)md->md_jend);
362 printf(" joffset: %ju\n", (uintmax_t)md->md_joffset);
363 printf(" jid: %u\n", (u_int)md->md_jid);
364 printf(" flags: %u\n", (u_int)md->md_flags);
365 printf("hcprovider: %s\n", md->md_provider);
366 printf(" provsize: %ju\n", (uintmax_t)md->md_provsize);
367 bzero(hash, sizeof(hash));
368 for (i = 0; i < 16; i++) {
369 hash[i * 2] = hex[md->md_hash[i] >> 4];
370 hash[i * 2 + 1] = hex[md->md_hash[i] & 0x0f];
371 }
372 printf(" MD5 hash: %s\n", hash);
373 }
374 #endif /* !_G_JOURNAL_H_ */
375