dmu_send.c (177698) | dmu_send.c (185029) |
---|---|
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/* | 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 2007 Sun Microsystems, Inc. All rights reserved. | 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 | 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 |
|
44struct backuparg { 45 dmu_replay_record_t *drr; 46 kthread_t *td; 47 struct file *fp; | 46struct backuparg { 47 dmu_replay_record_t *drr; 48 kthread_t *td; 49 struct file *fp; |
50 offset_t *off; |
|
48 objset_t *os; 49 zio_cksum_t zc; 50 int err; 51}; 52 53static int 54dump_bytes(struct backuparg *ba, void *buf, int len) 55{ --- 16 unchanged lines hidden (view full) --- 72#ifdef _KERNEL 73 if (ba->fp->f_type == DTYPE_VNODE) 74 bwillwrite(); 75 ba->err = fo_write(ba->fp, &auio, ba->td->td_ucred, 0, ba->td); 76#else 77 fprintf(stderr, "%s: returning EOPNOTSUPP\n", __func__); 78 ba->err = EOPNOTSUPP; 79#endif | 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; |
|
80 81 return (ba->err); 82} 83 84static int 85dump_free(struct backuparg *ba, uint64_t object, uint64_t offset, 86 uint64_t length) 87{ --- 86 unchanged lines hidden (view full) --- 174 uint64_t object = bc->bc_bookmark.zb_object; 175 int level = bc->bc_bookmark.zb_level; 176 uint64_t blkid = bc->bc_bookmark.zb_blkid; 177 blkptr_t *bp = bc->bc_blkptr.blk_birth ? &bc->bc_blkptr : NULL; 178 dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE; 179 void *data = bc->bc_data; 180 int err = 0; 181 | 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 |
182 if (SIGPENDING(curthread)) | 186 if (issig(JUSTLOOKING) && issig(FORREAL)) |
183 return (EINTR); 184 185 ASSERT(data || bp == NULL); 186 187 if (bp == NULL && object == 0) { 188 uint64_t span = BP_SPAN(bc->bc_dnode, level); 189 uint64_t dnobj = (blkid * span) >> DNODE_SHIFT; 190 err = dump_freeobjects(ba, dnobj, span >> DNODE_SHIFT); --- 19 unchanged lines hidden (view full) --- 210 uint32_t aflags = ARC_WAIT; 211 arc_buf_t *abuf; 212 zbookmark_t zb; 213 214 zb.zb_objset = ba->os->os->os_dsl_dataset->ds_object; 215 zb.zb_object = object; 216 zb.zb_level = level; 217 zb.zb_blkid = blkid; | 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; |
218 (void) arc_read(NULL, spa, bp, 219 dmu_ot[type].ot_byteswap, arc_getbuf_func, &abuf, 220 ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_MUSTSUCCEED, 221 &aflags, &zb); | 222 (void) arc_read_nolock(NULL, spa, bp, 223 arc_getbuf_func, &abuf, ZIO_PRIORITY_ASYNC_READ, 224 ZIO_FLAG_MUSTSUCCEED, &aflags, &zb); |
222 223 if (abuf) { 224 err = dump_data(ba, type, object, blkid * blksz, 225 blksz, abuf->b_data); 226 (void) arc_buf_remove_ref(abuf, &abuf); 227 } 228 } else { 229 err = dump_data(ba, type, object, blkid * blksz, 230 blksz, data); 231 } 232 } 233 234 ASSERT(err == 0 || err == EINTR); 235 return (err); 236} 237 238int | 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 |
239dmu_sendbackup(objset_t *tosnap, objset_t *fromsnap, struct file *fp) | 242dmu_sendbackup(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin, 243 struct file *fp, offset_t *off) |
240{ 241 dsl_dataset_t *ds = tosnap->os->os_dsl_dataset; 242 dsl_dataset_t *fromds = fromsnap ? fromsnap->os->os_dsl_dataset : NULL; 243 dmu_replay_record_t *drr; 244 struct backuparg ba; 245 int err; | 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; |
|
246 247 /* tosnap must be a snapshot */ 248 if (ds->ds_phys->ds_next_snap_obj == 0) 249 return (EINVAL); 250 251 /* fromsnap must be an earlier snapshot from the same fs as tosnap */ 252 if (fromds && (ds->ds_dir != fromds->ds_dir || | 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 || |
253 fromds->ds_phys->ds_creation_txg >= 254 ds->ds_phys->ds_creation_txg)) | 258 fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg)) |
255 return (EXDEV); 256 | 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 |
|
257 drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 258 drr->drr_type = DRR_BEGIN; 259 drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; | 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; |
260 drr->drr_u.drr_begin.drr_version = DMU_BACKUP_VERSION; | 283 drr->drr_u.drr_begin.drr_version = DMU_BACKUP_STREAM_VERSION; |
261 drr->drr_u.drr_begin.drr_creation_time = 262 ds->ds_phys->ds_creation_time; 263 drr->drr_u.drr_begin.drr_type = tosnap->os->os_phys->os_type; | 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; |
|
264 drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid; | 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 |
|
265 if (fromds) 266 drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid; 267 dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname); 268 | 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 |
|
269 ba.drr = drr; 270 ba.td = curthread; 271 ba.fp = fp; 272 ba.os = tosnap; | 302 ba.drr = drr; 303 ba.td = curthread; 304 ba.fp = fp; 305 ba.os = tosnap; |
306 ba.off = off; |
|
273 ZIO_SET_CHECKSUM(&ba.zc, 0, 0, 0, 0); 274 275 if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) { 276 kmem_free(drr, sizeof (dmu_replay_record_t)); 277 return (ba.err); 278 } 279 | 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 |
280 err = traverse_dsl_dataset(ds, 281 fromds ? fromds->ds_phys->ds_creation_txg : 0, | 314 err = traverse_dsl_dataset(ds, fromtxg, |
282 ADVANCE_PRE | ADVANCE_HOLES | ADVANCE_DATA | ADVANCE_NOLOCK, 283 backup_cb, &ba); 284 285 if (err) { 286 if (err == EINTR && ba.err) 287 err = ba.err; 288 kmem_free(drr, sizeof (dmu_replay_record_t)); 289 return (err); --- 8 unchanged lines hidden (view full) --- 298 return (ba.err); 299 } 300 301 kmem_free(drr, sizeof (dmu_replay_record_t)); 302 303 return (0); 304} 305 | 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 |
306struct restorearg { 307 int err; 308 int byteswap; 309 kthread_t *td; 310 struct file *fp; 311 char *buf; 312 uint64_t voff; 313 int buflen; /* number of valid bytes in buf */ 314 int bufoff; /* next offset to read */ 315 int bufsize; /* amount of memory allocated for buf */ 316 zio_cksum_t zc; | 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 */ |
317}; 318 | 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 |
|
319/* ARGSUSED */ 320static int | 374/* ARGSUSED */ 375static int |
321replay_incremental_check(void *arg1, void *arg2, dmu_tx_t *tx) | 376recv_full_check(void *arg1, void *arg2, dmu_tx_t *tx) |
322{ | 377{ |
323 dsl_dataset_t *ds = arg1; 324 struct drr_begin *drrb = arg2; 325 const char *snapname; 326 int err; | 378 dsl_dir_t *dd = arg1; 379 struct recvbeginsyncarg *rbsa = arg2; 380 objset_t *mos = dd->dd_pool->dp_meta_objset; |
327 uint64_t val; | 381 uint64_t val; |
382 int err; |
|
328 | 383 |
329 /* must already be a snapshot of this fs */ 330 if (ds->ds_phys->ds_prev_snap_obj == 0) 331 return (ENODEV); | 384 err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj, 385 strrchr(rbsa->tofs, '/') + 1, sizeof (uint64_t), 1, &val); |
332 | 386 |
333 /* most recent snapshot must match fromguid */ 334 if (ds->ds_prev->ds_phys->ds_guid != drrb->drr_fromguid) 335 return (ENODEV); 336 /* must not have any changes since most recent snapshot */ 337 if (ds->ds_phys->ds_bp.blk_birth > 338 ds->ds_prev->ds_phys->ds_creation_txg) 339 return (ETXTBSY); | 387 if (err != ENOENT) 388 return (err ? err : EEXIST); |
340 | 389 |
341 /* new snapshot name must not exist */ 342 snapname = strrchr(drrb->drr_toname, '@'); 343 if (snapname == NULL) 344 return (EEXIST); | 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 } |
345 | 399 |
346 snapname++; 347 err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 348 ds->ds_phys->ds_snapnames_zapobj, snapname, 8, 1, &val); 349 if (err == 0) 350 return (EEXIST); 351 if (err != ENOENT) | 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) |
352 return (err); 353 | 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 |
|
354 return (0); 355} 356 | 447 return (0); 448} 449 |
357/* ARGSUSED */ | |
358static void | 450static void |
359replay_incremental_sync(void *arg1, void *arg2, dmu_tx_t *tx) | 451recv_full_existing_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) |
360{ 361 dsl_dataset_t *ds = arg1; | 452{ 453 dsl_dataset_t *ds = arg1; |
362 dmu_buf_will_dirty(ds->ds_dbuf, tx); 363 ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; | 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); |
364} 365 366/* ARGSUSED */ 367static int | 470} 471 472/* ARGSUSED */ 473static int |
368replay_full_check(void *arg1, void *arg2, dmu_tx_t *tx) | 474recv_incremental_check(void *arg1, void *arg2, dmu_tx_t *tx) |
369{ | 475{ |
370 dsl_dir_t *dd = arg1; 371 struct drr_begin *drrb = arg2; 372 objset_t *mos = dd->dd_pool->dp_meta_objset; 373 char *cp; 374 uint64_t val; | 476 dsl_dataset_t *ds = arg1; 477 struct recvbeginsyncarg *rbsa = arg2; |
375 int err; | 478 int err; |
479 uint64_t val; |
|
376 | 480 |
377 cp = strchr(drrb->drr_toname, '@'); 378 *cp = '\0'; 379 err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj, 380 strrchr(drrb->drr_toname, '/') + 1, 381 sizeof (uint64_t), 1, &val); 382 *cp = '@'; | 481 /* must not have any changes since most recent snapshot */ 482 if (!rbsa->force && dsl_dataset_modified_since_lastsnap(ds)) 483 return (ETXTBSY); |
383 | 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); |
|
384 if (err != ENOENT) | 499 if (err != ENOENT) |
385 return (err ? err : EEXIST); | 500 return (err); |
386 | 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); |
|
387 return (0); 388} 389 | 509 return (0); 510} 511 |
512/* ARGSUSED */ |
|
390static void | 513static void |
391replay_full_sync(void *arg1, void *arg2, dmu_tx_t *tx) | 514recv_online_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) |
392{ | 515{ |
393 dsl_dir_t *dd = arg1; 394 struct drr_begin *drrb = arg2; 395 char *cp; 396 dsl_dataset_t *ds; | 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; |
397 uint64_t dsobj; 398 | 521 uint64_t dsobj; 522 |
399 cp = strchr(drrb->drr_toname, '@'); 400 *cp = '\0'; 401 dsobj = dsl_dataset_create_sync(dd, strrchr(drrb->drr_toname, '/') + 1, 402 NULL, tx); 403 *cp = '@'; | 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); |
404 | 529 |
405 VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, dsobj, NULL, 406 DS_MODE_EXCLUSIVE, FTAG, &ds)); | 530 /* open the temporary clone */ 531 VERIFY(0 == dsl_dataset_own_obj(dp, dsobj, 532 DS_MODE_INCONSISTENT, dmu_recv_tag, &cds)); |
407 | 533 |
408 (void) dmu_objset_create_impl(dsl_dataset_get_spa(ds), 409 ds, &ds->ds_phys->ds_bp, drrb->drr_type, tx); | 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); |
410 | 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 |
|
411 dmu_buf_will_dirty(ds->ds_dbuf, tx); 412 ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 413 | 550 dmu_buf_will_dirty(ds->ds_dbuf, tx); 551 ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 552 |
414 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); | 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); |
415} 416 | 556} 557 |
417static int 418replay_end_check(void *arg1, void *arg2, dmu_tx_t *tx) | 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) |
419{ | 565{ |
420 objset_t *os = arg1; 421 struct drr_begin *drrb = arg2; 422 char *snapname; | 566 int err = 0; 567 boolean_t byteswap; 568 struct recvbeginsyncarg rbsa; 569 uint64_t version; 570 int flags; 571 dsl_dataset_t *ds; |
423 | 572 |
424 /* XXX verify that drr_toname is in dd */ | 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); |
425 | 579 |
426 snapname = strchr(drrb->drr_toname, '@'); 427 if (snapname == NULL) | 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)) |
428 return (EINVAL); | 600 return (EINVAL); |
429 snapname++; | |
430 | 601 |
431 return (dsl_dataset_snapshot_check(os, snapname, tx)); 432} | 602 if (flags & DRR_FLAG_CI_DATA) 603 rbsa.dsflags = DS_FLAG_CI_DATASET; |
433 | 604 |
434static void 435replay_end_sync(void *arg1, void *arg2, dmu_tx_t *tx) 436{ 437 objset_t *os = arg1; 438 struct drr_begin *drrb = arg2; 439 char *snapname; 440 dsl_dataset_t *ds, *hds; | 605 bzero(drc, sizeof (dmu_recv_cookie_t)); 606 drc->drc_drrb = drrb; 607 drc->drc_tosnap = tosnap; 608 drc->drc_force = force; |
441 | 609 |
442 snapname = strchr(drrb->drr_toname, '@') + 1; | 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); |
443 | 618 |
444 dsl_dataset_snapshot_sync(os, snapname, tx); | 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 */ |
445 | 643 |
446 /* set snapshot's creation time and guid */ 447 hds = os->os->os_dsl_dataset; 448 VERIFY(0 == dsl_dataset_open_obj(hds->ds_dir->dd_pool, 449 hds->ds_phys->ds_prev_snap_obj, NULL, 450 DS_MODE_PRIMARY | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 451 FTAG, &ds)); | 644 /* tmp clone name is: tofs/%tosnap" */ 645 (void) snprintf(rbsa.clonelastname, sizeof (rbsa.clonelastname), 646 "%%%s", tosnap); |
452 | 647 |
453 dmu_buf_will_dirty(ds->ds_dbuf, tx); 454 ds->ds_phys->ds_creation_time = drrb->drr_creation_time; 455 ds->ds_phys->ds_guid = drrb->drr_toguid; 456 ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; | 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); |
457 | 652 |
458 dsl_dataset_close(ds, DS_MODE_PRIMARY, FTAG); | 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; |
459 | 667 |
460 dmu_buf_will_dirty(hds->ds_dbuf, tx); 461 hds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; | 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); |
462} 463 | 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 |
|
464static int 465restore_bytes(struct restorearg *ra, void *buf, int len, off_t off, int *resid) 466{ 467 struct uio auio; 468 struct iovec aiov; 469 int error; 470 471 aiov.iov_base = buf; --- 14 unchanged lines hidden (view full) --- 486 *resid = auio.uio_resid; 487 return (error); 488} 489 490static void * 491restore_read(struct restorearg *ra, int len) 492{ 493 void *rv; | 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; |
|
494 495 /* some things will require 8-byte alignment, so everything must */ 496 ASSERT3U(len % 8, ==, 0); 497 | 748 749 /* some things will require 8-byte alignment, so everything must */ 750 ASSERT3U(len % 8, ==, 0); 751 |
498 while (ra->buflen - ra->bufoff < len) { | 752 while (done < len) { |
499 int resid; | 753 int resid; |
500 int leftover = ra->buflen - ra->bufoff; | |
501 | 754 |
502 (void) memmove(ra->buf, ra->buf + ra->bufoff, leftover); | 755 ra->err = restore_bytes(ra, (caddr_t)ra->buf + done, 756 len - done, ra->voff, &resid); |
503 | 757 |
504 ra->err = restore_bytes(ra, (caddr_t)ra->buf + leftover, 505 ra->bufsize - leftover, ra->voff, &resid); 506 507 ra->voff += ra->bufsize - leftover - resid; 508 ra->buflen = ra->bufsize - resid; 509 ra->bufoff = 0; 510 if (resid == ra->bufsize - leftover) | 758 if (resid == len - done) |
511 ra->err = EINVAL; | 759 ra->err = EINVAL; |
760 ra->voff += len - done - resid; 761 done = len - resid; |
|
512 if (ra->err) 513 return (NULL); | 762 if (ra->err) 763 return (NULL); |
514 /* Could compute checksum here? */ | |
515 } 516 | 764 } 765 |
517 ASSERT3U(ra->bufoff % 8, ==, 0); 518 ASSERT3U(ra->buflen - ra->bufoff, >=, len); 519 rv = ra->buf + ra->bufoff; 520 ra->bufoff += len; | 766 ASSERT3U(done, ==, len); 767 rv = ra->buf; |
521 if (ra->byteswap) | 768 if (ra->byteswap) |
522 fletcher_4_incremental_byteswap(rv, len, &ra->zc); | 769 fletcher_4_incremental_byteswap(rv, len, &ra->cksum); |
523 else | 770 else |
524 fletcher_4_incremental_native(rv, len, &ra->zc); | 771 fletcher_4_incremental_native(rv, len, &ra->cksum); |
525 return (rv); 526} 527 528static void 529backup_byteswap(dmu_replay_record_t *drr) 530{ 531#define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X)) 532#define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X)) 533 drr->drr_type = BSWAP_32(drr->drr_type); | 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); |
|
534 switch (drr->drr_type) { 535 case DRR_BEGIN: 536 DO64(drr_begin.drr_magic); 537 DO64(drr_begin.drr_version); 538 DO64(drr_begin.drr_creation_time); 539 DO32(drr_begin.drr_type); | 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); |
|
540 DO64(drr_begin.drr_toguid); 541 DO64(drr_begin.drr_fromguid); 542 break; 543 case DRR_OBJECT: 544 DO64(drr_object.drr_object); 545 /* DO64(drr_object.drr_allocation_txg); */ 546 DO32(drr_object.drr_type); 547 DO32(drr_object.drr_bonustype); --- 90 unchanged lines hidden (view full) --- 638 dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 639 640 if (drro->drr_bonuslen) { 641 dmu_buf_t *db; 642 void *data; 643 VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db)); 644 dmu_buf_will_dirty(db, tx); 645 | 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 |
646 ASSERT3U(db->db_size, ==, drro->drr_bonuslen); 647 data = restore_read(ra, P2ROUNDUP(db->db_size, 8)); | 895 ASSERT3U(db->db_size, >=, drro->drr_bonuslen); 896 data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8)); |
648 if (data == NULL) { 649 dmu_tx_commit(tx); 650 return (ra->err); 651 } | 897 if (data == NULL) { 898 dmu_tx_commit(tx); 899 return (ra->err); 900 } |
652 bcopy(data, db->db_data, db->db_size); | 901 bcopy(data, db->db_data, drro->drr_bonuslen); |
653 if (ra->byteswap) { 654 dmu_ot[drro->drr_bonustype].ot_byteswap(db->db_data, 655 drro->drr_bonuslen); 656 } 657 dmu_buf_rele(db, FTAG); 658 } 659 dmu_tx_commit(tx); 660 return (0); --- 7 unchanged lines hidden (view full) --- 668 uint64_t obj; 669 670 if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj) 671 return (EINVAL); 672 673 for (obj = drrfo->drr_firstobj; 674 obj < drrfo->drr_firstobj + drrfo->drr_numobjs; 675 (void) dmu_object_next(os, &obj, FALSE, 0)) { | 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)) { |
676 dmu_tx_t *tx; | |
677 int err; 678 679 if (dmu_object_info(os, obj, NULL) != 0) 680 continue; 681 | 925 int err; 926 927 if (dmu_object_info(os, obj, NULL) != 0) 928 continue; 929 |
682 tx = dmu_tx_create(os); 683 dmu_tx_hold_bonus(tx, obj); 684 err = dmu_tx_assign(tx, TXG_WAIT); 685 if (err) { 686 dmu_tx_abort(tx); | 930 err = dmu_free_object(os, obj); 931 if (err) |
687 return (err); | 932 return (err); |
688 } 689 err = dmu_object_free(os, obj, tx); 690 dmu_tx_commit(tx); 691 if (err && err != ENOENT) 692 return (EINVAL); | |
693 } 694 return (0); 695} 696 697static int 698restore_write(struct restorearg *ra, objset_t *os, 699 struct drr_write *drrw) 700{ --- 29 unchanged lines hidden (view full) --- 730 return (0); 731} 732 733/* ARGSUSED */ 734static int 735restore_free(struct restorearg *ra, objset_t *os, 736 struct drr_free *drrf) 737{ | 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{ |
738 dmu_tx_t *tx; | |
739 int err; 740 741 if (drrf->drr_length != -1ULL && 742 drrf->drr_offset + drrf->drr_length < drrf->drr_offset) 743 return (EINVAL); 744 745 if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 746 return (EINVAL); 747 | 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 |
748 tx = dmu_tx_create(os); 749 750 dmu_tx_hold_free(tx, drrf->drr_object, | 987 err = dmu_free_long_range(os, drrf->drr_object, |
751 drrf->drr_offset, drrf->drr_length); | 988 drrf->drr_offset, drrf->drr_length); |
752 err = dmu_tx_assign(tx, TXG_WAIT); 753 if (err) { 754 dmu_tx_abort(tx); 755 return (err); 756 } 757 err = dmu_free_range(os, drrf->drr_object, 758 drrf->drr_offset, drrf->drr_length, tx); 759 dmu_tx_commit(tx); | |
760 return (err); 761} 762 | 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 */ |
|
763int | 1015int |
764dmu_recvbackup(char *tosnap, struct drr_begin *drrb, uint64_t *sizep, 765 boolean_t force, struct file *fp, uint64_t voffset) | 1016dmu_recv_stream(dmu_recv_cookie_t *drc, struct file *fp, offset_t *voffp) |
766{ 767 kthread_t *td = curthread; | 1017{ 1018 kthread_t *td = curthread; |
768 struct restorearg ra; | 1019 struct restorearg ra = { 0 }; |
769 dmu_replay_record_t *drr; | 1020 dmu_replay_record_t *drr; |
770 char *cp; 771 objset_t *os = NULL; 772 zio_cksum_t pzc; | 1021 objset_t *os; 1022 zio_cksum_t pcksum; |
773 | 1023 |
774 bzero(&ra, sizeof (ra)); 775 ra.td = td; 776 ra.fp = fp; 777 ra.voff = voffset; 778 ra.bufsize = 1<<20; 779 ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 780 781 if (drrb->drr_magic == DMU_BACKUP_MAGIC) { 782 ra.byteswap = FALSE; 783 } else if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { | 1024 if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) |
784 ra.byteswap = TRUE; | 1025 ra.byteswap = TRUE; |
785 } else { 786 ra.err = EINVAL; 787 goto out; 788 } | |
789 | 1026 |
790 /* 791 * NB: this assumes that struct drr_begin will be the largest in 792 * dmu_replay_record_t's drr_u, and thus we don't need to pad it 793 * with zeros to make it the same length as we wrote out. 794 */ 795 ((dmu_replay_record_t *)ra.buf)->drr_type = DRR_BEGIN; 796 ((dmu_replay_record_t *)ra.buf)->drr_pad = 0; 797 ((dmu_replay_record_t *)ra.buf)->drr_u.drr_begin = *drrb; 798 if (ra.byteswap) { 799 fletcher_4_incremental_byteswap(ra.buf, 800 sizeof (dmu_replay_record_t), &ra.zc); 801 } else { 802 fletcher_4_incremental_native(ra.buf, 803 sizeof (dmu_replay_record_t), &ra.zc); | 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)); |
804 } | 1042 } |
805 (void) strcpy(drrb->drr_toname, tosnap); /* for the sync funcs */ | |
806 807 if (ra.byteswap) { | 1043 1044 if (ra.byteswap) { |
1045 struct drr_begin *drrb = drc->drc_drrb; |
|
808 drrb->drr_magic = BSWAP_64(drrb->drr_magic); 809 drrb->drr_version = BSWAP_64(drrb->drr_version); 810 drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 811 drrb->drr_type = BSWAP_32(drrb->drr_type); 812 drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 813 drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 814 } 815 | 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 |
816 ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC); | 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); |
817 | 1059 |
818 if (drrb->drr_version != DMU_BACKUP_VERSION || 819 drrb->drr_type >= DMU_OST_NUMTYPES || 820 strchr(drrb->drr_toname, '@') == NULL) { 821 ra.err = EINVAL; 822 goto out; 823 } | 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); |
824 825 /* | 1063 1064 /* |
826 * Process the begin in syncing context. 827 */ 828 if (drrb->drr_fromguid) { 829 /* incremental backup */ 830 dsl_dataset_t *ds = NULL; 831 832 cp = strchr(tosnap, '@'); 833 *cp = '\0'; 834 ra.err = dsl_dataset_open(tosnap, DS_MODE_EXCLUSIVE, FTAG, &ds); 835 *cp = '@'; 836 if (ra.err) 837 goto out; 838 839 /* 840 * Only do the rollback if the most recent snapshot 841 * matches the incremental source 842 */ 843 if (force) { 844 if (ds->ds_prev == NULL || 845 ds->ds_prev->ds_phys->ds_guid != 846 drrb->drr_fromguid) { 847 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 848 kmem_free(ra.buf, ra.bufsize); 849 return (ENODEV); 850 } 851 (void) dsl_dataset_rollback(ds); 852 } 853 ra.err = dsl_sync_task_do(ds->ds_dir->dd_pool, 854 replay_incremental_check, replay_incremental_sync, 855 ds, drrb, 1); 856 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 857 } else { 858 /* full backup */ 859 dsl_dir_t *dd = NULL; 860 const char *tail; 861 862 /* can't restore full backup into topmost fs, for now */ 863 if (strrchr(drrb->drr_toname, '/') == NULL) { 864 ra.err = EINVAL; 865 goto out; 866 } 867 868 cp = strchr(tosnap, '@'); 869 *cp = '\0'; 870 ra.err = dsl_dir_open(tosnap, FTAG, &dd, &tail); 871 *cp = '@'; 872 if (ra.err) 873 goto out; 874 if (tail == NULL) { 875 ra.err = EEXIST; 876 goto out; 877 } 878 879 ra.err = dsl_sync_task_do(dd->dd_pool, replay_full_check, 880 replay_full_sync, dd, drrb, 5); 881 dsl_dir_close(dd, FTAG); 882 } 883 if (ra.err) 884 goto out; 885 886 /* | |
887 * Open the objset we are modifying. 888 */ | 1065 * Open the objset we are modifying. 1066 */ |
1067 VERIFY(dmu_objset_open_ds(drc->drc_real_ds, DMU_OST_ANY, &os) == 0); |
|
889 | 1068 |
890 cp = strchr(tosnap, '@'); 891 *cp = '\0'; 892 ra.err = dmu_objset_open(tosnap, DMU_OST_ANY, 893 DS_MODE_PRIMARY | DS_MODE_INCONSISTENT, &os); 894 *cp = '@'; 895 ASSERT3U(ra.err, ==, 0); | 1069 ASSERT(drc->drc_real_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT); |
896 897 /* 898 * Read records and process them. 899 */ | 1070 1071 /* 1072 * Read records and process them. 1073 */ |
900 pzc = ra.zc; | 1074 pcksum = ra.cksum; |
901 while (ra.err == 0 && 902 NULL != (drr = restore_read(&ra, sizeof (*drr)))) { | 1075 while (ra.err == 0 && 1076 NULL != (drr = restore_read(&ra, sizeof (*drr)))) { |
903 if (SIGPENDING(td)) { | 1077 if (issig(JUSTLOOKING) && issig(FORREAL)) { |
904 ra.err = EINTR; 905 goto out; 906 } 907 908 if (ra.byteswap) 909 backup_byteswap(drr); 910 911 switch (drr->drr_type) { --- 30 unchanged lines hidden (view full) --- 942 case DRR_END: 943 { 944 struct drr_end drre = drr->drr_u.drr_end; 945 /* 946 * We compare against the *previous* checksum 947 * value, because the stored checksum is of 948 * everything before the DRR_END record. 949 */ | 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 */ |
950 if (drre.drr_checksum.zc_word[0] != 0 && 951 !ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pzc)) { | 1124 if (!ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pcksum)) |
952 ra.err = ECKSUM; | 1125 ra.err = ECKSUM; |
953 goto out; 954 } 955 956 ra.err = dsl_sync_task_do(dmu_objset_ds(os)-> 957 ds_dir->dd_pool, replay_end_check, replay_end_sync, 958 os, drrb, 3); | |
959 goto out; 960 } 961 default: 962 ra.err = EINVAL; 963 goto out; 964 } | 1126 goto out; 1127 } 1128 default: 1129 ra.err = EINVAL; 1130 goto out; 1131 } |
965 pzc = ra.zc; | 1132 pcksum = ra.cksum; |
966 } | 1133 } |
1134 ASSERT(ra.err != 0); |
|
967 968out: | 1135 1136out: |
969 if (os) 970 dmu_objset_close(os); | 1137 dmu_objset_close(os); |
971 | 1138 |
972 /* 973 * Make sure we don't rollback/destroy unless we actually 974 * processed the begin properly. 'os' will only be set if this 975 * is the case. 976 */ 977 if (ra.err && os && tosnap && strchr(tosnap, '@')) { | 1139 if (ra.err != 0) { |
978 /* 979 * rollback or destroy what we created, so we don't 980 * leave it in the restoring state. 981 */ | 1140 /* 1141 * rollback or destroy what we created, so we don't 1142 * leave it in the restoring state. 1143 */ |
982 dsl_dataset_t *ds; 983 int err; 984 985 cp = strchr(tosnap, '@'); 986 *cp = '\0'; 987 err = dsl_dataset_open(tosnap, 988 DS_MODE_EXCLUSIVE | DS_MODE_INCONSISTENT, 989 FTAG, &ds); 990 if (err == 0) { 991 txg_wait_synced(ds->ds_dir->dd_pool, 0); 992 if (drrb->drr_fromguid) { 993 /* incremental: rollback to most recent snap */ 994 (void) dsl_dataset_rollback(ds); 995 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 996 } else { 997 /* full: destroy whole fs */ 998 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 999 (void) dsl_dataset_destroy(tosnap); 1000 } 1001 } 1002 *cp = '@'; | 1144 txg_wait_synced(drc->drc_real_ds->ds_dir->dd_pool, 0); 1145 dmu_recv_abort_cleanup(drc); |
1003 } 1004 1005 kmem_free(ra.buf, ra.bufsize); | 1146 } 1147 1148 kmem_free(ra.buf, ra.bufsize); |
1006 if (sizep) 1007 *sizep = ra.voff; | 1149 *voffp = ra.voff; |
1008 return (ra.err); 1009} | 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} |
|