Deleted Added
sdiff udiff text old ( 177698 ) new ( 185029 )
full compact
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE

--- 5 unchanged lines hidden (view full) ---

14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident "%Z%%M% %I% %E% SMI"
27
28#include <sys/dmu.h>
29#include <sys/dmu_impl.h>
30#include <sys/dmu_tx.h>

--- 5 unchanged lines hidden (view full) ---

36#include <sys/dsl_dataset.h>
37#include <sys/dsl_dir.h>
38#include <sys/dsl_pool.h>
39#include <sys/dsl_synctask.h>
40#include <sys/zfs_ioctl.h>
41#include <sys/zap.h>
42#include <sys/zio_checksum.h>
43
44static char *dmu_recv_tag = "dmu_recv_tag";
45
46struct backuparg {
47 dmu_replay_record_t *drr;
48 kthread_t *td;
49 struct file *fp;
50 offset_t *off;
51 objset_t *os;
52 zio_cksum_t zc;
53 int err;
54};
55
56static int
57dump_bytes(struct backuparg *ba, void *buf, int len)
58{

--- 16 unchanged lines hidden (view full) ---

75#ifdef _KERNEL
76 if (ba->fp->f_type == DTYPE_VNODE)
77 bwillwrite();
78 ba->err = fo_write(ba->fp, &auio, ba->td->td_ucred, 0, ba->td);
79#else
80 fprintf(stderr, "%s: returning EOPNOTSUPP\n", __func__);
81 ba->err = EOPNOTSUPP;
82#endif
83 *ba->off += len;
84
85 return (ba->err);
86}
87
88static int
89dump_free(struct backuparg *ba, uint64_t object, uint64_t offset,
90 uint64_t length)
91{

--- 86 unchanged lines hidden (view full) ---

178 uint64_t object = bc->bc_bookmark.zb_object;
179 int level = bc->bc_bookmark.zb_level;
180 uint64_t blkid = bc->bc_bookmark.zb_blkid;
181 blkptr_t *bp = bc->bc_blkptr.blk_birth ? &bc->bc_blkptr : NULL;
182 dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE;
183 void *data = bc->bc_data;
184 int err = 0;
185
186 if (issig(JUSTLOOKING) && issig(FORREAL))
187 return (EINTR);
188
189 ASSERT(data || bp == NULL);
190
191 if (bp == NULL && object == 0) {
192 uint64_t span = BP_SPAN(bc->bc_dnode, level);
193 uint64_t dnobj = (blkid * span) >> DNODE_SHIFT;
194 err = dump_freeobjects(ba, dnobj, span >> DNODE_SHIFT);

--- 19 unchanged lines hidden (view full) ---

214 uint32_t aflags = ARC_WAIT;
215 arc_buf_t *abuf;
216 zbookmark_t zb;
217
218 zb.zb_objset = ba->os->os->os_dsl_dataset->ds_object;
219 zb.zb_object = object;
220 zb.zb_level = level;
221 zb.zb_blkid = blkid;
222 (void) arc_read_nolock(NULL, spa, bp,
223 arc_getbuf_func, &abuf, ZIO_PRIORITY_ASYNC_READ,
224 ZIO_FLAG_MUSTSUCCEED, &aflags, &zb);
225
226 if (abuf) {
227 err = dump_data(ba, type, object, blkid * blksz,
228 blksz, abuf->b_data);
229 (void) arc_buf_remove_ref(abuf, &abuf);
230 }
231 } else {
232 err = dump_data(ba, type, object, blkid * blksz,
233 blksz, data);
234 }
235 }
236
237 ASSERT(err == 0 || err == EINTR);
238 return (err);
239}
240
241int
242dmu_sendbackup(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
243 struct file *fp, offset_t *off)
244{
245 dsl_dataset_t *ds = tosnap->os->os_dsl_dataset;
246 dsl_dataset_t *fromds = fromsnap ? fromsnap->os->os_dsl_dataset : NULL;
247 dmu_replay_record_t *drr;
248 struct backuparg ba;
249 int err;
250 uint64_t fromtxg = 0;
251
252 /* tosnap must be a snapshot */
253 if (ds->ds_phys->ds_next_snap_obj == 0)
254 return (EINVAL);
255
256 /* fromsnap must be an earlier snapshot from the same fs as tosnap */
257 if (fromds && (ds->ds_dir != fromds->ds_dir ||
258 fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg))
259 return (EXDEV);
260
261 if (fromorigin) {
262 dsl_pool_t *dp = ds->ds_dir->dd_pool;
263
264 if (fromsnap)
265 return (EINVAL);
266
267 if (dsl_dir_is_clone(ds->ds_dir)) {
268 rw_enter(&dp->dp_config_rwlock, RW_READER);
269 err = dsl_dataset_hold_obj(dp,
270 ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds);
271 rw_exit(&dp->dp_config_rwlock);
272 if (err)
273 return (err);
274 } else {
275 fromorigin = B_FALSE;
276 }
277 }
278
279
280 drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
281 drr->drr_type = DRR_BEGIN;
282 drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
283 drr->drr_u.drr_begin.drr_version = DMU_BACKUP_STREAM_VERSION;
284 drr->drr_u.drr_begin.drr_creation_time =
285 ds->ds_phys->ds_creation_time;
286 drr->drr_u.drr_begin.drr_type = tosnap->os->os_phys->os_type;
287 if (fromorigin)
288 drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE;
289 drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid;
290 if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET)
291 drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA;
292
293 if (fromds)
294 drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid;
295 dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname);
296
297 if (fromds)
298 fromtxg = fromds->ds_phys->ds_creation_txg;
299 if (fromorigin)
300 dsl_dataset_rele(fromds, FTAG);
301
302 ba.drr = drr;
303 ba.td = curthread;
304 ba.fp = fp;
305 ba.os = tosnap;
306 ba.off = off;
307 ZIO_SET_CHECKSUM(&ba.zc, 0, 0, 0, 0);
308
309 if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) {
310 kmem_free(drr, sizeof (dmu_replay_record_t));
311 return (ba.err);
312 }
313
314 err = traverse_dsl_dataset(ds, fromtxg,
315 ADVANCE_PRE | ADVANCE_HOLES | ADVANCE_DATA | ADVANCE_NOLOCK,
316 backup_cb, &ba);
317
318 if (err) {
319 if (err == EINTR && ba.err)
320 err = ba.err;
321 kmem_free(drr, sizeof (dmu_replay_record_t));
322 return (err);

--- 8 unchanged lines hidden (view full) ---

331 return (ba.err);
332 }
333
334 kmem_free(drr, sizeof (dmu_replay_record_t));
335
336 return (0);
337}
338
339struct recvbeginsyncarg {
340 const char *tofs;
341 const char *tosnap;
342 dsl_dataset_t *origin;
343 uint64_t fromguid;
344 dmu_objset_type_t type;
345 void *tag;
346 boolean_t force;
347 uint64_t dsflags;
348 char clonelastname[MAXNAMELEN];
349 dsl_dataset_t *ds; /* the ds to recv into; returned from the syncfunc */
350};
351
352static dsl_dataset_t *
353recv_full_sync_impl(dsl_pool_t *dp, uint64_t dsobj, dmu_objset_type_t type,
354 cred_t *cr, dmu_tx_t *tx)
355{
356 dsl_dataset_t *ds;
357
358 /* This should always work, since we just created it */
359 /* XXX - create should return an owned ds */
360 VERIFY(0 == dsl_dataset_own_obj(dp, dsobj,
361 DS_MODE_INCONSISTENT, dmu_recv_tag, &ds));
362
363 if (type != DMU_OST_NONE) {
364 (void) dmu_objset_create_impl(dp->dp_spa,
365 ds, &ds->ds_phys->ds_bp, type, tx);
366 }
367
368 spa_history_internal_log(LOG_DS_REPLAY_FULL_SYNC,
369 dp->dp_spa, tx, cr, "dataset = %lld", dsobj);
370
371 return (ds);
372}
373
374/* ARGSUSED */
375static int
376recv_full_check(void *arg1, void *arg2, dmu_tx_t *tx)
377{
378 dsl_dir_t *dd = arg1;
379 struct recvbeginsyncarg *rbsa = arg2;
380 objset_t *mos = dd->dd_pool->dp_meta_objset;
381 uint64_t val;
382 int err;
383
384 err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj,
385 strrchr(rbsa->tofs, '/') + 1, sizeof (uint64_t), 1, &val);
386
387 if (err != ENOENT)
388 return (err ? err : EEXIST);
389
390 if (rbsa->origin) {
391 /* make sure it's a snap in the same pool */
392 if (rbsa->origin->ds_dir->dd_pool != dd->dd_pool)
393 return (EXDEV);
394 if (rbsa->origin->ds_phys->ds_num_children == 0)
395 return (EINVAL);
396 if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid)
397 return (ENODEV);
398 }
399
400 return (0);
401}
402
403static void
404recv_full_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
405{
406 dsl_dir_t *dd = arg1;
407 struct recvbeginsyncarg *rbsa = arg2;
408 uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags;
409 uint64_t dsobj;
410
411 dsobj = dsl_dataset_create_sync(dd, strrchr(rbsa->tofs, '/') + 1,
412 rbsa->origin, flags, cr, tx);
413
414 rbsa->ds = recv_full_sync_impl(dd->dd_pool, dsobj,
415 rbsa->origin ? DMU_OST_NONE : rbsa->type, cr, tx);
416}
417
418static int
419recv_full_existing_check(void *arg1, void *arg2, dmu_tx_t *tx)
420{
421 dsl_dataset_t *ds = arg1;
422 struct recvbeginsyncarg *rbsa = arg2;
423 int err;
424
425 /* must be a head ds */
426 if (ds->ds_phys->ds_next_snap_obj != 0)
427 return (EINVAL);
428
429 /* must not be a clone ds */
430 if (dsl_dir_is_clone(ds->ds_dir))
431 return (EINVAL);
432
433 err = dsl_dataset_destroy_check(ds, rbsa->tag, tx);
434 if (err)
435 return (err);
436
437 if (rbsa->origin) {
438 /* make sure it's a snap in the same pool */
439 if (rbsa->origin->ds_dir->dd_pool != ds->ds_dir->dd_pool)
440 return (EXDEV);
441 if (rbsa->origin->ds_phys->ds_num_children == 0)
442 return (EINVAL);
443 if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid)
444 return (ENODEV);
445 }
446
447 return (0);
448}
449
450static void
451recv_full_existing_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
452{
453 dsl_dataset_t *ds = arg1;
454 struct recvbeginsyncarg *rbsa = arg2;
455 dsl_dir_t *dd = ds->ds_dir;
456 uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags;
457 uint64_t dsobj;
458
459 /*
460 * NB: caller must provide an extra hold on the dsl_dir_t, so it
461 * won't go away when dsl_dataset_destroy_sync() closes the
462 * dataset.
463 */
464 dsl_dataset_destroy_sync(ds, rbsa->tag, cr, tx);
465
466 dsobj = dsl_dataset_create_sync_dd(dd, rbsa->origin, flags, tx);
467
468 rbsa->ds = recv_full_sync_impl(dd->dd_pool, dsobj,
469 rbsa->origin ? DMU_OST_NONE : rbsa->type, cr, tx);
470}
471
472/* ARGSUSED */
473static int
474recv_incremental_check(void *arg1, void *arg2, dmu_tx_t *tx)
475{
476 dsl_dataset_t *ds = arg1;
477 struct recvbeginsyncarg *rbsa = arg2;
478 int err;
479 uint64_t val;
480
481 /* must not have any changes since most recent snapshot */
482 if (!rbsa->force && dsl_dataset_modified_since_lastsnap(ds))
483 return (ETXTBSY);
484
485 /* must already be a snapshot of this fs */
486 if (ds->ds_phys->ds_prev_snap_obj == 0)
487 return (ENODEV);
488
489 /* most recent snapshot must match fromguid */
490 if (ds->ds_prev->ds_phys->ds_guid != rbsa->fromguid)
491 return (ENODEV);
492
493 /* temporary clone name must not exist */
494 err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
495 ds->ds_dir->dd_phys->dd_child_dir_zapobj,
496 rbsa->clonelastname, 8, 1, &val);
497 if (err == 0)
498 return (EEXIST);
499 if (err != ENOENT)
500 return (err);
501
502 /* new snapshot name must not exist */
503 err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
504 ds->ds_phys->ds_snapnames_zapobj, rbsa->tosnap, 8, 1, &val);
505 if (err == 0)
506 return (EEXIST);
507 if (err != ENOENT)
508 return (err);
509 return (0);
510}
511
512/* ARGSUSED */
513static void
514recv_online_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
515{
516 dsl_dataset_t *ohds = arg1;
517 struct recvbeginsyncarg *rbsa = arg2;
518 dsl_pool_t *dp = ohds->ds_dir->dd_pool;
519 dsl_dataset_t *ods, *cds;
520 uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags;
521 uint64_t dsobj;
522
523 /* create the temporary clone */
524 VERIFY(0 == dsl_dataset_hold_obj(dp, ohds->ds_phys->ds_prev_snap_obj,
525 FTAG, &ods));
526 dsobj = dsl_dataset_create_sync(ohds->ds_dir,
527 rbsa->clonelastname, ods, flags, cr, tx);
528 dsl_dataset_rele(ods, FTAG);
529
530 /* open the temporary clone */
531 VERIFY(0 == dsl_dataset_own_obj(dp, dsobj,
532 DS_MODE_INCONSISTENT, dmu_recv_tag, &cds));
533
534 /* copy the refquota from the target fs to the clone */
535 if (ohds->ds_quota > 0)
536 dsl_dataset_set_quota_sync(cds, &ohds->ds_quota, cr, tx);
537
538 rbsa->ds = cds;
539
540 spa_history_internal_log(LOG_DS_REPLAY_INC_SYNC,
541 dp->dp_spa, tx, cr, "dataset = %lld", dsobj);
542}
543
544/* ARGSUSED */
545static void
546recv_offline_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
547{
548 dsl_dataset_t *ds = arg1;
549
550 dmu_buf_will_dirty(ds->ds_dbuf, tx);
551 ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT;
552
553 spa_history_internal_log(LOG_DS_REPLAY_INC_SYNC,
554 ds->ds_dir->dd_pool->dp_spa, tx, cr, "dataset = %lld",
555 ds->ds_object);
556}
557
558/*
559 * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin()
560 * succeeds; otherwise we will leak the holds on the datasets.
561 */
562int
563dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb,
564 boolean_t force, objset_t *origin, boolean_t online, dmu_recv_cookie_t *drc)
565{
566 int err = 0;
567 boolean_t byteswap;
568 struct recvbeginsyncarg rbsa;
569 uint64_t version;
570 int flags;
571 dsl_dataset_t *ds;
572
573 if (drrb->drr_magic == DMU_BACKUP_MAGIC)
574 byteswap = FALSE;
575 else if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC))
576 byteswap = TRUE;
577 else
578 return (EINVAL);
579
580 rbsa.tofs = tofs;
581 rbsa.tosnap = tosnap;
582 rbsa.origin = origin ? origin->os->os_dsl_dataset : NULL;
583 rbsa.fromguid = drrb->drr_fromguid;
584 rbsa.type = drrb->drr_type;
585 rbsa.tag = FTAG;
586 rbsa.dsflags = 0;
587 version = drrb->drr_version;
588 flags = drrb->drr_flags;
589
590 if (byteswap) {
591 rbsa.type = BSWAP_32(rbsa.type);
592 rbsa.fromguid = BSWAP_64(rbsa.fromguid);
593 version = BSWAP_64(version);
594 flags = BSWAP_32(flags);
595 }
596
597 if (version != DMU_BACKUP_STREAM_VERSION ||
598 rbsa.type >= DMU_OST_NUMTYPES ||
599 ((flags & DRR_FLAG_CLONE) && origin == NULL))
600 return (EINVAL);
601
602 if (flags & DRR_FLAG_CI_DATA)
603 rbsa.dsflags = DS_FLAG_CI_DATASET;
604
605 bzero(drc, sizeof (dmu_recv_cookie_t));
606 drc->drc_drrb = drrb;
607 drc->drc_tosnap = tosnap;
608 drc->drc_force = force;
609
610 /*
611 * Process the begin in syncing context.
612 */
613 if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE) && !online) {
614 /* offline incremental receive */
615 err = dsl_dataset_own(tofs, 0, dmu_recv_tag, &ds);
616 if (err)
617 return (err);
618
619 /*
620 * Only do the rollback if the most recent snapshot
621 * matches the incremental source
622 */
623 if (force) {
624 if (ds->ds_prev == NULL ||
625 ds->ds_prev->ds_phys->ds_guid !=
626 rbsa.fromguid) {
627 dsl_dataset_disown(ds, dmu_recv_tag);
628 return (ENODEV);
629 }
630 (void) dsl_dataset_rollback(ds, DMU_OST_NONE);
631 }
632 rbsa.force = B_FALSE;
633 err = dsl_sync_task_do(ds->ds_dir->dd_pool,
634 recv_incremental_check,
635 recv_offline_incremental_sync, ds, &rbsa, 1);
636 if (err) {
637 dsl_dataset_disown(ds, dmu_recv_tag);
638 return (err);
639 }
640 drc->drc_logical_ds = drc->drc_real_ds = ds;
641 } else if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE)) {
642 /* online incremental receive */
643
644 /* tmp clone name is: tofs/%tosnap" */
645 (void) snprintf(rbsa.clonelastname, sizeof (rbsa.clonelastname),
646 "%%%s", tosnap);
647
648 /* open the dataset we are logically receiving into */
649 err = dsl_dataset_hold(tofs, dmu_recv_tag, &ds);
650 if (err)
651 return (err);
652
653 rbsa.force = force;
654 err = dsl_sync_task_do(ds->ds_dir->dd_pool,
655 recv_incremental_check,
656 recv_online_incremental_sync, ds, &rbsa, 5);
657 if (err) {
658 dsl_dataset_rele(ds, dmu_recv_tag);
659 return (err);
660 }
661 drc->drc_logical_ds = ds;
662 drc->drc_real_ds = rbsa.ds;
663 } else {
664 /* create new fs -- full backup or clone */
665 dsl_dir_t *dd = NULL;
666 const char *tail;
667
668 err = dsl_dir_open(tofs, FTAG, &dd, &tail);
669 if (err)
670 return (err);
671 if (tail == NULL) {
672 if (!force) {
673 dsl_dir_close(dd, FTAG);
674 return (EEXIST);
675 }
676
677 rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER);
678 err = dsl_dataset_own_obj(dd->dd_pool,
679 dd->dd_phys->dd_head_dataset_obj,
680 DS_MODE_INCONSISTENT, FTAG, &ds);
681 rw_exit(&dd->dd_pool->dp_config_rwlock);
682 if (err) {
683 dsl_dir_close(dd, FTAG);
684 return (err);
685 }
686
687 dsl_dataset_make_exclusive(ds, FTAG);
688 err = dsl_sync_task_do(dd->dd_pool,
689 recv_full_existing_check,
690 recv_full_existing_sync, ds, &rbsa, 5);
691 dsl_dataset_disown(ds, FTAG);
692 } else {
693 err = dsl_sync_task_do(dd->dd_pool, recv_full_check,
694 recv_full_sync, dd, &rbsa, 5);
695 }
696 dsl_dir_close(dd, FTAG);
697 if (err)
698 return (err);
699 drc->drc_logical_ds = drc->drc_real_ds = rbsa.ds;
700 drc->drc_newfs = B_TRUE;
701 }
702
703 return (0);
704}
705
706struct restorearg {
707 int err;
708 int byteswap;
709 kthread_t *td;
710 struct file *fp;
711 char *buf;
712 uint64_t voff;
713 int bufsize; /* amount of memory allocated for buf */
714 zio_cksum_t cksum;
715};
716
717static int
718restore_bytes(struct restorearg *ra, void *buf, int len, off_t off, int *resid)
719{
720 struct uio auio;
721 struct iovec aiov;
722 int error;
723
724 aiov.iov_base = buf;

--- 14 unchanged lines hidden (view full) ---

739 *resid = auio.uio_resid;
740 return (error);
741}
742
743static void *
744restore_read(struct restorearg *ra, int len)
745{
746 void *rv;
747 int done = 0;
748
749 /* some things will require 8-byte alignment, so everything must */
750 ASSERT3U(len % 8, ==, 0);
751
752 while (done < len) {
753 int resid;
754
755 ra->err = restore_bytes(ra, (caddr_t)ra->buf + done,
756 len - done, ra->voff, &resid);
757
758 if (resid == len - done)
759 ra->err = EINVAL;
760 ra->voff += len - done - resid;
761 done = len - resid;
762 if (ra->err)
763 return (NULL);
764 }
765
766 ASSERT3U(done, ==, len);
767 rv = ra->buf;
768 if (ra->byteswap)
769 fletcher_4_incremental_byteswap(rv, len, &ra->cksum);
770 else
771 fletcher_4_incremental_native(rv, len, &ra->cksum);
772 return (rv);
773}
774
775static void
776backup_byteswap(dmu_replay_record_t *drr)
777{
778#define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X))
779#define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X))
780 drr->drr_type = BSWAP_32(drr->drr_type);
781 drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen);
782 switch (drr->drr_type) {
783 case DRR_BEGIN:
784 DO64(drr_begin.drr_magic);
785 DO64(drr_begin.drr_version);
786 DO64(drr_begin.drr_creation_time);
787 DO32(drr_begin.drr_type);
788 DO32(drr_begin.drr_flags);
789 DO64(drr_begin.drr_toguid);
790 DO64(drr_begin.drr_fromguid);
791 break;
792 case DRR_OBJECT:
793 DO64(drr_object.drr_object);
794 /* DO64(drr_object.drr_allocation_txg); */
795 DO32(drr_object.drr_type);
796 DO32(drr_object.drr_bonustype);

--- 90 unchanged lines hidden (view full) ---

887 dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx);
888
889 if (drro->drr_bonuslen) {
890 dmu_buf_t *db;
891 void *data;
892 VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db));
893 dmu_buf_will_dirty(db, tx);
894
895 ASSERT3U(db->db_size, >=, drro->drr_bonuslen);
896 data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8));
897 if (data == NULL) {
898 dmu_tx_commit(tx);
899 return (ra->err);
900 }
901 bcopy(data, db->db_data, drro->drr_bonuslen);
902 if (ra->byteswap) {
903 dmu_ot[drro->drr_bonustype].ot_byteswap(db->db_data,
904 drro->drr_bonuslen);
905 }
906 dmu_buf_rele(db, FTAG);
907 }
908 dmu_tx_commit(tx);
909 return (0);

