1dd94f1b1SMatthew Dillon /*
2dd94f1b1SMatthew Dillon * Copyright (c) 2008 The DragonFly Project. All rights reserved.
3dd94f1b1SMatthew Dillon *
4dd94f1b1SMatthew Dillon * This code is derived from software contributed to The DragonFly Project
5dd94f1b1SMatthew Dillon * by Matthew Dillon <dillon@backplane.com>
6dd94f1b1SMatthew Dillon *
7dd94f1b1SMatthew Dillon * Redistribution and use in source and binary forms, with or without
8dd94f1b1SMatthew Dillon * modification, are permitted provided that the following conditions
9dd94f1b1SMatthew Dillon * are met:
10dd94f1b1SMatthew Dillon *
11dd94f1b1SMatthew Dillon * 1. Redistributions of source code must retain the above copyright
12dd94f1b1SMatthew Dillon * notice, this list of conditions and the following disclaimer.
13dd94f1b1SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
14dd94f1b1SMatthew Dillon * notice, this list of conditions and the following disclaimer in
15dd94f1b1SMatthew Dillon * the documentation and/or other materials provided with the
16dd94f1b1SMatthew Dillon * distribution.
17dd94f1b1SMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its
18dd94f1b1SMatthew Dillon * contributors may be used to endorse or promote products derived
19dd94f1b1SMatthew Dillon * from this software without specific, prior written permission.
20dd94f1b1SMatthew Dillon *
21dd94f1b1SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22dd94f1b1SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23dd94f1b1SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24dd94f1b1SMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25dd94f1b1SMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26dd94f1b1SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27dd94f1b1SMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28dd94f1b1SMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29dd94f1b1SMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30dd94f1b1SMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31dd94f1b1SMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32dd94f1b1SMatthew Dillon * SUCH DAMAGE.
33dd94f1b1SMatthew Dillon */
34dd94f1b1SMatthew Dillon /*
35dd94f1b1SMatthew Dillon * HAMMER mirroring ioctls - serialize and deserialize modifications made
36dd94f1b1SMatthew Dillon * to a filesystem.
37dd94f1b1SMatthew Dillon */
38dd94f1b1SMatthew Dillon
39dd94f1b1SMatthew Dillon #include "hammer.h"
40dd94f1b1SMatthew Dillon
41c82af904SMatthew Dillon static int hammer_mirror_check(hammer_cursor_t cursor,
424c038e17SMatthew Dillon struct hammer_ioc_mrecord_rec *mrec);
43c82af904SMatthew Dillon static int hammer_mirror_update(hammer_cursor_t cursor,
444c038e17SMatthew Dillon struct hammer_ioc_mrecord_rec *mrec);
454c038e17SMatthew Dillon static int hammer_ioc_mirror_write_rec(hammer_cursor_t cursor,
464c038e17SMatthew Dillon struct hammer_ioc_mrecord_rec *mrec,
474c038e17SMatthew Dillon struct hammer_ioc_mirror_rw *mirror,
4846137e17STomohiro Kusumi uint32_t localization,
494c038e17SMatthew Dillon char *uptr);
504c038e17SMatthew Dillon static int hammer_ioc_mirror_write_pass(hammer_cursor_t cursor,
514c038e17SMatthew Dillon struct hammer_ioc_mrecord_rec *mrec,
524c038e17SMatthew Dillon struct hammer_ioc_mirror_rw *mirror,
5346137e17STomohiro Kusumi uint32_t localization);
544c038e17SMatthew Dillon static int hammer_ioc_mirror_write_skip(hammer_cursor_t cursor,
554c038e17SMatthew Dillon struct hammer_ioc_mrecord_skip *mrec,
564c038e17SMatthew Dillon struct hammer_ioc_mirror_rw *mirror,
5746137e17STomohiro Kusumi uint32_t localization);
58842e7a70SMatthew Dillon static int hammer_mirror_delete_to(hammer_cursor_t cursor,
594c038e17SMatthew Dillon struct hammer_ioc_mirror_rw *mirror);
605f532f10STomohiro Kusumi static int hammer_mirror_nomirror(hammer_base_elm_t base);
61c82af904SMatthew Dillon
62c82af904SMatthew Dillon /*
63c82af904SMatthew Dillon * All B-Tree records within the specified key range which also conform
64c82af904SMatthew Dillon * to the transaction id range are returned. Mirroring code keeps track
65c82af904SMatthew Dillon * of the last transaction id fully scanned and can efficiently pick up
66c82af904SMatthew Dillon * where it left off if interrupted.
67ea434b6fSMatthew Dillon *
68ea434b6fSMatthew Dillon * The PFS is identified in the mirror structure. The passed ip is just
69ea434b6fSMatthew Dillon * some directory in the overall HAMMER filesystem and has nothing to
70ea434b6fSMatthew Dillon * do with the PFS.
71c82af904SMatthew Dillon */
72dd94f1b1SMatthew Dillon int
hammer_ioc_mirror_read(hammer_transaction_t trans,hammer_inode_t ip,struct hammer_ioc_mirror_rw * mirror)73dd94f1b1SMatthew Dillon hammer_ioc_mirror_read(hammer_transaction_t trans, hammer_inode_t ip,
74dd94f1b1SMatthew Dillon struct hammer_ioc_mirror_rw *mirror)
75dd94f1b1SMatthew Dillon {
764c038e17SMatthew Dillon struct hammer_cmirror cmirror;
77dd94f1b1SMatthew Dillon struct hammer_cursor cursor;
784c038e17SMatthew Dillon union hammer_ioc_mrecord_any mrec;
79c82af904SMatthew Dillon hammer_btree_leaf_elm_t elm;
80c82af904SMatthew Dillon char *uptr;
81dd94f1b1SMatthew Dillon int error;
82c82af904SMatthew Dillon int data_len;
83c82af904SMatthew Dillon int bytes;
844c038e17SMatthew Dillon int eatdisk;
854c286c36SMatthew Dillon int mrec_flags;
8646137e17STomohiro Kusumi uint32_t localization;
87*17b150c6STomohiro Kusumi hammer_crc_t rec_crc;
88ea434b6fSMatthew Dillon
8920cf2291STomohiro Kusumi localization = pfs_to_lo(mirror->pfs_id);
90dd94f1b1SMatthew Dillon
91dd94f1b1SMatthew Dillon if ((mirror->key_beg.localization | mirror->key_end.localization) &
92dd94f1b1SMatthew Dillon HAMMER_LOCALIZE_PSEUDOFS_MASK) {
93dd94f1b1SMatthew Dillon return(EINVAL);
94dd94f1b1SMatthew Dillon }
95dd94f1b1SMatthew Dillon if (hammer_btree_cmp(&mirror->key_beg, &mirror->key_end) > 0)
96dd94f1b1SMatthew Dillon return(EINVAL);
97dd94f1b1SMatthew Dillon
98dd94f1b1SMatthew Dillon mirror->key_cur = mirror->key_beg;
994c038e17SMatthew Dillon mirror->key_cur.localization &= HAMMER_LOCALIZE_MASK;
1007e52af60STomohiro Kusumi mirror->key_cur.localization |= localization;
101c82af904SMatthew Dillon bzero(&mrec, sizeof(mrec));
1024c038e17SMatthew Dillon bzero(&cmirror, sizeof(cmirror));
103dd94f1b1SMatthew Dillon
1044c286c36SMatthew Dillon /*
1054c286c36SMatthew Dillon * Make CRC errors non-fatal (at least on data), causing an EDOM
1064c286c36SMatthew Dillon * error instead of EIO.
1074c286c36SMatthew Dillon */
1084c286c36SMatthew Dillon trans->flags |= HAMMER_TRANSF_CRCDOM;
1094c286c36SMatthew Dillon
110dd94f1b1SMatthew Dillon retry:
111dd94f1b1SMatthew Dillon error = hammer_init_cursor(trans, &cursor, NULL, NULL);
112dd94f1b1SMatthew Dillon if (error) {
113dd94f1b1SMatthew Dillon hammer_done_cursor(&cursor);
114dd94f1b1SMatthew Dillon goto failed;
115dd94f1b1SMatthew Dillon }
116dd94f1b1SMatthew Dillon cursor.key_beg = mirror->key_cur;
117dd94f1b1SMatthew Dillon cursor.key_end = mirror->key_end;
1184c038e17SMatthew Dillon cursor.key_end.localization &= HAMMER_LOCALIZE_MASK;
1197e52af60STomohiro Kusumi cursor.key_end.localization |= localization;
120dd94f1b1SMatthew Dillon
121dd94f1b1SMatthew Dillon cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE;
122dd94f1b1SMatthew Dillon cursor.flags |= HAMMER_CURSOR_BACKEND;
123dd94f1b1SMatthew Dillon
124dd94f1b1SMatthew Dillon /*
125c82af904SMatthew Dillon * This flag filters the search to only return elements whos create
126c82af904SMatthew Dillon * or delete TID is >= mirror_tid. The B-Tree uses the mirror_tid
127c82af904SMatthew Dillon * field stored with internal and leaf nodes to shortcut the scan.
128dd94f1b1SMatthew Dillon */
129c82af904SMatthew Dillon cursor.flags |= HAMMER_CURSOR_MIRROR_FILTERED;
1304c038e17SMatthew Dillon cursor.cmirror = &cmirror;
1314c038e17SMatthew Dillon cmirror.mirror_tid = mirror->tid_beg;
132dd94f1b1SMatthew Dillon
133dd94f1b1SMatthew Dillon error = hammer_btree_first(&cursor);
134dd94f1b1SMatthew Dillon while (error == 0) {
135dd94f1b1SMatthew Dillon /*
13693291532SMatthew Dillon * Yield to more important tasks
13793291532SMatthew Dillon */
13893291532SMatthew Dillon if (error == 0) {
13993291532SMatthew Dillon error = hammer_signal_check(trans->hmp);
14093291532SMatthew Dillon if (error)
14193291532SMatthew Dillon break;
14293291532SMatthew Dillon }
14393291532SMatthew Dillon
14493291532SMatthew Dillon /*
1454c038e17SMatthew Dillon * An internal node can be returned in mirror-filtered
1464c038e17SMatthew Dillon * mode and indicates that the scan is returning a skip
1474c038e17SMatthew Dillon * range in the cursor->cmirror structure.
1484c038e17SMatthew Dillon */
1494c038e17SMatthew Dillon uptr = (char *)mirror->ubuf + mirror->count;
1504c038e17SMatthew Dillon if (cursor.node->ondisk->type == HAMMER_BTREE_TYPE_INTERNAL) {
1514c038e17SMatthew Dillon /*
1524c038e17SMatthew Dillon * Check space
1534c038e17SMatthew Dillon */
1544c038e17SMatthew Dillon mirror->key_cur = cmirror.skip_beg;
1554c038e17SMatthew Dillon bytes = sizeof(mrec.skip);
1564c038e17SMatthew Dillon if (mirror->count + HAMMER_HEAD_DOALIGN(bytes) >
1574c038e17SMatthew Dillon mirror->size) {
1584c038e17SMatthew Dillon break;
1594c038e17SMatthew Dillon }
1604c038e17SMatthew Dillon
1614c038e17SMatthew Dillon /*
1624c038e17SMatthew Dillon * Fill mrec
1634c038e17SMatthew Dillon */
1644c038e17SMatthew Dillon mrec.head.signature = HAMMER_IOC_MIRROR_SIGNATURE;
1654c038e17SMatthew Dillon mrec.head.type = HAMMER_MREC_TYPE_SKIP;
1664c038e17SMatthew Dillon mrec.head.rec_size = bytes;
1674c038e17SMatthew Dillon mrec.skip.skip_beg = cmirror.skip_beg;
1684c038e17SMatthew Dillon mrec.skip.skip_end = cmirror.skip_end;
169d8fe5eceSTomohiro Kusumi hammer_crc_set_mrec_head(&mrec.head, bytes);
1704c038e17SMatthew Dillon error = copyout(&mrec, uptr, bytes);
1714c038e17SMatthew Dillon eatdisk = 0;
1724c038e17SMatthew Dillon goto didwrite;
1734c038e17SMatthew Dillon }
1744c038e17SMatthew Dillon
1754c038e17SMatthew Dillon /*
1764c038e17SMatthew Dillon * Leaf node. In full-history mode we could filter out
1774c038e17SMatthew Dillon * elements modified outside the user-requested TID range.
1784c038e17SMatthew Dillon *
1794c038e17SMatthew Dillon * However, such elements must be returned so the writer
180f96881ffSMatthew Dillon * can compare them against the target to determine what
1814c038e17SMatthew Dillon * needs to be deleted on the target, particular for
1824c038e17SMatthew Dillon * no-history mirrors.
183dd94f1b1SMatthew Dillon */
184c82af904SMatthew Dillon KKASSERT(cursor.node->ondisk->type == HAMMER_BTREE_TYPE_LEAF);
185c82af904SMatthew Dillon elm = &cursor.node->ondisk->elms[cursor.index].leaf;
186c82af904SMatthew Dillon mirror->key_cur = elm->base;
187dd94f1b1SMatthew Dillon
188e469566bSMatthew Dillon /*
1893324b8cdSMatthew Dillon * If the record was created after our end point we just
1903324b8cdSMatthew Dillon * ignore it.
1913324b8cdSMatthew Dillon */
1923324b8cdSMatthew Dillon if (elm->base.create_tid > mirror->tid_end) {
1933324b8cdSMatthew Dillon error = 0;
1943324b8cdSMatthew Dillon bytes = 0;
1953324b8cdSMatthew Dillon eatdisk = 1;
1963324b8cdSMatthew Dillon goto didwrite;
1973324b8cdSMatthew Dillon }
1983324b8cdSMatthew Dillon
1993324b8cdSMatthew Dillon /*
200e469566bSMatthew Dillon * Determine if we should generate a PASS or a REC. PASS
201e469566bSMatthew Dillon * records are records without any data payload. Such
202e469566bSMatthew Dillon * records will be generated if the target is already expected
203e469566bSMatthew Dillon * to have the record, allowing it to delete the gaps.
204e469566bSMatthew Dillon *
205e469566bSMatthew Dillon * A PASS record is also used to perform deletions on the
206e469566bSMatthew Dillon * target.
207e469566bSMatthew Dillon *
208e469566bSMatthew Dillon * Such deletions are needed if the master or files on the
209e469566bSMatthew Dillon * master are no-history, or if the slave is so far behind
210e469566bSMatthew Dillon * the master has already been pruned.
211e469566bSMatthew Dillon */
2123324b8cdSMatthew Dillon if (elm->base.create_tid < mirror->tid_beg) {
2134c038e17SMatthew Dillon bytes = sizeof(mrec.rec);
2144c038e17SMatthew Dillon if (mirror->count + HAMMER_HEAD_DOALIGN(bytes) >
2154c038e17SMatthew Dillon mirror->size) {
2164c038e17SMatthew Dillon break;
2174c038e17SMatthew Dillon }
2184c038e17SMatthew Dillon
2194c038e17SMatthew Dillon /*
220e469566bSMatthew Dillon * Fill mrec.
2214c038e17SMatthew Dillon */
2224c038e17SMatthew Dillon mrec.head.signature = HAMMER_IOC_MIRROR_SIGNATURE;
2234c038e17SMatthew Dillon mrec.head.type = HAMMER_MREC_TYPE_PASS;
2244c038e17SMatthew Dillon mrec.head.rec_size = bytes;
2254c038e17SMatthew Dillon mrec.rec.leaf = *elm;
226d8fe5eceSTomohiro Kusumi hammer_crc_set_mrec_head(&mrec.head, bytes);
2274c038e17SMatthew Dillon error = copyout(&mrec, uptr, bytes);
2284c038e17SMatthew Dillon eatdisk = 1;
2294c038e17SMatthew Dillon goto didwrite;
2304c038e17SMatthew Dillon }
2314c038e17SMatthew Dillon
232dd94f1b1SMatthew Dillon /*
233c82af904SMatthew Dillon * The core code exports the data to userland.
2344c286c36SMatthew Dillon *
2354c286c36SMatthew Dillon * CRC errors on data are reported but passed through,
2364c286c36SMatthew Dillon * but the data must be washed by the user program.
23754ee5a26SMatthew Dillon *
23854ee5a26SMatthew Dillon * If userland just wants the btree records it can
23954ee5a26SMatthew Dillon * request that bulk data not be returned. This is
24054ee5a26SMatthew Dillon * use during mirror-stream histogram generation.
241dd94f1b1SMatthew Dillon */
2424c286c36SMatthew Dillon mrec_flags = 0;
243c82af904SMatthew Dillon data_len = (elm->data_offset) ? elm->data_len : 0;
24454ee5a26SMatthew Dillon if (data_len &&
24554ee5a26SMatthew Dillon (mirror->head.flags & HAMMER_IOC_MIRROR_NODATA)) {
24654ee5a26SMatthew Dillon data_len = 0;
24754ee5a26SMatthew Dillon mrec_flags |= HAMMER_MRECF_NODATA;
24854ee5a26SMatthew Dillon }
249c82af904SMatthew Dillon if (data_len) {
25040962009STomohiro Kusumi error = hammer_btree_extract_data(&cursor);
2514c286c36SMatthew Dillon if (error) {
2524c286c36SMatthew Dillon if (error != EDOM)
253c82af904SMatthew Dillon break;
2544c286c36SMatthew Dillon mrec_flags |= HAMMER_MRECF_CRC_ERROR |
2554c286c36SMatthew Dillon HAMMER_MRECF_DATA_CRC_BAD;
2564c286c36SMatthew Dillon }
257c82af904SMatthew Dillon }
2584c038e17SMatthew Dillon
2594c038e17SMatthew Dillon bytes = sizeof(mrec.rec) + data_len;
2604c038e17SMatthew Dillon if (mirror->count + HAMMER_HEAD_DOALIGN(bytes) > mirror->size)
261c82af904SMatthew Dillon break;
262c82af904SMatthew Dillon
263c82af904SMatthew Dillon /*
264c82af904SMatthew Dillon * Construct the record for userland and copyout.
265c82af904SMatthew Dillon *
266c82af904SMatthew Dillon * The user is asking for a snapshot, if the record was
267c82af904SMatthew Dillon * deleted beyond the user-requested ending tid, the record
268c82af904SMatthew Dillon * is not considered deleted from the point of view of
269c82af904SMatthew Dillon * userland and delete_tid is cleared.
270c82af904SMatthew Dillon */
2714c038e17SMatthew Dillon mrec.head.signature = HAMMER_IOC_MIRROR_SIGNATURE;
2724c286c36SMatthew Dillon mrec.head.type = HAMMER_MREC_TYPE_REC | mrec_flags;
2734c038e17SMatthew Dillon mrec.head.rec_size = bytes;
2744c038e17SMatthew Dillon mrec.rec.leaf = *elm;
2754c286c36SMatthew Dillon
2764889cbd4SMatthew Dillon if (elm->base.delete_tid > mirror->tid_end)
2774c038e17SMatthew Dillon mrec.rec.leaf.base.delete_tid = 0;
278d8fe5eceSTomohiro Kusumi rec_crc = hammer_crc_get_mrec_head(&mrec.head, sizeof(mrec.rec));
2794c038e17SMatthew Dillon if (data_len)
2804c038e17SMatthew Dillon rec_crc = crc32_ext(cursor.data, data_len, rec_crc);
2814c038e17SMatthew Dillon mrec.head.rec_crc = rec_crc;
2824c038e17SMatthew Dillon error = copyout(&mrec, uptr, sizeof(mrec.rec));
283c82af904SMatthew Dillon if (data_len && error == 0) {
2844c038e17SMatthew Dillon error = copyout(cursor.data, uptr + sizeof(mrec.rec),
285c82af904SMatthew Dillon data_len);
286c82af904SMatthew Dillon }
2874c038e17SMatthew Dillon eatdisk = 1;
2884c038e17SMatthew Dillon
2894c038e17SMatthew Dillon /*
2904c038e17SMatthew Dillon * eatdisk controls whether we skip the current cursor
2914c038e17SMatthew Dillon * position on the next scan or not. If doing a SKIP
2924c038e17SMatthew Dillon * the cursor is already positioned properly for the next
2934c038e17SMatthew Dillon * scan and eatdisk will be 0.
2944c038e17SMatthew Dillon */
2954c038e17SMatthew Dillon didwrite:
296dd94f1b1SMatthew Dillon if (error == 0) {
2974c038e17SMatthew Dillon mirror->count += HAMMER_HEAD_DOALIGN(bytes);
2984c038e17SMatthew Dillon if (eatdisk)
299dd94f1b1SMatthew Dillon cursor.flags |= HAMMER_CURSOR_ATEDISK;
3004c038e17SMatthew Dillon else
3014c038e17SMatthew Dillon cursor.flags &= ~HAMMER_CURSOR_ATEDISK;
302dd94f1b1SMatthew Dillon error = hammer_btree_iterate(&cursor);
303dd94f1b1SMatthew Dillon }
304dd94f1b1SMatthew Dillon }
305c82af904SMatthew Dillon if (error == ENOENT) {
306c82af904SMatthew Dillon mirror->key_cur = mirror->key_end;
307dd94f1b1SMatthew Dillon error = 0;
308c82af904SMatthew Dillon }
309dd94f1b1SMatthew Dillon hammer_done_cursor(&cursor);
310dd94f1b1SMatthew Dillon if (error == EDEADLK)
311dd94f1b1SMatthew Dillon goto retry;
312dd94f1b1SMatthew Dillon if (error == EINTR) {
313c82af904SMatthew Dillon mirror->head.flags |= HAMMER_IOC_HEAD_INTR;
314dd94f1b1SMatthew Dillon error = 0;
315dd94f1b1SMatthew Dillon }
316dd94f1b1SMatthew Dillon failed:
317dd94f1b1SMatthew Dillon mirror->key_cur.localization &= HAMMER_LOCALIZE_MASK;
318dd94f1b1SMatthew Dillon return(error);
319dd94f1b1SMatthew Dillon }
320dd94f1b1SMatthew Dillon
321c82af904SMatthew Dillon /*
3224c038e17SMatthew Dillon * Copy records from userland to the target mirror.
323602c6cb8SMatthew Dillon *
324ea434b6fSMatthew Dillon * The PFS is identified in the mirror structure. The passed ip is just
325ea434b6fSMatthew Dillon * some directory in the overall HAMMER filesystem and has nothing to
326ea434b6fSMatthew Dillon * do with the PFS. In fact, there might not even be a root directory for
327ea434b6fSMatthew Dillon * the PFS yet!
328c82af904SMatthew Dillon */
329c82af904SMatthew Dillon int
hammer_ioc_mirror_write(hammer_transaction_t trans,hammer_inode_t ip,struct hammer_ioc_mirror_rw * mirror)330c82af904SMatthew Dillon hammer_ioc_mirror_write(hammer_transaction_t trans, hammer_inode_t ip,
331c82af904SMatthew Dillon struct hammer_ioc_mirror_rw *mirror)
332c82af904SMatthew Dillon {
3334c038e17SMatthew Dillon union hammer_ioc_mrecord_any mrec;
334c82af904SMatthew Dillon struct hammer_cursor cursor;
33546137e17STomohiro Kusumi uint32_t localization;
33693291532SMatthew Dillon int checkspace_count = 0;
3374c038e17SMatthew Dillon int error;
3384c038e17SMatthew Dillon int bytes;
3394c038e17SMatthew Dillon char *uptr;
34093291532SMatthew Dillon int seq;
341ea434b6fSMatthew Dillon
34220cf2291STomohiro Kusumi localization = pfs_to_lo(mirror->pfs_id);
343e86903d8SMatthew Dillon seq = trans->hmp->flusher.done;
344c82af904SMatthew Dillon
3454c038e17SMatthew Dillon /*
3464c038e17SMatthew Dillon * Validate the mirror structure and relocalize the tracking keys.
3474c038e17SMatthew Dillon */
348c82af904SMatthew Dillon if (mirror->size < 0 || mirror->size > 0x70000000)
349c82af904SMatthew Dillon return(EINVAL);
3504c038e17SMatthew Dillon mirror->key_beg.localization &= HAMMER_LOCALIZE_MASK;
3517e52af60STomohiro Kusumi mirror->key_beg.localization |= localization;
3524c038e17SMatthew Dillon mirror->key_end.localization &= HAMMER_LOCALIZE_MASK;
3537e52af60STomohiro Kusumi mirror->key_end.localization |= localization;
3544c038e17SMatthew Dillon mirror->key_cur.localization &= HAMMER_LOCALIZE_MASK;
3557e52af60STomohiro Kusumi mirror->key_cur.localization |= localization;
356c82af904SMatthew Dillon
3574c038e17SMatthew Dillon /*
3584c038e17SMatthew Dillon * Set up our tracking cursor for the loop. The tracking cursor
3594c038e17SMatthew Dillon * is used to delete records that are no longer present on the
3604c038e17SMatthew Dillon * master. The last handled record at key_cur must be skipped.
3614c038e17SMatthew Dillon */
362c82af904SMatthew Dillon error = hammer_init_cursor(trans, &cursor, NULL, NULL);
363c82af904SMatthew Dillon
3644c038e17SMatthew Dillon cursor.key_beg = mirror->key_cur;
3654c038e17SMatthew Dillon cursor.key_end = mirror->key_end;
3664c038e17SMatthew Dillon cursor.flags |= HAMMER_CURSOR_BACKEND;
3674c038e17SMatthew Dillon error = hammer_btree_first(&cursor);
3684c038e17SMatthew Dillon if (error == 0)
3694c038e17SMatthew Dillon cursor.flags |= HAMMER_CURSOR_ATEDISK;
3704c038e17SMatthew Dillon if (error == ENOENT)
3714c038e17SMatthew Dillon error = 0;
3724c038e17SMatthew Dillon
3734c038e17SMatthew Dillon /*
3744c038e17SMatthew Dillon * Loop until our input buffer has been exhausted.
3754c038e17SMatthew Dillon */
3764c038e17SMatthew Dillon while (error == 0 &&
3774c038e17SMatthew Dillon mirror->count + sizeof(mrec.head) <= mirror->size) {
3784c038e17SMatthew Dillon
379c82af904SMatthew Dillon /*
38093291532SMatthew Dillon * Don't blow out the buffer cache. Leave room for frontend
38193291532SMatthew Dillon * cache as well.
382c9ce54d6SMatthew Dillon *
383c9ce54d6SMatthew Dillon * WARNING: See warnings in hammer_unlock_cursor() function.
38493291532SMatthew Dillon */
38515e75dabSMatthew Dillon while (hammer_flusher_meta_halflimit(trans->hmp) ||
3867a61b85dSMatthew Dillon hammer_flusher_undo_exhausted(trans, 2)) {
387982be4bfSMatthew Dillon hammer_unlock_cursor(&cursor);
38893291532SMatthew Dillon hammer_flusher_wait(trans->hmp, seq);
389982be4bfSMatthew Dillon hammer_lock_cursor(&cursor);
39015e75dabSMatthew Dillon seq = hammer_flusher_async_one(trans->hmp);
39193291532SMatthew Dillon }
39293291532SMatthew Dillon
39393291532SMatthew Dillon /*
39493291532SMatthew Dillon * If there is insufficient free space it may be due to
395a981af19STomohiro Kusumi * reserved big-blocks, which flushing might fix.
39693291532SMatthew Dillon */
39793291532SMatthew Dillon if (hammer_checkspace(trans->hmp, HAMMER_CHKSPC_MIRROR)) {
39893291532SMatthew Dillon if (++checkspace_count == 10) {
39993291532SMatthew Dillon error = ENOSPC;
40093291532SMatthew Dillon break;
40193291532SMatthew Dillon }
402982be4bfSMatthew Dillon hammer_unlock_cursor(&cursor);
40393291532SMatthew Dillon hammer_flusher_wait(trans->hmp, seq);
404982be4bfSMatthew Dillon hammer_lock_cursor(&cursor);
4057a61b85dSMatthew Dillon seq = hammer_flusher_async(trans->hmp, NULL);
40693291532SMatthew Dillon }
40793291532SMatthew Dillon
40893291532SMatthew Dillon
40993291532SMatthew Dillon /*
410c82af904SMatthew Dillon * Acquire and validate header
411c82af904SMatthew Dillon */
4124c038e17SMatthew Dillon if ((bytes = mirror->size - mirror->count) > sizeof(mrec))
4134c038e17SMatthew Dillon bytes = sizeof(mrec);
414c82af904SMatthew Dillon uptr = (char *)mirror->ubuf + mirror->count;
4154c038e17SMatthew Dillon error = copyin(uptr, &mrec, bytes);
416c82af904SMatthew Dillon if (error)
417c82af904SMatthew Dillon break;
4184c038e17SMatthew Dillon if (mrec.head.signature != HAMMER_IOC_MIRROR_SIGNATURE) {
419c82af904SMatthew Dillon error = EINVAL;
420c82af904SMatthew Dillon break;
421c82af904SMatthew Dillon }
4224c038e17SMatthew Dillon if (mrec.head.rec_size < sizeof(mrec.head) ||
4234c038e17SMatthew Dillon mrec.head.rec_size > sizeof(mrec) + HAMMER_XBUFSIZE ||
4244c038e17SMatthew Dillon mirror->count + mrec.head.rec_size > mirror->size) {
4255fa5c92fSMatthew Dillon error = EINVAL;
4265fa5c92fSMatthew Dillon break;
4275fa5c92fSMatthew Dillon }
4284c038e17SMatthew Dillon
4294c286c36SMatthew Dillon switch(mrec.head.type & HAMMER_MRECF_TYPE_MASK) {
4304c038e17SMatthew Dillon case HAMMER_MREC_TYPE_SKIP:
4314c038e17SMatthew Dillon if (mrec.head.rec_size != sizeof(mrec.skip))
4324c038e17SMatthew Dillon error = EINVAL;
4334c038e17SMatthew Dillon if (error == 0)
4344c038e17SMatthew Dillon error = hammer_ioc_mirror_write_skip(&cursor, &mrec.skip, mirror, localization);
4354c038e17SMatthew Dillon break;
4364c038e17SMatthew Dillon case HAMMER_MREC_TYPE_REC:
4374c038e17SMatthew Dillon if (mrec.head.rec_size < sizeof(mrec.rec))
4384c038e17SMatthew Dillon error = EINVAL;
4394c038e17SMatthew Dillon if (error == 0)
4404c038e17SMatthew Dillon error = hammer_ioc_mirror_write_rec(&cursor, &mrec.rec, mirror, localization, uptr + sizeof(mrec.rec));
4414c038e17SMatthew Dillon break;
44254ee5a26SMatthew Dillon case HAMMER_MREC_TYPE_REC_NODATA:
4434c286c36SMatthew Dillon case HAMMER_MREC_TYPE_REC_BADCRC:
4444c286c36SMatthew Dillon /*
4454c286c36SMatthew Dillon * Records with bad data payloads are ignored XXX.
44654ee5a26SMatthew Dillon * Records with no data payload have to be skipped
44754ee5a26SMatthew Dillon * (they shouldn't have been written in the first
44854ee5a26SMatthew Dillon * place).
4494c286c36SMatthew Dillon */
4504c286c36SMatthew Dillon if (mrec.head.rec_size < sizeof(mrec.rec))
4514c286c36SMatthew Dillon error = EINVAL;
4524c286c36SMatthew Dillon break;
4534c038e17SMatthew Dillon case HAMMER_MREC_TYPE_PASS:
4544c038e17SMatthew Dillon if (mrec.head.rec_size != sizeof(mrec.rec))
4554c038e17SMatthew Dillon error = EINVAL;
4564c038e17SMatthew Dillon if (error == 0)
4574c038e17SMatthew Dillon error = hammer_ioc_mirror_write_pass(&cursor, &mrec.rec, mirror, localization);
4584c038e17SMatthew Dillon break;
4594c038e17SMatthew Dillon default:
460c82af904SMatthew Dillon error = EINVAL;
461c82af904SMatthew Dillon break;
462c82af904SMatthew Dillon }
4634c038e17SMatthew Dillon
4644c038e17SMatthew Dillon /*
4654c038e17SMatthew Dillon * Retry the current record on deadlock, otherwise setup
4664c038e17SMatthew Dillon * for the next loop.
4674c038e17SMatthew Dillon */
4684c038e17SMatthew Dillon if (error == EDEADLK) {
4694c038e17SMatthew Dillon while (error == EDEADLK) {
470f3a4893bSMatthew Dillon hammer_sync_lock_sh(trans);
4714c038e17SMatthew Dillon hammer_recover_cursor(&cursor);
4724c038e17SMatthew Dillon error = hammer_cursor_upgrade(&cursor);
473f3a4893bSMatthew Dillon hammer_sync_unlock(trans);
474c82af904SMatthew Dillon }
4754c038e17SMatthew Dillon } else {
4764c038e17SMatthew Dillon if (error == EALREADY)
4774c038e17SMatthew Dillon error = 0;
4784c038e17SMatthew Dillon if (error == 0) {
4794c038e17SMatthew Dillon mirror->count +=
4804c038e17SMatthew Dillon HAMMER_HEAD_DOALIGN(mrec.head.rec_size);
4814c038e17SMatthew Dillon }
4824c038e17SMatthew Dillon }
4834c038e17SMatthew Dillon }
4844c038e17SMatthew Dillon hammer_done_cursor(&cursor);
4854c038e17SMatthew Dillon
4864c038e17SMatthew Dillon /*
4874c038e17SMatthew Dillon * cumulative error
4884c038e17SMatthew Dillon */
4894c038e17SMatthew Dillon if (error) {
4904c038e17SMatthew Dillon mirror->head.flags |= HAMMER_IOC_HEAD_ERROR;
4914c038e17SMatthew Dillon mirror->head.error = error;
4924c038e17SMatthew Dillon }
4934c038e17SMatthew Dillon
4944c038e17SMatthew Dillon /*
4954c038e17SMatthew Dillon * ioctls don't update the RW data structure if an error is returned,
4964c038e17SMatthew Dillon * always return 0.
4974c038e17SMatthew Dillon */
4984c038e17SMatthew Dillon return(0);
4994c038e17SMatthew Dillon }
5004c038e17SMatthew Dillon
5014c038e17SMatthew Dillon /*
5024c038e17SMatthew Dillon * Handle skip records.
5034c038e17SMatthew Dillon *
5044c038e17SMatthew Dillon * We must iterate from the last resolved record position at mirror->key_cur
5053324b8cdSMatthew Dillon * to skip_beg non-inclusive and delete any records encountered.
5064c038e17SMatthew Dillon *
5074c038e17SMatthew Dillon * mirror->key_cur must be carefully set when we succeed in processing
5084c038e17SMatthew Dillon * this mrec.
5094c038e17SMatthew Dillon */
5104c038e17SMatthew Dillon static int
hammer_ioc_mirror_write_skip(hammer_cursor_t cursor,struct hammer_ioc_mrecord_skip * mrec,struct hammer_ioc_mirror_rw * mirror,uint32_t localization)5114c038e17SMatthew Dillon hammer_ioc_mirror_write_skip(hammer_cursor_t cursor,
5124c038e17SMatthew Dillon struct hammer_ioc_mrecord_skip *mrec,
5134c038e17SMatthew Dillon struct hammer_ioc_mirror_rw *mirror,
51446137e17STomohiro Kusumi uint32_t localization)
5154c038e17SMatthew Dillon {
5164c038e17SMatthew Dillon int error;
5174c038e17SMatthew Dillon
5184c038e17SMatthew Dillon /*
5194c038e17SMatthew Dillon * Relocalize the skip range
5204c038e17SMatthew Dillon */
5214c038e17SMatthew Dillon mrec->skip_beg.localization &= HAMMER_LOCALIZE_MASK;
5227e52af60STomohiro Kusumi mrec->skip_beg.localization |= localization;
5234c038e17SMatthew Dillon mrec->skip_end.localization &= HAMMER_LOCALIZE_MASK;
5247e52af60STomohiro Kusumi mrec->skip_end.localization |= localization;
5254c038e17SMatthew Dillon
5264c038e17SMatthew Dillon /*
5274c038e17SMatthew Dillon * Iterate from current position to skip_beg, deleting any records
5283324b8cdSMatthew Dillon * we encounter. The record at skip_beg is not included (it is
5293324b8cdSMatthew Dillon * skipped).
5304c038e17SMatthew Dillon */
5314c038e17SMatthew Dillon cursor->key_end = mrec->skip_beg;
5323324b8cdSMatthew Dillon cursor->flags &= ~HAMMER_CURSOR_END_INCLUSIVE;
5334c038e17SMatthew Dillon cursor->flags |= HAMMER_CURSOR_BACKEND;
534842e7a70SMatthew Dillon error = hammer_mirror_delete_to(cursor, mirror);
5354c038e17SMatthew Dillon
5364c038e17SMatthew Dillon /*
5374c038e17SMatthew Dillon * Now skip past the skip (which is the whole point point of
5384c038e17SMatthew Dillon * having a skip record). The sender has not sent us any records
5394c038e17SMatthew Dillon * for the skip area so we wouldn't know what to keep and what
5404c038e17SMatthew Dillon * to delete anyway.
5414c038e17SMatthew Dillon *
5424c038e17SMatthew Dillon * Clear ATEDISK because skip_end is non-inclusive, so we can't
5434c038e17SMatthew Dillon * count an exact match if we happened to get one.
5444c038e17SMatthew Dillon */
5454c038e17SMatthew Dillon if (error == 0) {
5464c038e17SMatthew Dillon mirror->key_cur = mrec->skip_end;
5474c038e17SMatthew Dillon cursor->key_beg = mrec->skip_end;
5484c038e17SMatthew Dillon error = hammer_btree_lookup(cursor);
5494c038e17SMatthew Dillon cursor->flags &= ~HAMMER_CURSOR_ATEDISK;
5504c038e17SMatthew Dillon if (error == ENOENT)
5514c038e17SMatthew Dillon error = 0;
5524c038e17SMatthew Dillon }
5534c038e17SMatthew Dillon return(error);
5544c038e17SMatthew Dillon }
5554c038e17SMatthew Dillon
5564c038e17SMatthew Dillon /*
5574c038e17SMatthew Dillon * Handle B-Tree records.
5584c038e17SMatthew Dillon *
5594c038e17SMatthew Dillon * We must iterate to mrec->base.key (non-inclusively), and then process
5604c038e17SMatthew Dillon * the record. We are allowed to write a new record or delete an existing
5614c038e17SMatthew Dillon * record, but cannot replace an existing record.
5624c038e17SMatthew Dillon *
5634c038e17SMatthew Dillon * mirror->key_cur must be carefully set when we succeed in processing
5644c038e17SMatthew Dillon * this mrec.
5654c038e17SMatthew Dillon */
5664c038e17SMatthew Dillon static int
hammer_ioc_mirror_write_rec(hammer_cursor_t cursor,struct hammer_ioc_mrecord_rec * mrec,struct hammer_ioc_mirror_rw * mirror,uint32_t localization,char * uptr)5674c038e17SMatthew Dillon hammer_ioc_mirror_write_rec(hammer_cursor_t cursor,
5684c038e17SMatthew Dillon struct hammer_ioc_mrecord_rec *mrec,
5694c038e17SMatthew Dillon struct hammer_ioc_mirror_rw *mirror,
57046137e17STomohiro Kusumi uint32_t localization,
5714c038e17SMatthew Dillon char *uptr)
5724c038e17SMatthew Dillon {
5734c038e17SMatthew Dillon int error;
5744c038e17SMatthew Dillon
5754c038e17SMatthew Dillon if (mrec->leaf.data_len < 0 ||
5764c038e17SMatthew Dillon mrec->leaf.data_len > HAMMER_XBUFSIZE ||
5774c038e17SMatthew Dillon mrec->leaf.data_len + sizeof(*mrec) > mrec->head.rec_size) {
5784c038e17SMatthew Dillon return(EINVAL);
579c82af904SMatthew Dillon }
580c82af904SMatthew Dillon
581c82af904SMatthew Dillon /*
582c82af904SMatthew Dillon * Re-localize for target. relocalization of data is handled
583913505ffSTomohiro Kusumi * by hammer_create_at_cursor().
584c82af904SMatthew Dillon */
5854c038e17SMatthew Dillon mrec->leaf.base.localization &= HAMMER_LOCALIZE_MASK;
5867e52af60STomohiro Kusumi mrec->leaf.base.localization |= localization;
5874c038e17SMatthew Dillon
5884c038e17SMatthew Dillon /*
5894c038e17SMatthew Dillon * Delete records through until we reach (non-inclusively) the
5904c038e17SMatthew Dillon * target record.
5914c038e17SMatthew Dillon */
5924c038e17SMatthew Dillon cursor->key_end = mrec->leaf.base;
5934c038e17SMatthew Dillon cursor->flags &= ~HAMMER_CURSOR_END_INCLUSIVE;
5944c038e17SMatthew Dillon cursor->flags |= HAMMER_CURSOR_BACKEND;
595842e7a70SMatthew Dillon error = hammer_mirror_delete_to(cursor, mirror);
596c82af904SMatthew Dillon
597c82af904SMatthew Dillon /*
59883f2a3aaSMatthew Dillon * Certain records are not part of the mirroring operation
59983f2a3aaSMatthew Dillon */
600bbb01e14SMatthew Dillon if (error == 0 && hammer_mirror_nomirror(&mrec->leaf.base))
60183f2a3aaSMatthew Dillon return(0);
60283f2a3aaSMatthew Dillon
60383f2a3aaSMatthew Dillon /*
604c82af904SMatthew Dillon * Locate the record.
605c82af904SMatthew Dillon *
606c82af904SMatthew Dillon * If the record exists only the delete_tid may be updated.
607c82af904SMatthew Dillon *
608e469566bSMatthew Dillon * If the record does not exist we can create it only if the
609e469566bSMatthew Dillon * create_tid is not too old. If the create_tid is too old
610e469566bSMatthew Dillon * it may have already been destroyed on the slave from pruning.
611e469566bSMatthew Dillon *
612e469566bSMatthew Dillon * Note that mirror operations are effectively as-of operations
613e469566bSMatthew Dillon * and delete_tid can be 0 for mirroring purposes even if it is
614c82af904SMatthew Dillon * not actually 0 at the originator.
61598da6d8cSMatthew Dillon *
61698da6d8cSMatthew Dillon * These functions can return EDEADLK
617c82af904SMatthew Dillon */
618bbb01e14SMatthew Dillon if (error == 0) {
6194c038e17SMatthew Dillon cursor->key_beg = mrec->leaf.base;
6204c038e17SMatthew Dillon cursor->flags |= HAMMER_CURSOR_BACKEND;
6214c038e17SMatthew Dillon cursor->flags &= ~HAMMER_CURSOR_INSERT;
6224c038e17SMatthew Dillon error = hammer_btree_lookup(cursor);
623bbb01e14SMatthew Dillon }
624c82af904SMatthew Dillon
6254c038e17SMatthew Dillon if (error == 0 && hammer_mirror_check(cursor, mrec)) {
6264c038e17SMatthew Dillon error = hammer_mirror_update(cursor, mrec);
627adf01747SMatthew Dillon } else if (error == ENOENT) {
62883f2a3aaSMatthew Dillon if (mrec->leaf.base.create_tid >= mirror->tid_beg) {
62983f2a3aaSMatthew Dillon error = hammer_create_at_cursor(
63083f2a3aaSMatthew Dillon cursor, &mrec->leaf,
63183f2a3aaSMatthew Dillon uptr, HAMMER_CREATE_MODE_UMIRROR);
63283f2a3aaSMatthew Dillon } else {
633adf01747SMatthew Dillon error = 0;
634c82af904SMatthew Dillon }
63583f2a3aaSMatthew Dillon }
6364c038e17SMatthew Dillon if (error == 0 || error == EALREADY)
6374c038e17SMatthew Dillon mirror->key_cur = mrec->leaf.base;
6384c038e17SMatthew Dillon return(error);
6394c038e17SMatthew Dillon }
640c82af904SMatthew Dillon
641c82af904SMatthew Dillon /*
6424c038e17SMatthew Dillon * This works like write_rec but no write or update is necessary,
6434c038e17SMatthew Dillon * and no data payload is included so we couldn't do a write even
6444c038e17SMatthew Dillon * if we wanted to.
6454c038e17SMatthew Dillon *
6464c038e17SMatthew Dillon * We must still iterate for deletions, and we can validate the
6474c038e17SMatthew Dillon * record header which is a good way to test for corrupted mirror
6484c038e17SMatthew Dillon * targets XXX.
6494c038e17SMatthew Dillon *
6504c038e17SMatthew Dillon * mirror->key_cur must be carefully set when we succeed in processing
6514c038e17SMatthew Dillon * this mrec.
652c82af904SMatthew Dillon */
6534c038e17SMatthew Dillon static
6544c038e17SMatthew Dillon int
hammer_ioc_mirror_write_pass(hammer_cursor_t cursor,struct hammer_ioc_mrecord_rec * mrec,struct hammer_ioc_mirror_rw * mirror,uint32_t localization)6554c038e17SMatthew Dillon hammer_ioc_mirror_write_pass(hammer_cursor_t cursor,
6564c038e17SMatthew Dillon struct hammer_ioc_mrecord_rec *mrec,
6574c038e17SMatthew Dillon struct hammer_ioc_mirror_rw *mirror,
65846137e17STomohiro Kusumi uint32_t localization)
6594c038e17SMatthew Dillon {
6604c038e17SMatthew Dillon int error;
6614c038e17SMatthew Dillon
6624c038e17SMatthew Dillon /*
6634c038e17SMatthew Dillon * Re-localize for target. Relocalization of data is handled
664913505ffSTomohiro Kusumi * by hammer_create_at_cursor().
6654c038e17SMatthew Dillon */
6664c038e17SMatthew Dillon mrec->leaf.base.localization &= HAMMER_LOCALIZE_MASK;
6677e52af60STomohiro Kusumi mrec->leaf.base.localization |= localization;
6684c038e17SMatthew Dillon
6694c038e17SMatthew Dillon /*
6704c038e17SMatthew Dillon * Delete records through until we reach (non-inclusively) the
6714c038e17SMatthew Dillon * target record.
6724c038e17SMatthew Dillon */
6734c038e17SMatthew Dillon cursor->key_end = mrec->leaf.base;
6744c038e17SMatthew Dillon cursor->flags &= ~HAMMER_CURSOR_END_INCLUSIVE;
6754c038e17SMatthew Dillon cursor->flags |= HAMMER_CURSOR_BACKEND;
676842e7a70SMatthew Dillon error = hammer_mirror_delete_to(cursor, mirror);
6774c038e17SMatthew Dillon
6784c038e17SMatthew Dillon /*
67983f2a3aaSMatthew Dillon * Certain records are not part of the mirroring operation
68083f2a3aaSMatthew Dillon */
68183f2a3aaSMatthew Dillon if (hammer_mirror_nomirror(&mrec->leaf.base))
68283f2a3aaSMatthew Dillon return(0);
68383f2a3aaSMatthew Dillon
68483f2a3aaSMatthew Dillon /*
685e469566bSMatthew Dillon * Locate the record and get past it by setting ATEDISK. Perform
686e469566bSMatthew Dillon * any necessary deletions. We have no data payload and cannot
687e469566bSMatthew Dillon * create a new record.
6884c038e17SMatthew Dillon */
6894c038e17SMatthew Dillon if (error == 0) {
6904c038e17SMatthew Dillon mirror->key_cur = mrec->leaf.base;
6914c038e17SMatthew Dillon cursor->key_beg = mrec->leaf.base;
6924c038e17SMatthew Dillon cursor->flags |= HAMMER_CURSOR_BACKEND;
6934c038e17SMatthew Dillon cursor->flags &= ~HAMMER_CURSOR_INSERT;
6944c038e17SMatthew Dillon error = hammer_btree_lookup(cursor);
695e469566bSMatthew Dillon if (error == 0) {
696e469566bSMatthew Dillon if (hammer_mirror_check(cursor, mrec))
697e469566bSMatthew Dillon error = hammer_mirror_update(cursor, mrec);
6984c038e17SMatthew Dillon cursor->flags |= HAMMER_CURSOR_ATEDISK;
699e469566bSMatthew Dillon } else {
7004c038e17SMatthew Dillon cursor->flags &= ~HAMMER_CURSOR_ATEDISK;
701e469566bSMatthew Dillon }
7024c038e17SMatthew Dillon if (error == ENOENT)
7034c038e17SMatthew Dillon error = 0;
7044c038e17SMatthew Dillon }
7054c038e17SMatthew Dillon return(error);
706c82af904SMatthew Dillon }
707adf01747SMatthew Dillon
7084c038e17SMatthew Dillon /*
7094c038e17SMatthew Dillon * As part of the mirror write we iterate across swaths of records
7104c038e17SMatthew Dillon * on the target which no longer exist on the source, and mark them
7114c038e17SMatthew Dillon * deleted.
712842e7a70SMatthew Dillon *
713842e7a70SMatthew Dillon * The caller has indexed the cursor and set up key_end. We iterate
714842e7a70SMatthew Dillon * through to key_end.
715f96881ffSMatthew Dillon *
716f96881ffSMatthew Dillon * There is an edge case where the master has deleted a record whos
717f96881ffSMatthew Dillon * create_tid exactly matches our end_tid. We cannot delete this
718f96881ffSMatthew Dillon * record on the slave yet because we cannot assign delete_tid == create_tid.
719f96881ffSMatthew Dillon * The deletion should be picked up on the next sequence since in order
720f96881ffSMatthew Dillon * to have been deleted on the master a transaction must have occured with
721f96881ffSMatthew Dillon * a TID greater then the create_tid of the record.
7223324b8cdSMatthew Dillon *
7233324b8cdSMatthew Dillon * To support incremental re-mirroring, just for robustness, we do not
7243324b8cdSMatthew Dillon * touch any records created beyond (or equal to) mirror->tid_end.
7254c038e17SMatthew Dillon */
7264c038e17SMatthew Dillon static
7274c038e17SMatthew Dillon int
hammer_mirror_delete_to(hammer_cursor_t cursor,struct hammer_ioc_mirror_rw * mirror)728842e7a70SMatthew Dillon hammer_mirror_delete_to(hammer_cursor_t cursor,
7294c038e17SMatthew Dillon struct hammer_ioc_mirror_rw *mirror)
7304c038e17SMatthew Dillon {
731842e7a70SMatthew Dillon hammer_btree_leaf_elm_t elm;
73298da6d8cSMatthew Dillon int error;
73398da6d8cSMatthew Dillon
734842e7a70SMatthew Dillon error = hammer_btree_iterate(cursor);
735842e7a70SMatthew Dillon while (error == 0) {
736842e7a70SMatthew Dillon elm = &cursor->node->ondisk->elms[cursor->index].leaf;
737842e7a70SMatthew Dillon KKASSERT(elm->base.btype == HAMMER_BTREE_TYPE_RECORD);
7384889cbd4SMatthew Dillon cursor->flags |= HAMMER_CURSOR_ATEDISK;
7393324b8cdSMatthew Dillon
7403324b8cdSMatthew Dillon /*
74183f2a3aaSMatthew Dillon * Certain records are not part of the mirroring operation
74283f2a3aaSMatthew Dillon */
74383f2a3aaSMatthew Dillon if (hammer_mirror_nomirror(&elm->base)) {
74483f2a3aaSMatthew Dillon error = hammer_btree_iterate(cursor);
74583f2a3aaSMatthew Dillon continue;
74683f2a3aaSMatthew Dillon }
74783f2a3aaSMatthew Dillon
74883f2a3aaSMatthew Dillon /*
7493324b8cdSMatthew Dillon * Note: Must still delete records with create_tid < tid_beg,
7503324b8cdSMatthew Dillon * as record may have been pruned-away on source.
7513324b8cdSMatthew Dillon */
752f96881ffSMatthew Dillon if (elm->base.delete_tid == 0 &&
7533324b8cdSMatthew Dillon elm->base.create_tid < mirror->tid_end) {
754842e7a70SMatthew Dillon error = hammer_delete_at_cursor(cursor,
755842e7a70SMatthew Dillon HAMMER_DELETE_ADJUST,
756842e7a70SMatthew Dillon mirror->tid_end,
757842e7a70SMatthew Dillon time_second,
758842e7a70SMatthew Dillon 1, NULL);
759842e7a70SMatthew Dillon }
760842e7a70SMatthew Dillon if (error == 0)
761842e7a70SMatthew Dillon error = hammer_btree_iterate(cursor);
762842e7a70SMatthew Dillon }
763842e7a70SMatthew Dillon if (error == ENOENT)
764842e7a70SMatthew Dillon error = 0;
765842e7a70SMatthew Dillon return(error);
766c82af904SMatthew Dillon }
767c82af904SMatthew Dillon
768c82af904SMatthew Dillon /*
769c82af904SMatthew Dillon * Check whether an update is needed in the case where a match already
770c82af904SMatthew Dillon * exists on the target. The only type of update allowed in this case
771c82af904SMatthew Dillon * is an update of the delete_tid.
772c82af904SMatthew Dillon *
773c82af904SMatthew Dillon * Return non-zero if the update should proceed.
774c82af904SMatthew Dillon */
775c82af904SMatthew Dillon static
776c82af904SMatthew Dillon int
hammer_mirror_check(hammer_cursor_t cursor,struct hammer_ioc_mrecord_rec * mrec)7774c038e17SMatthew Dillon hammer_mirror_check(hammer_cursor_t cursor, struct hammer_ioc_mrecord_rec *mrec)
778c82af904SMatthew Dillon {
779c82af904SMatthew Dillon hammer_btree_leaf_elm_t leaf = cursor->leaf;
780c82af904SMatthew Dillon
781c82af904SMatthew Dillon if (leaf->base.delete_tid != mrec->leaf.base.delete_tid) {
782ea434b6fSMatthew Dillon if (mrec->leaf.base.delete_tid != 0)
783c82af904SMatthew Dillon return(1);
784c82af904SMatthew Dillon }
785c82af904SMatthew Dillon return(0);
786c82af904SMatthew Dillon }
787c82af904SMatthew Dillon
788c82af904SMatthew Dillon /*
78983f2a3aaSMatthew Dillon * Filter out records which are never mirrored, such as configuration space
79083f2a3aaSMatthew Dillon * records (for hammer cleanup).
79183f2a3aaSMatthew Dillon *
79283f2a3aaSMatthew Dillon * NOTE: We currently allow HAMMER_RECTYPE_SNAPSHOT records to be mirrored.
79383f2a3aaSMatthew Dillon */
79483f2a3aaSMatthew Dillon static
79583f2a3aaSMatthew Dillon int
hammer_mirror_nomirror(hammer_base_elm_t base)7965f532f10STomohiro Kusumi hammer_mirror_nomirror(hammer_base_elm_t base)
79783f2a3aaSMatthew Dillon {
79883f2a3aaSMatthew Dillon /*
79983f2a3aaSMatthew Dillon * Certain types of records are never updated when mirroring.
80083f2a3aaSMatthew Dillon * Slaves have their own configuration space.
80183f2a3aaSMatthew Dillon */
80283f2a3aaSMatthew Dillon if (base->rec_type == HAMMER_RECTYPE_CONFIG)
80383f2a3aaSMatthew Dillon return(1);
80483f2a3aaSMatthew Dillon return(0);
80583f2a3aaSMatthew Dillon }
80683f2a3aaSMatthew Dillon
80783f2a3aaSMatthew Dillon
80883f2a3aaSMatthew Dillon /*
809842e7a70SMatthew Dillon * Update a record in-place. Only the delete_tid can change, and
810842e7a70SMatthew Dillon * only from zero to non-zero.
811c82af904SMatthew Dillon */
812c82af904SMatthew Dillon static
813c82af904SMatthew Dillon int
hammer_mirror_update(hammer_cursor_t cursor,struct hammer_ioc_mrecord_rec * mrec)8144c038e17SMatthew Dillon hammer_mirror_update(hammer_cursor_t cursor,
8154c038e17SMatthew Dillon struct hammer_ioc_mrecord_rec *mrec)
816c82af904SMatthew Dillon {
81798da6d8cSMatthew Dillon int error;
81898da6d8cSMatthew Dillon
819842e7a70SMatthew Dillon /*
820842e7a70SMatthew Dillon * This case shouldn't occur.
821842e7a70SMatthew Dillon */
822842e7a70SMatthew Dillon if (mrec->leaf.base.delete_tid == 0)
82306ad81ffSMatthew Dillon return(0);
824adf01747SMatthew Dillon
825adf01747SMatthew Dillon /*
826842e7a70SMatthew Dillon * Mark the record deleted on the mirror target.
8274c038e17SMatthew Dillon */
828842e7a70SMatthew Dillon error = hammer_delete_at_cursor(cursor, HAMMER_DELETE_ADJUST,
829842e7a70SMatthew Dillon mrec->leaf.base.delete_tid,
830842e7a70SMatthew Dillon mrec->leaf.delete_ts,
831842e7a70SMatthew Dillon 1, NULL);
8324c038e17SMatthew Dillon cursor->flags |= HAMMER_CURSOR_ATEDISK;
833842e7a70SMatthew Dillon return(error);
834c82af904SMatthew Dillon }
835