xref: /dflybsd-src/sys/vfs/hammer/hammer_mirror.c (revision 602c6cb864a1dea3aca7d0958cfd8ae79b413894)
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  *
34*602c6cb8SMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_mirror.c,v 1.6 2008/07/04 07:25:36 dillon Exp $
35dd94f1b1SMatthew Dillon  */
36dd94f1b1SMatthew Dillon /*
37dd94f1b1SMatthew Dillon  * HAMMER mirroring ioctls - serialize and deserialize modifications made
38dd94f1b1SMatthew Dillon  *			     to a filesystem.
39dd94f1b1SMatthew Dillon  */
40dd94f1b1SMatthew Dillon 
41dd94f1b1SMatthew Dillon #include "hammer.h"
42dd94f1b1SMatthew Dillon 
43c82af904SMatthew Dillon static int hammer_mirror_check(hammer_cursor_t cursor,
44c82af904SMatthew Dillon 				struct hammer_ioc_mrecord *mrec);
45c82af904SMatthew Dillon static int hammer_mirror_update(hammer_cursor_t cursor,
46c82af904SMatthew Dillon 				struct hammer_ioc_mrecord *mrec);
47c82af904SMatthew Dillon static int hammer_mirror_write(hammer_cursor_t cursor,
48c82af904SMatthew Dillon 				struct hammer_ioc_mrecord *mrec,
49*602c6cb8SMatthew Dillon 				hammer_inode_t ip, char *udata);
50c82af904SMatthew Dillon static int hammer_mirror_localize_data(hammer_data_ondisk_t data,
51c82af904SMatthew Dillon 				hammer_btree_leaf_elm_t leaf);
52c82af904SMatthew Dillon 
53c82af904SMatthew Dillon /*
54c82af904SMatthew Dillon  * All B-Tree records within the specified key range which also conform
55c82af904SMatthew Dillon  * to the transaction id range are returned.  Mirroring code keeps track
56c82af904SMatthew Dillon  * of the last transaction id fully scanned and can efficiently pick up
57c82af904SMatthew Dillon  * where it left off if interrupted.
58c82af904SMatthew Dillon  */
59dd94f1b1SMatthew Dillon int
60dd94f1b1SMatthew Dillon hammer_ioc_mirror_read(hammer_transaction_t trans, hammer_inode_t ip,
61dd94f1b1SMatthew Dillon 		       struct hammer_ioc_mirror_rw *mirror)
62dd94f1b1SMatthew Dillon {
63dd94f1b1SMatthew Dillon 	struct hammer_cursor cursor;
64c82af904SMatthew Dillon 	struct hammer_ioc_mrecord mrec;
65c82af904SMatthew Dillon 	hammer_btree_leaf_elm_t elm;
66c82af904SMatthew Dillon 	const int head_size = HAMMER_MREC_HEADSIZE;
67c82af904SMatthew Dillon 	const int crc_start = HAMMER_MREC_CRCOFF;
68c82af904SMatthew Dillon 	char *uptr;
69dd94f1b1SMatthew Dillon 	int error;
70c82af904SMatthew Dillon 	int data_len;
71c82af904SMatthew Dillon 	int bytes;
72dd94f1b1SMatthew Dillon 
73dd94f1b1SMatthew Dillon 	if ((mirror->key_beg.localization | mirror->key_end.localization) &
74dd94f1b1SMatthew Dillon 	    HAMMER_LOCALIZE_PSEUDOFS_MASK) {
75dd94f1b1SMatthew Dillon 		return(EINVAL);
76dd94f1b1SMatthew Dillon 	}
77dd94f1b1SMatthew Dillon 	if (hammer_btree_cmp(&mirror->key_beg, &mirror->key_end) > 0)
78dd94f1b1SMatthew Dillon 		return(EINVAL);
79dd94f1b1SMatthew Dillon 
80dd94f1b1SMatthew Dillon 	mirror->key_cur = mirror->key_beg;
81dd94f1b1SMatthew Dillon 	mirror->key_cur.localization += ip->obj_localization;
82c82af904SMatthew Dillon 	bzero(&mrec, sizeof(mrec));
83dd94f1b1SMatthew Dillon 
84dd94f1b1SMatthew Dillon retry:
85dd94f1b1SMatthew Dillon 	error = hammer_init_cursor(trans, &cursor, NULL, NULL);
86dd94f1b1SMatthew Dillon 	if (error) {
87dd94f1b1SMatthew Dillon 		hammer_done_cursor(&cursor);
88dd94f1b1SMatthew Dillon 		goto failed;
89dd94f1b1SMatthew Dillon 	}
90dd94f1b1SMatthew Dillon 	cursor.key_beg = mirror->key_cur;
91dd94f1b1SMatthew Dillon 	cursor.key_end = mirror->key_end;
92dd94f1b1SMatthew Dillon 	cursor.key_end.localization += ip->obj_localization;
93dd94f1b1SMatthew Dillon 
94dd94f1b1SMatthew Dillon 	cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE;
95dd94f1b1SMatthew Dillon 	cursor.flags |= HAMMER_CURSOR_BACKEND;
96dd94f1b1SMatthew Dillon 
97dd94f1b1SMatthew Dillon 	/*
98c82af904SMatthew Dillon 	 * This flag filters the search to only return elements whos create
99c82af904SMatthew Dillon 	 * or delete TID is >= mirror_tid.  The B-Tree uses the mirror_tid
100c82af904SMatthew Dillon 	 * field stored with internal and leaf nodes to shortcut the scan.
101dd94f1b1SMatthew Dillon 	 */
102c82af904SMatthew Dillon 	cursor.flags |= HAMMER_CURSOR_MIRROR_FILTERED;
103c82af904SMatthew Dillon 	cursor.mirror_tid = mirror->tid_beg;
104dd94f1b1SMatthew Dillon 
105dd94f1b1SMatthew Dillon 	error = hammer_btree_first(&cursor);
106dd94f1b1SMatthew Dillon 	while (error == 0) {
107dd94f1b1SMatthew Dillon 		/*
108c82af904SMatthew Dillon 		 * Leaf node.  Only return elements modified in the range
109c82af904SMatthew Dillon 		 * requested by userland.
110dd94f1b1SMatthew Dillon 		 */
111c82af904SMatthew Dillon 		KKASSERT(cursor.node->ondisk->type == HAMMER_BTREE_TYPE_LEAF);
112c82af904SMatthew Dillon 		elm = &cursor.node->ondisk->elms[cursor.index].leaf;
113c82af904SMatthew Dillon 
114c82af904SMatthew Dillon 		if (elm->base.create_tid < mirror->tid_beg ||
115c82af904SMatthew Dillon 		    elm->base.create_tid >= mirror->tid_end) {
116c82af904SMatthew Dillon 			if (elm->base.delete_tid < mirror->tid_beg ||
117c82af904SMatthew Dillon 			    elm->base.delete_tid >= mirror->tid_end) {
118c82af904SMatthew Dillon 				goto skip;
119c82af904SMatthew Dillon 			}
120c82af904SMatthew Dillon 		}
121c82af904SMatthew Dillon 
122c82af904SMatthew Dillon 		mirror->key_cur = elm->base;
123dd94f1b1SMatthew Dillon 
124dd94f1b1SMatthew Dillon 		/*
125dd94f1b1SMatthew Dillon 		 * Yield to more important tasks
126dd94f1b1SMatthew Dillon 		 */
127dd94f1b1SMatthew Dillon 		if ((error = hammer_signal_check(trans->hmp)) != 0)
128dd94f1b1SMatthew Dillon 			break;
129dd94f1b1SMatthew Dillon 		if (trans->hmp->sync_lock.wanted) {
130dd94f1b1SMatthew Dillon 			tsleep(trans, 0, "hmrslo", hz / 10);
131dd94f1b1SMatthew Dillon 		}
132f5a07a7aSMatthew Dillon 		if (trans->hmp->locked_dirty_space +
133f5a07a7aSMatthew Dillon 		    trans->hmp->io_running_space > hammer_limit_dirtybufspace) {
134dd94f1b1SMatthew Dillon 			hammer_flusher_async(trans->hmp);
135dd94f1b1SMatthew Dillon 			tsleep(trans, 0, "hmrslo", hz / 10);
136dd94f1b1SMatthew Dillon 		}
137dd94f1b1SMatthew Dillon 
138dd94f1b1SMatthew Dillon 		/*
139c82af904SMatthew Dillon 		 * The core code exports the data to userland.
140dd94f1b1SMatthew Dillon 		 */
141c82af904SMatthew Dillon 		data_len = (elm->data_offset) ? elm->data_len : 0;
142c82af904SMatthew Dillon 		if (data_len) {
143c82af904SMatthew Dillon 			error = hammer_btree_extract(&cursor,
144c82af904SMatthew Dillon 						     HAMMER_CURSOR_GET_DATA);
145c82af904SMatthew Dillon 			if (error)
146c82af904SMatthew Dillon 				break;
147c82af904SMatthew Dillon 		}
1485fa5c92fSMatthew Dillon 		bytes = sizeof(struct hammer_ioc_mrecord) + data_len;
149c82af904SMatthew Dillon 		bytes = (bytes + HAMMER_HEAD_ALIGN_MASK) &
150c82af904SMatthew Dillon 			~HAMMER_HEAD_ALIGN_MASK;
151c82af904SMatthew Dillon 		if (mirror->count + bytes > mirror->size)
152c82af904SMatthew Dillon 			break;
153c82af904SMatthew Dillon 
154c82af904SMatthew Dillon 		/*
155c82af904SMatthew Dillon 		 * Construct the record for userland and copyout.
156c82af904SMatthew Dillon 		 *
157c82af904SMatthew Dillon 		 * The user is asking for a snapshot, if the record was
158c82af904SMatthew Dillon 		 * deleted beyond the user-requested ending tid, the record
159c82af904SMatthew Dillon 		 * is not considered deleted from the point of view of
160c82af904SMatthew Dillon 		 * userland and delete_tid is cleared.
161c82af904SMatthew Dillon 		 */
162c82af904SMatthew Dillon 		mrec.signature = HAMMER_IOC_MIRROR_SIGNATURE;
1635fa5c92fSMatthew Dillon 		mrec.type = HAMMER_MREC_TYPE_REC;
164c82af904SMatthew Dillon 		mrec.rec_size = bytes;
165c82af904SMatthew Dillon 		mrec.leaf = *elm;
166c82af904SMatthew Dillon 		if (elm->base.delete_tid >= mirror->tid_end)
167c82af904SMatthew Dillon 			mrec.leaf.base.delete_tid = 0;
168c82af904SMatthew Dillon 		mrec.rec_crc = crc32(&mrec.rec_size, head_size - crc_start);
169c82af904SMatthew Dillon 		uptr = (char *)mirror->ubuf + mirror->count;
170c82af904SMatthew Dillon 		error = copyout(&mrec, uptr, head_size);
171c82af904SMatthew Dillon 		if (data_len && error == 0) {
172c82af904SMatthew Dillon 			error = copyout(cursor.data, uptr + head_size,
173c82af904SMatthew Dillon 					data_len);
174c82af904SMatthew Dillon 		}
175c82af904SMatthew Dillon 		if (error == 0)
176c82af904SMatthew Dillon 			mirror->count += bytes;
177c82af904SMatthew Dillon skip:
178dd94f1b1SMatthew Dillon 		if (error == 0) {
179dd94f1b1SMatthew Dillon 			cursor.flags |= HAMMER_CURSOR_ATEDISK;
180dd94f1b1SMatthew Dillon 			error = hammer_btree_iterate(&cursor);
181dd94f1b1SMatthew Dillon 		}
182dd94f1b1SMatthew Dillon 	}
183c82af904SMatthew Dillon 	if (error == ENOENT) {
184c82af904SMatthew Dillon 		mirror->key_cur = mirror->key_end;
185dd94f1b1SMatthew Dillon 		error = 0;
186c82af904SMatthew Dillon 	}
187dd94f1b1SMatthew Dillon 	hammer_done_cursor(&cursor);
188dd94f1b1SMatthew Dillon 	if (error == EDEADLK)
189dd94f1b1SMatthew Dillon 		goto retry;
190dd94f1b1SMatthew Dillon 	if (error == EINTR) {
191c82af904SMatthew Dillon 		mirror->head.flags |= HAMMER_IOC_HEAD_INTR;
192dd94f1b1SMatthew Dillon 		error = 0;
193dd94f1b1SMatthew Dillon 	}
194dd94f1b1SMatthew Dillon failed:
195dd94f1b1SMatthew Dillon 	mirror->key_cur.localization &= HAMMER_LOCALIZE_MASK;
196dd94f1b1SMatthew Dillon 	return(error);
197dd94f1b1SMatthew Dillon }
198dd94f1b1SMatthew Dillon 
199c82af904SMatthew Dillon /*
200c82af904SMatthew Dillon  * Copy records from userland to the target mirror.  Records which already
201c82af904SMatthew Dillon  * exist may only have their delete_tid updated.
202*602c6cb8SMatthew Dillon  *
203*602c6cb8SMatthew Dillon  * The passed ip is the root ip of the pseudofs
204c82af904SMatthew Dillon  */
205c82af904SMatthew Dillon int
206c82af904SMatthew Dillon hammer_ioc_mirror_write(hammer_transaction_t trans, hammer_inode_t ip,
207c82af904SMatthew Dillon 		       struct hammer_ioc_mirror_rw *mirror)
208c82af904SMatthew Dillon {
209c82af904SMatthew Dillon 	struct hammer_cursor cursor;
210c82af904SMatthew Dillon 	struct hammer_ioc_mrecord mrec;
211c82af904SMatthew Dillon 	const int head_size = HAMMER_MREC_HEADSIZE;
212c82af904SMatthew Dillon 	const int crc_start = HAMMER_MREC_CRCOFF;
213c82af904SMatthew Dillon 	u_int32_t rec_crc;
214c82af904SMatthew Dillon 	int error;
215c82af904SMatthew Dillon 	char *uptr;
216c82af904SMatthew Dillon 
217c82af904SMatthew Dillon 	if (mirror->size < 0 || mirror->size > 0x70000000)
218c82af904SMatthew Dillon 		return(EINVAL);
219c82af904SMatthew Dillon 
220c82af904SMatthew Dillon 	error = hammer_init_cursor(trans, &cursor, NULL, NULL);
221c82af904SMatthew Dillon retry:
222c82af904SMatthew Dillon 	hammer_normalize_cursor(&cursor);
223c82af904SMatthew Dillon 
224c82af904SMatthew Dillon 	while (error == 0 && mirror->count + head_size <= mirror->size) {
225c82af904SMatthew Dillon 		/*
226c82af904SMatthew Dillon 		 * Acquire and validate header
227c82af904SMatthew Dillon 		 */
228c82af904SMatthew Dillon 		uptr = (char *)mirror->ubuf + mirror->count;
229c82af904SMatthew Dillon 		error = copyin(uptr, &mrec, head_size);
230c82af904SMatthew Dillon 		if (error)
231c82af904SMatthew Dillon 			break;
232c82af904SMatthew Dillon 		rec_crc = crc32(&mrec.rec_size, head_size - crc_start);
233c82af904SMatthew Dillon 		if (mrec.signature != HAMMER_IOC_MIRROR_SIGNATURE) {
234c82af904SMatthew Dillon 			error = EINVAL;
235c82af904SMatthew Dillon 			break;
236c82af904SMatthew Dillon 		}
2375fa5c92fSMatthew Dillon 		if (mrec.type != HAMMER_MREC_TYPE_REC) {
2385fa5c92fSMatthew Dillon 			error = EINVAL;
2395fa5c92fSMatthew Dillon 			break;
2405fa5c92fSMatthew Dillon 		}
241c82af904SMatthew Dillon 		if (rec_crc != mrec.rec_crc) {
242c82af904SMatthew Dillon 			error = EINVAL;
243c82af904SMatthew Dillon 			break;
244c82af904SMatthew Dillon 		}
245c82af904SMatthew Dillon 		if (mrec.rec_size < head_size ||
246c82af904SMatthew Dillon 		    mrec.rec_size > head_size + HAMMER_XBUFSIZE + 16 ||
247c82af904SMatthew Dillon 		    mirror->count + mrec.rec_size > mirror->size) {
248c82af904SMatthew Dillon 			error = EINVAL;
249c82af904SMatthew Dillon 			break;
250c82af904SMatthew Dillon 		}
251c82af904SMatthew Dillon 		if (mrec.leaf.data_len < 0 ||
252c82af904SMatthew Dillon 		    mrec.leaf.data_len > HAMMER_XBUFSIZE ||
2535fa5c92fSMatthew Dillon 		    sizeof(struct hammer_ioc_mrecord) + mrec.leaf.data_len > mrec.rec_size) {
254c82af904SMatthew Dillon 			error = EINVAL;
255c82af904SMatthew Dillon 		}
256c82af904SMatthew Dillon 
257c82af904SMatthew Dillon 		/*
258c82af904SMatthew Dillon 		 * Re-localize for target.  relocalization of data is handled
259c82af904SMatthew Dillon 		 * by hammer_mirror_write().
260c82af904SMatthew Dillon 		 */
261c82af904SMatthew Dillon 		mrec.leaf.base.localization &= HAMMER_LOCALIZE_MASK;
262c82af904SMatthew Dillon 		mrec.leaf.base.localization += ip->obj_localization;
263c82af904SMatthew Dillon 
264c82af904SMatthew Dillon 		/*
265c82af904SMatthew Dillon 		 * Locate the record.
266c82af904SMatthew Dillon 		 *
267c82af904SMatthew Dillon 		 * If the record exists only the delete_tid may be updated.
268c82af904SMatthew Dillon 		 *
269c82af904SMatthew Dillon 		 * If the record does not exist we create it.  For now we
270c82af904SMatthew Dillon 		 * ignore records with a non-zero delete_tid.  Note that
271c82af904SMatthew Dillon 		 * mirror operations are effective an as-of operation and
272c82af904SMatthew Dillon 		 * delete_tid can be 0 for mirroring purposes even if it is
273c82af904SMatthew Dillon 		 * not actually 0 at the originator.
274c82af904SMatthew Dillon 		 */
275c82af904SMatthew Dillon 		hammer_normalize_cursor(&cursor);
276c82af904SMatthew Dillon 		cursor.key_beg = mrec.leaf.base;
277c82af904SMatthew Dillon 		cursor.flags |= HAMMER_CURSOR_BACKEND;
278c82af904SMatthew Dillon 		cursor.flags &= ~HAMMER_CURSOR_INSERT;
279c82af904SMatthew Dillon 		error = hammer_btree_lookup(&cursor);
280c82af904SMatthew Dillon 
281c82af904SMatthew Dillon 		if (error == 0 && hammer_mirror_check(&cursor, &mrec)) {
282c82af904SMatthew Dillon 			hammer_sync_lock_sh(trans);
283c82af904SMatthew Dillon 			error = hammer_mirror_update(&cursor, &mrec);
284c82af904SMatthew Dillon 			hammer_sync_unlock(trans);
285c82af904SMatthew Dillon 		} else if (error == ENOENT && mrec.leaf.base.delete_tid == 0) {
286c82af904SMatthew Dillon 			hammer_sync_lock_sh(trans);
287*602c6cb8SMatthew Dillon 			error = hammer_mirror_write(&cursor, &mrec, ip,
288c82af904SMatthew Dillon 						    uptr + head_size);
289c82af904SMatthew Dillon 			hammer_sync_unlock(trans);
290c82af904SMatthew Dillon 		}
291c82af904SMatthew Dillon 
292c82af904SMatthew Dillon 		/*
293c82af904SMatthew Dillon 		 * Setup for loop
294c82af904SMatthew Dillon 		 */
295c82af904SMatthew Dillon 		if (error == EDEADLK) {
296c82af904SMatthew Dillon 			hammer_done_cursor(&cursor);
297c82af904SMatthew Dillon 			error = hammer_init_cursor(trans, &cursor, NULL, NULL);
298c82af904SMatthew Dillon 			goto retry;
299c82af904SMatthew Dillon 		}
300c82af904SMatthew Dillon 		if (error == 0) {
301c82af904SMatthew Dillon 			mirror->count += mrec.rec_size;
302c82af904SMatthew Dillon 		}
303c82af904SMatthew Dillon 	}
304c82af904SMatthew Dillon 	hammer_done_cursor(&cursor);
305c82af904SMatthew Dillon 	return(0);
306c82af904SMatthew Dillon }
307c82af904SMatthew Dillon 
308c82af904SMatthew Dillon /*
309c82af904SMatthew Dillon  * Check whether an update is needed in the case where a match already
310c82af904SMatthew Dillon  * exists on the target.  The only type of update allowed in this case
311c82af904SMatthew Dillon  * is an update of the delete_tid.
312c82af904SMatthew Dillon  *
313c82af904SMatthew Dillon  * Return non-zero if the update should proceed.
314c82af904SMatthew Dillon  */
315c82af904SMatthew Dillon static
316c82af904SMatthew Dillon int
317c82af904SMatthew Dillon hammer_mirror_check(hammer_cursor_t cursor, struct hammer_ioc_mrecord *mrec)
318c82af904SMatthew Dillon {
319c82af904SMatthew Dillon 	hammer_btree_leaf_elm_t leaf = cursor->leaf;
320c82af904SMatthew Dillon 
321c82af904SMatthew Dillon 	if (leaf->base.delete_tid != mrec->leaf.base.delete_tid) {
322c82af904SMatthew Dillon 		if (leaf->base.delete_tid != 0)
323c82af904SMatthew Dillon 			return(1);
324c82af904SMatthew Dillon 	}
325c82af904SMatthew Dillon 	return(0);
326c82af904SMatthew Dillon }
327c82af904SMatthew Dillon 
328c82af904SMatthew Dillon /*
329c82af904SMatthew Dillon  * Update a record in-place.  Only the delete_tid can change.
330c82af904SMatthew Dillon  */
331c82af904SMatthew Dillon static
332c82af904SMatthew Dillon int
333c82af904SMatthew Dillon hammer_mirror_update(hammer_cursor_t cursor, struct hammer_ioc_mrecord *mrec)
334c82af904SMatthew Dillon {
335c82af904SMatthew Dillon 	hammer_btree_leaf_elm_t elm;
336c82af904SMatthew Dillon 
337c82af904SMatthew Dillon 	elm = cursor->leaf;
33806ad81ffSMatthew Dillon 
33906ad81ffSMatthew Dillon 	if (mrec->leaf.base.delete_tid == 0) {
34006ad81ffSMatthew Dillon 		kprintf("mirror_write: object %016llx:%016llx deleted on "
34106ad81ffSMatthew Dillon 			"target, not deleted on source\n",
34206ad81ffSMatthew Dillon 			elm->base.obj_id, elm->base.key);
34306ad81ffSMatthew Dillon 		return(0);
34406ad81ffSMatthew Dillon 	}
34506ad81ffSMatthew Dillon 
346c82af904SMatthew Dillon 	KKASSERT(elm->base.create_tid < mrec->leaf.base.delete_tid);
347c82af904SMatthew Dillon 	hammer_modify_node(cursor->trans, cursor->node, elm, sizeof(*elm));
348c82af904SMatthew Dillon 	elm->base.delete_tid = mrec->leaf.base.delete_tid;
349c82af904SMatthew Dillon 	elm->delete_ts = mrec->leaf.delete_ts;
350c82af904SMatthew Dillon 	hammer_modify_node_done(cursor->node);
351c82af904SMatthew Dillon 	return(0);
352c82af904SMatthew Dillon }
353c82af904SMatthew Dillon 
354c82af904SMatthew Dillon /*
355c82af904SMatthew Dillon  * Write out a new record.
356c82af904SMatthew Dillon  *
357c82af904SMatthew Dillon  * XXX this is messy.
358c82af904SMatthew Dillon  */
359c82af904SMatthew Dillon static
360c82af904SMatthew Dillon int
361c82af904SMatthew Dillon hammer_mirror_write(hammer_cursor_t cursor, struct hammer_ioc_mrecord *mrec,
362*602c6cb8SMatthew Dillon 		    hammer_inode_t ip, char *udata)
363c82af904SMatthew Dillon {
364c82af904SMatthew Dillon 	hammer_buffer_t data_buffer = NULL;
365c82af904SMatthew Dillon 	hammer_off_t ndata_offset;
366c82af904SMatthew Dillon 	void *ndata;
367c82af904SMatthew Dillon 	int error;
368*602c6cb8SMatthew Dillon 	int doprop;
369c82af904SMatthew Dillon 	int wanted_skip = 0;
370c82af904SMatthew Dillon 
371c82af904SMatthew Dillon 	if (mrec->leaf.data_len && mrec->leaf.data_offset) {
372c82af904SMatthew Dillon 		ndata = hammer_alloc_data(cursor->trans, mrec->leaf.data_len,
373c82af904SMatthew Dillon 					  mrec->leaf.base.rec_type,
374c82af904SMatthew Dillon 					  &ndata_offset, &data_buffer, &error);
375c82af904SMatthew Dillon 		if (ndata == NULL)
376c82af904SMatthew Dillon 			return(error);
377c82af904SMatthew Dillon 		mrec->leaf.data_offset = ndata_offset;
378c82af904SMatthew Dillon 		hammer_modify_buffer(cursor->trans, data_buffer, NULL, 0);
379c82af904SMatthew Dillon 		error = copyin(udata, ndata, mrec->leaf.data_len);
380c82af904SMatthew Dillon 		if (error == 0) {
381c82af904SMatthew Dillon 			if (hammer_crc_test_leaf(ndata, &mrec->leaf) == 0) {
382c82af904SMatthew Dillon 				kprintf("data crc mismatch on pipe\n");
383c82af904SMatthew Dillon 				error = EINVAL;
384c82af904SMatthew Dillon 			} else {
385c82af904SMatthew Dillon 				error = hammer_mirror_localize_data(
386c82af904SMatthew Dillon 							ndata, &mrec->leaf);
387c82af904SMatthew Dillon 				if (error)
388c82af904SMatthew Dillon 					wanted_skip = 1;
389c82af904SMatthew Dillon 			}
390c82af904SMatthew Dillon 		}
391c82af904SMatthew Dillon 		hammer_modify_buffer_done(data_buffer);
392c82af904SMatthew Dillon 	} else {
393c82af904SMatthew Dillon 		mrec->leaf.data_offset = 0;
394c82af904SMatthew Dillon 		error = 0;
395c82af904SMatthew Dillon 		ndata = NULL;
396c82af904SMatthew Dillon 	}
397c82af904SMatthew Dillon 	if (error)
398c82af904SMatthew Dillon 		goto failed;
399c82af904SMatthew Dillon 	cursor->flags |= HAMMER_CURSOR_INSERT;
400c82af904SMatthew Dillon 	error = hammer_btree_lookup(cursor);
401c82af904SMatthew Dillon 	if (error != ENOENT) {
402c82af904SMatthew Dillon 		if (error == 0)
403c82af904SMatthew Dillon 			error = EALREADY;
404c82af904SMatthew Dillon 		goto failed;
405c82af904SMatthew Dillon 	}
406c82af904SMatthew Dillon 	error = 0;
407c82af904SMatthew Dillon 
408c82af904SMatthew Dillon 	/*
409c82af904SMatthew Dillon 	 * Physical insertion
410c82af904SMatthew Dillon 	 */
411*602c6cb8SMatthew Dillon 	error = hammer_btree_insert(cursor, &mrec->leaf, &doprop);
412*602c6cb8SMatthew Dillon 	if (error == 0 && doprop)
413*602c6cb8SMatthew Dillon 		hammer_btree_do_propagation(cursor, ip, &mrec->leaf);
414c82af904SMatthew Dillon 
415c82af904SMatthew Dillon failed:
416c82af904SMatthew Dillon 	/*
417c82af904SMatthew Dillon 	 * Cleanup
418c82af904SMatthew Dillon 	 */
419c82af904SMatthew Dillon 	if (error && mrec->leaf.data_offset) {
420c82af904SMatthew Dillon 		hammer_blockmap_free(cursor->trans,
421c82af904SMatthew Dillon 				     mrec->leaf.data_offset,
422c82af904SMatthew Dillon 				     mrec->leaf.data_len);
423c82af904SMatthew Dillon 	}
424c82af904SMatthew Dillon 	if (data_buffer)
425c82af904SMatthew Dillon 		hammer_rel_buffer(data_buffer, 0);
426c82af904SMatthew Dillon 	if (wanted_skip)
427c82af904SMatthew Dillon 		error = 0;
428c82af904SMatthew Dillon 	return(error);
429c82af904SMatthew Dillon }
430c82af904SMatthew Dillon 
431c82af904SMatthew Dillon /*
432c82af904SMatthew Dillon  * Localize the data payload.  Directory entries may need their
433c82af904SMatthew Dillon  * localization adjusted.
434c82af904SMatthew Dillon  *
435c82af904SMatthew Dillon  * Pseudo-fs directory entries must be skipped entirely (EBADF).
436c82af904SMatthew Dillon  *
437c82af904SMatthew Dillon  * The root inode must be skipped, it will exist on the target with a
438c82af904SMatthew Dillon  * different create_tid so updating it would result in a duplicate.  This
439c82af904SMatthew Dillon  * also prevents inode updates on the root directory (aka mtime, ctime, etc)
440c82af904SMatthew Dillon  * from mirroring, which is ok.
441c82af904SMatthew Dillon  *
442c82af904SMatthew Dillon  * XXX Root directory inode updates - parent_obj_localization is broken.
443c82af904SMatthew Dillon  */
444c82af904SMatthew Dillon static
445c82af904SMatthew Dillon int
446c82af904SMatthew Dillon hammer_mirror_localize_data(hammer_data_ondisk_t data,
447c82af904SMatthew Dillon 			    hammer_btree_leaf_elm_t leaf)
448c82af904SMatthew Dillon {
449c82af904SMatthew Dillon 	int modified = 0;
450c82af904SMatthew Dillon 	int error = 0;
451c82af904SMatthew Dillon 	u_int32_t localization;
452c82af904SMatthew Dillon 
453c82af904SMatthew Dillon 	if (leaf->base.rec_type == HAMMER_RECTYPE_DIRENTRY) {
454c82af904SMatthew Dillon 		localization = leaf->base.localization &
455c82af904SMatthew Dillon 			       HAMMER_LOCALIZE_PSEUDOFS_MASK;
456c82af904SMatthew Dillon 		if (data->entry.localization != localization) {
457c82af904SMatthew Dillon 			data->entry.localization = localization;
458c82af904SMatthew Dillon 			modified = 1;
459c82af904SMatthew Dillon 		}
460c82af904SMatthew Dillon 		if (data->entry.obj_id == 1)
461c82af904SMatthew Dillon 			error = EBADF;
462c82af904SMatthew Dillon 	}
4635fa5c92fSMatthew Dillon 	if (leaf->base.obj_id == HAMMER_OBJID_ROOT) {
4645fa5c92fSMatthew Dillon 		if (leaf->base.rec_type == HAMMER_RECTYPE_INODE ||
4655fa5c92fSMatthew Dillon 		    leaf->base.rec_type == HAMMER_RECTYPE_FIX) {
466c82af904SMatthew Dillon 			error = EBADF;
467c82af904SMatthew Dillon 		}
4685fa5c92fSMatthew Dillon 	}
469c82af904SMatthew Dillon 	if (modified)
470c82af904SMatthew Dillon 		hammer_crc_set_leaf(data, leaf);
471c82af904SMatthew Dillon 	return(error);
472c82af904SMatthew Dillon }
473c82af904SMatthew Dillon 
4745fa5c92fSMatthew Dillon /*
4755fa5c92fSMatthew Dillon  * Set mirroring/pseudo-fs information
4765fa5c92fSMatthew Dillon  */
4775fa5c92fSMatthew Dillon int
4785fa5c92fSMatthew Dillon hammer_ioc_set_pseudofs(hammer_transaction_t trans, hammer_inode_t ip,
4795fa5c92fSMatthew Dillon 			struct hammer_ioc_pseudofs_rw *pfs)
4805fa5c92fSMatthew Dillon {
4815fa5c92fSMatthew Dillon 	hammer_pseudofs_inmem_t pfsm;
4825fa5c92fSMatthew Dillon 	int error;
4835fa5c92fSMatthew Dillon 
4845fa5c92fSMatthew Dillon 	pfsm = ip->pfsm;
4855fa5c92fSMatthew Dillon 	error = 0;
4865fa5c92fSMatthew Dillon 
4875fa5c92fSMatthew Dillon 	if (pfs->pseudoid != ip->obj_localization)
4885fa5c92fSMatthew Dillon 		error = EINVAL;
4895fa5c92fSMatthew Dillon 	if (pfs->bytes != sizeof(pfsm->pfsd))
4905fa5c92fSMatthew Dillon 		error = EINVAL;
4915fa5c92fSMatthew Dillon 	if (pfs->version != HAMMER_IOC_PSEUDOFS_VERSION)
4925fa5c92fSMatthew Dillon 		error = EINVAL;
4935fa5c92fSMatthew Dillon 	if (error == 0 && pfs->ondisk) {
4945fa5c92fSMatthew Dillon 		if (ip->obj_id != HAMMER_OBJID_ROOT)
4955fa5c92fSMatthew Dillon 			error = EINVAL;
4965fa5c92fSMatthew Dillon 		if (error == 0) {
4975fa5c92fSMatthew Dillon 			error = copyin(pfs->ondisk, &ip->pfsm->pfsd,
4985fa5c92fSMatthew Dillon 				       sizeof(ip->pfsm->pfsd));
4995fa5c92fSMatthew Dillon 		}
5005fa5c92fSMatthew Dillon 		if (error == 0)
5015fa5c92fSMatthew Dillon 			error = hammer_save_pseudofs(trans, ip);
5025fa5c92fSMatthew Dillon 	}
5035fa5c92fSMatthew Dillon 	return(error);
5045fa5c92fSMatthew Dillon }
5055fa5c92fSMatthew Dillon 
5065fa5c92fSMatthew Dillon /*
5075fa5c92fSMatthew Dillon  * Get mirroring/pseudo-fs information
5085fa5c92fSMatthew Dillon  */
5095fa5c92fSMatthew Dillon int
5105fa5c92fSMatthew Dillon hammer_ioc_get_pseudofs(hammer_transaction_t trans, hammer_inode_t ip,
5115fa5c92fSMatthew Dillon 			struct hammer_ioc_pseudofs_rw *pfs)
5125fa5c92fSMatthew Dillon {
5135fa5c92fSMatthew Dillon 	hammer_pseudofs_inmem_t pfsm;
5145fa5c92fSMatthew Dillon 	int error;
5155fa5c92fSMatthew Dillon 
5165fa5c92fSMatthew Dillon 	pfs->pseudoid = ip->obj_localization;
5175fa5c92fSMatthew Dillon 	pfs->bytes = sizeof(struct hammer_pseudofs_data);
5185fa5c92fSMatthew Dillon 	pfs->version = HAMMER_IOC_PSEUDOFS_VERSION;
5195fa5c92fSMatthew Dillon 
5205fa5c92fSMatthew Dillon 	/*
5215fa5c92fSMatthew Dillon 	 * Update pfsm->sync_end_tid if a master
5225fa5c92fSMatthew Dillon 	 */
5235fa5c92fSMatthew Dillon 	pfsm = ip->pfsm;
5245fa5c92fSMatthew Dillon 	if (pfsm->pfsd.master_id >= 0)
5255fa5c92fSMatthew Dillon 		pfsm->pfsd.sync_end_tid = trans->rootvol->ondisk->vol0_next_tid;
5265fa5c92fSMatthew Dillon 
5275fa5c92fSMatthew Dillon 	/*
5285fa5c92fSMatthew Dillon 	 * Return PFS information for root inodes only.
5295fa5c92fSMatthew Dillon 	 */
5305fa5c92fSMatthew Dillon 	error = 0;
5315fa5c92fSMatthew Dillon 	if (pfs->ondisk) {
5325fa5c92fSMatthew Dillon 		if (ip->obj_id != HAMMER_OBJID_ROOT)
5335fa5c92fSMatthew Dillon 			error = EINVAL;
5345fa5c92fSMatthew Dillon 		if (error == 0) {
5355fa5c92fSMatthew Dillon 			error = copyout(&ip->pfsm->pfsd, pfs->ondisk,
5365fa5c92fSMatthew Dillon 					sizeof(ip->pfsm->pfsd));
5375fa5c92fSMatthew Dillon 		}
5385fa5c92fSMatthew Dillon 	}
5395fa5c92fSMatthew Dillon 	return(error);
5405fa5c92fSMatthew Dillon }
5415fa5c92fSMatthew Dillon 
542