--- 7 unchanged lines hidden (view full) ---

917 uint64_t obj;
918
919 if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj)
920 return (EINVAL);
921
922 for (obj = drrfo->drr_firstobj;
923 obj < drrfo->drr_firstobj + drrfo->drr_numobjs;
924 (void) dmu_object_next(os, &obj, FALSE, 0)) {
925 int err;
926
927 if (dmu_object_info(os, obj, NULL) != 0)
928 continue;
929
930 err = dmu_free_object(os, obj);
931 if (err)
932 return (err);
933 }
934 return (0);
935}
936
937static int
938restore_write(struct restorearg *ra, objset_t *os,
939 struct drr_write *drrw)
940{

--- 29 unchanged lines hidden (view full) ---

970 return (0);
971}
972
973/* ARGSUSED */
974static int
975restore_free(struct restorearg *ra, objset_t *os,
976 struct drr_free *drrf)
977{
978 int err;
979
980 if (drrf->drr_length != -1ULL &&
981 drrf->drr_offset + drrf->drr_length < drrf->drr_offset)
982 return (EINVAL);
983
984 if (dmu_object_info(os, drrf->drr_object, NULL) != 0)
985 return (EINVAL);
986
987 err = dmu_free_long_range(os, drrf->drr_object,
988 drrf->drr_offset, drrf->drr_length);
989 return (err);
990}
991
992void
993dmu_recv_abort_cleanup(dmu_recv_cookie_t *drc)
994{
995 if (drc->drc_newfs || drc->drc_real_ds != drc->drc_logical_ds) {
996 /*
997 * online incremental or new fs: destroy the fs (which
998 * may be a clone) that we created
999 */
1000 (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag);
1001 if (drc->drc_real_ds != drc->drc_logical_ds)
1002 dsl_dataset_rele(drc->drc_logical_ds, dmu_recv_tag);
1003 } else {
1004 /*
1005 * offline incremental: rollback to most recent snapshot.
1006 */
1007 (void) dsl_dataset_rollback(drc->drc_real_ds, DMU_OST_NONE);
1008 dsl_dataset_disown(drc->drc_real_ds, dmu_recv_tag);
1009 }
1010}
1011
1012/*
1013 * NB: callers *must* call dmu_recv_end() if this succeeds.
1014 */
1015int
1016dmu_recv_stream(dmu_recv_cookie_t *drc, struct file *fp, offset_t *voffp)
1017{
1018 kthread_t *td = curthread;
1019 struct restorearg ra = { 0 };
1020 dmu_replay_record_t *drr;
1021 objset_t *os;
1022 zio_cksum_t pcksum;
1023
1024 if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC))
1025 ra.byteswap = TRUE;
1026
1027 {
1028 /* compute checksum of drr_begin record */
1029 dmu_replay_record_t *drr;
1030 drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
1031
1032 drr->drr_type = DRR_BEGIN;
1033 drr->drr_u.drr_begin = *drc->drc_drrb;
1034 if (ra.byteswap) {
1035 fletcher_4_incremental_byteswap(drr,
1036 sizeof (dmu_replay_record_t), &ra.cksum);
1037 } else {
1038 fletcher_4_incremental_native(drr,
1039 sizeof (dmu_replay_record_t), &ra.cksum);
1040 }
1041 kmem_free(drr, sizeof (dmu_replay_record_t));
1042 }
1043
1044 if (ra.byteswap) {
1045 struct drr_begin *drrb = drc->drc_drrb;
1046 drrb->drr_magic = BSWAP_64(drrb->drr_magic);
1047 drrb->drr_version = BSWAP_64(drrb->drr_version);
1048 drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time);
1049 drrb->drr_type = BSWAP_32(drrb->drr_type);
1050 drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
1051 drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid);
1052 }
1053
1054 ra.td = td;
1055 ra.fp = fp;
1056 ra.voff = *voffp;
1057 ra.bufsize = 1<<20;
1058 ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP);
1059
1060 /* these were verified in dmu_recv_begin */
1061 ASSERT(drc->drc_drrb->drr_version == DMU_BACKUP_STREAM_VERSION);
1062 ASSERT(drc->drc_drrb->drr_type < DMU_OST_NUMTYPES);
1063
1064 /*
1065 * Open the objset we are modifying.
1066 */
1067 VERIFY(dmu_objset_open_ds(drc->drc_real_ds, DMU_OST_ANY, &os) == 0);
1068
1069 ASSERT(drc->drc_real_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT);
1070
1071 /*
1072 * Read records and process them.
1073 */
1074 pcksum = ra.cksum;
1075 while (ra.err == 0 &&
1076 NULL != (drr = restore_read(&ra, sizeof (*drr)))) {
1077 if (issig(JUSTLOOKING) && issig(FORREAL)) {
1078 ra.err = EINTR;
1079 goto out;
1080 }
1081
1082 if (ra.byteswap)
1083 backup_byteswap(drr);
1084
1085 switch (drr->drr_type) {

--- 30 unchanged lines hidden (view full) ---

1116 case DRR_END:
1117 {
1118 struct drr_end drre = drr->drr_u.drr_end;
1119 /*
1120 * We compare against the *previous* checksum
1121 * value, because the stored checksum is of
1122 * everything before the DRR_END record.
1123 */
1124 if (!ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pcksum))
1125 ra.err = ECKSUM;
1126 goto out;
1127 }
1128 default:
1129 ra.err = EINVAL;
1130 goto out;
1131 }
1132 pcksum = ra.cksum;
1133 }
1134 ASSERT(ra.err != 0);
1135
1136out:
1137 dmu_objset_close(os);
1138
1139 if (ra.err != 0) {
1140 /*
1141 * rollback or destroy what we created, so we don't
1142 * leave it in the restoring state.
1143 */
1144 txg_wait_synced(drc->drc_real_ds->ds_dir->dd_pool, 0);
1145 dmu_recv_abort_cleanup(drc);
1146 }
1147
1148 kmem_free(ra.buf, ra.bufsize);
1149 *voffp = ra.voff;
1150 return (ra.err);
1151}
1152
1153struct recvendsyncarg {
1154 char *tosnap;
1155 uint64_t creation_time;
1156 uint64_t toguid;
1157};
1158
1159static int
1160recv_end_check(void *arg1, void *arg2, dmu_tx_t *tx)
1161{
1162 dsl_dataset_t *ds = arg1;
1163 struct recvendsyncarg *resa = arg2;
1164
1165 return (dsl_dataset_snapshot_check(ds, resa->tosnap, tx));
1166}
1167
1168static void
1169recv_end_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
1170{
1171 dsl_dataset_t *ds = arg1;
1172 struct recvendsyncarg *resa = arg2;
1173
1174 dsl_dataset_snapshot_sync(ds, resa->tosnap, cr, tx);
1175
1176 /* set snapshot's creation time and guid */
1177 dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
1178 ds->ds_prev->ds_phys->ds_creation_time = resa->creation_time;
1179 ds->ds_prev->ds_phys->ds_guid = resa->toguid;
1180 ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1181
1182 dmu_buf_will_dirty(ds->ds_dbuf, tx);
1183 ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1184}
1185
1186int
1187dmu_recv_end(dmu_recv_cookie_t *drc)
1188{
1189 struct recvendsyncarg resa;
1190 dsl_dataset_t *ds = drc->drc_logical_ds;
1191 int err;
1192
1193 /*
1194 * XXX hack; seems the ds is still dirty and
1195 * dsl_pool_zil_clean() expects it to have a ds_user_ptr
1196 * (and zil), but clone_swap() can close it.
1197 */
1198 txg_wait_synced(ds->ds_dir->dd_pool, 0);
1199
1200 if (ds != drc->drc_real_ds) {
1201 /* we are doing an online recv */
1202 if (dsl_dataset_tryown(ds, FALSE, dmu_recv_tag)) {
1203 err = dsl_dataset_clone_swap(drc->drc_real_ds, ds,
1204 drc->drc_force);
1205 if (err)
1206 dsl_dataset_disown(ds, dmu_recv_tag);
1207 } else {
1208 err = EBUSY;
1209 dsl_dataset_rele(ds, dmu_recv_tag);
1210 }
1211 /* dsl_dataset_destroy() will disown the ds */
1212 (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag);
1213 if (err)
1214 return (err);
1215 }
1216
1217 resa.creation_time = drc->drc_drrb->drr_creation_time;
1218 resa.toguid = drc->drc_drrb->drr_toguid;
1219 resa.tosnap = drc->drc_tosnap;
1220
1221 err = dsl_sync_task_do(ds->ds_dir->dd_pool,
1222 recv_end_check, recv_end_sync, ds, &resa, 3);
1223 if (err) {
1224 if (drc->drc_newfs) {
1225 ASSERT(ds == drc->drc_real_ds);
1226 (void) dsl_dataset_destroy(ds, dmu_recv_tag);
1227 return (err);
1228 } else {
1229 (void) dsl_dataset_rollback(ds, DMU_OST_NONE);
1230 }
1231 }
1232
1233 /* release the hold from dmu_recv_begin */
1234 dsl_dataset_disown(ds, dmu_recv_tag);
1235 return (err);
1236}