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