1 #include <sys/zfs_events.h> 2 #include <sys/zev_checksums.h> 3 #include <sys/fs/zev.h> 4 #include <sys/zfs_znode.h> 5 #include <sys/sha1.h> 6 #include <sys/avl.h> 7 #include <sys/sysmacros.h> 8 #include <sys/fs/zev.h> 9 #include <sys/zfs_rlock.h> 10 #include <sys/list.h> 11 12 typedef struct zev_sig_cache_chksums_t { 13 /* begin of key */ 14 uint64_t offset_l1; 15 /* end of key */ 16 avl_node_t avl_node; 17 uint8_t sigs[ZEV_L1_SIZE/ZEV_L0_SIZE][SHA1_DIGEST_LENGTH]; 18 } zev_sig_cache_chksums_t; 19 20 typedef struct zev_sig_cache_file_t { 21 /* begin of key */ 22 uint64_t guid; 23 uint64_t ino; 24 uint64_t gen; 25 /* end of key */ 26 uint32_t refcnt; 27 list_node_t lru_node; 28 avl_node_t avl_node; 29 avl_tree_t chksums; 30 } zev_sig_cache_file_t; 31 32 typedef struct zev_sig_cache_t { 33 kmutex_t mutex; 34 uint64_t cache_size; 35 uint64_t max_cache_size; 36 uint64_t hits; 37 uint64_t misses; 38 list_t lru; 39 avl_tree_t files; 40 } zev_sig_cache_t; 41 42 extern offset_t zfs_read_chunk_size; /* tuneable from zfs_vnops.c */ 43 44 static uint8_t all_zero_sig[SHA1_DIGEST_LENGTH] = { 45 0x1c, 0xea, 0xf7, 0x3d, 0xf4, 0x0e, 0x53, 0x1d, 0xf3, 0xbf, 46 0xb2, 0x6b, 0x4f, 0xb7, 0xcd, 0x95, 0xfb, 0x7b, 0xff, 0x1d 47 }; 48 49 static uint8_t unknown_sig[SHA1_DIGEST_LENGTH] = { 50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 52 }; 53 54 static zev_sig_cache_t zev_sig_cache; 55 56 static int 57 zev_cache_file_cmp(const void *entry_a, const void *entry_b) 58 { 59 const zev_sig_cache_file_t *a = entry_a; 60 const zev_sig_cache_file_t *b = entry_b; 61 62 if (a->guid < b->guid) 63 return -1; 64 if (a->guid > b->guid) 65 return 1; 66 if (a->ino < b->ino) 67 return -1; 68 if (a->ino > b->ino) 69 return 1; 70 if (a->gen < b->gen) 71 return -1; 72 if (a->gen > b->gen) 73 return 1; 74 return 0; 75 } 76 77 static int 78 zev_chksum_cache_cmp(const void *entry_a, const void *entry_b) 79 { 80 const zev_sig_cache_chksums_t *a = entry_a; 81 const zev_sig_cache_chksums_t *b = entry_b; 82 83 if (a->offset_l1 < b->offset_l1) 84 return -1; 85 if (a->offset_l1 > b->offset_l1) 86 return 1; 87 return 0; 88 } 89 90 /* must be called with zev_sig_cache.mutex held */ 91 static void 92 zev_chksum_cache_file_free(zev_sig_cache_file_t *file) 93 { 94 zev_sig_cache_chksums_t *cs; 95 void *c = NULL; /* cookie */ 96 97 /* remove from lru list */ 98 list_remove(&zev_sig_cache.lru, file); 99 /* free resources */ 100 avl_remove(&zev_sig_cache.files, file); 101 while ((cs = avl_destroy_nodes(&file->chksums, &c)) != NULL) { 102 zev_sig_cache.cache_size -= sizeof(*cs); 103 zev_free(cs, sizeof(*cs)); 104 } 105 avl_destroy(&file->chksums); 106 zev_free(file, sizeof(*file)); 107 zev_sig_cache.cache_size -= sizeof(*file); 108 } 109 110 void 111 zev_chksum_init(void) 112 { 113 memset(&zev_sig_cache, 0, sizeof(zev_sig_cache)); 114 mutex_init(&zev_sig_cache.mutex, NULL, MUTEX_DRIVER, NULL); 115 avl_create(&zev_sig_cache.files, zev_cache_file_cmp, 116 sizeof(zev_sig_cache_file_t), 117 offsetof(zev_sig_cache_file_t, avl_node)); 118 list_create(&zev_sig_cache.lru, 119 sizeof(zev_sig_cache_file_t), 120 offsetof(zev_sig_cache_file_t, lru_node)); 121 zev_sig_cache.max_cache_size = ZEV_CHKSUM_DEFAULT_CACHE_SIZE; 122 } 123 124 void 125 zev_chksum_fini(void) 126 { 127 zev_sig_cache_file_t *file; 128 129 mutex_destroy(&zev_sig_cache.mutex); 130 while ((file = avl_first(&zev_sig_cache.files)) != NULL) 131 zev_chksum_cache_file_free(file); 132 list_destroy(&zev_sig_cache.lru); 133 avl_destroy(&zev_sig_cache.files); 134 } 135 136 static zev_sig_cache_file_t * 137 zev_chksum_cache_file_get_and_hold(znode_t *zp) 138 { 139 zev_sig_cache_file_t find_file; 140 zev_sig_cache_file_t *file; 141 avl_index_t where; 142 143 find_file.guid = zp->z_zfsvfs->z_os->os_dsl_dataset->ds_phys->ds_guid; 144 find_file.ino = zp->z_id; 145 find_file.gen = zp->z_gen; 146 147 mutex_enter(&zev_sig_cache.mutex); 148 file = avl_find(&zev_sig_cache.files, &find_file, &where); 149 if (!file) { 150 file = zev_alloc(sizeof(*file)); 151 file->guid = 152 zp->z_zfsvfs->z_os->os_dsl_dataset->ds_phys->ds_guid; 153 file->ino = zp->z_id; 154 file->gen = zp->z_gen; 155 file->refcnt = 0; 156 avl_create(&file->chksums, zev_chksum_cache_cmp, 157 sizeof(zev_sig_cache_chksums_t), 158 offsetof(zev_sig_cache_chksums_t, avl_node)); 159 list_insert_head(&zev_sig_cache.lru, file); 160 avl_insert(&zev_sig_cache.files, file, where); 161 zev_sig_cache.cache_size += sizeof(*file); 162 } 163 file->refcnt++; 164 mutex_exit(&zev_sig_cache.mutex); 165 return file; 166 } 167 168 static void 169 zev_chksum_cache_file_release(zev_sig_cache_file_t *file) 170 { 171 mutex_enter(&zev_sig_cache.mutex); 172 173 /* We don't invalidate/free/destroy *file. Cache expiry does that */ 174 file->refcnt--; 175 176 /* Move file to front of lru list */ 177 list_remove(&zev_sig_cache.lru, file); 178 list_insert_head(&zev_sig_cache.lru, file); 179 180 mutex_exit(&zev_sig_cache.mutex); 181 } 182 183 static zev_sig_cache_chksums_t * 184 zev_chksum_cache_get_lv1_entry(zev_sig_cache_file_t *file, uint64_t off_l1) 185 { 186 zev_sig_cache_chksums_t find_chksum; 187 zev_sig_cache_chksums_t *cs; 188 avl_index_t where; 189 190 mutex_enter(&zev_sig_cache.mutex); 191 192 find_chksum.offset_l1 = off_l1; 193 cs = avl_find(&file->chksums, &find_chksum, &where); 194 if (!cs) { 195 cs = zev_zalloc(sizeof(*cs)); 196 cs->offset_l1 = off_l1; 197 avl_insert(&file->chksums, cs, where); 198 zev_sig_cache.cache_size += sizeof(*cs); 199 } 200 201 mutex_exit(&zev_sig_cache.mutex); 202 203 return cs; 204 } 205 206 void 207 zev_chksum_stats(uint64_t *c_size, uint64_t *c_hits, uint64_t *c_misses) 208 { 209 mutex_enter(&zev_sig_cache.mutex); 210 *c_size = zev_sig_cache.cache_size; 211 *c_hits = zev_sig_cache.hits; 212 *c_misses = zev_sig_cache.misses; 213 mutex_exit(&zev_sig_cache.mutex); 214 } 215 216 static void 217 zev_chksum_cache_invalidate(zev_sig_cache_file_t *file, 218 znode_t *zp, 219 zev_chksum_mode_t mode, 220 uint64_t off, 221 uint64_t len) 222 { 223 zev_sig_cache_chksums_t find_chksum; 224 zev_sig_cache_chksums_t *cs; 225 int idx; 226 uint64_t off_l1; 227 uint64_t len_l1; 228 uint64_t pos_l0; 229 uint64_t pos_l1; 230 231 mutex_enter(&zev_sig_cache.mutex); 232 233 /* start of this megabyte */ 234 off_l1 = P2ALIGN(off, ZEV_L1_SIZE); 235 236 if (len == 0) { 237 /* truncate() to EOF */ 238 len_l1 = ZEV_L1_SIZE; 239 } else { 240 /* full megabytes */ 241 len_l1 = len + (off - off_l1); 242 len_l1 = P2ROUNDUP(len_l1, ZEV_L1_SIZE); 243 } 244 245 for (pos_l1 = off_l1; pos_l1 < (off_l1+len_l1); pos_l1 += ZEV_L1_SIZE) { 246 247 find_chksum.offset_l1 = pos_l1; 248 cs = avl_find(&file->chksums, &find_chksum, NULL); 249 if (!cs) 250 continue; 251 252 for (pos_l0 = MAX(pos_l1, P2ALIGN(off, ZEV_L0_SIZE)); 253 pos_l0 < (pos_l1 + ZEV_L1_SIZE); 254 pos_l0 += ZEV_L0_SIZE){ 255 256 if ((len > 0) && (pos_l0 > (off + len - 1))) 257 break; 258 259 idx = (pos_l0 % ZEV_L1_SIZE) / ZEV_L0_SIZE; 260 memcpy(cs->sigs[idx], unknown_sig, SHA1_DIGEST_LENGTH); 261 } 262 } 263 264 if (len == 0) { 265 /* truncate() to EOF -> invalidate all l1 sigs beyond EOF */ 266 while ((cs = avl_last(&file->chksums)) != NULL) { 267 if (cs->offset_l1 < zp->z_size) 268 break; 269 avl_remove(&file->chksums, cs); 270 zev_sig_cache.cache_size -= sizeof(*cs); 271 zev_free(cs, sizeof(*cs)); 272 } 273 } 274 275 mutex_exit(&zev_sig_cache.mutex); 276 } 277 278 static int 279 zev_chksum_cache_get(uint8_t *dst, 280 zev_sig_cache_file_t *file, 281 zev_sig_cache_chksums_t *cs, 282 uint64_t off_l0) 283 { 284 int idx; 285 286 mutex_enter(&zev_sig_cache.mutex); 287 288 idx = (off_l0 % ZEV_L1_SIZE) / ZEV_L0_SIZE; 289 if (!memcmp(cs->sigs[idx], unknown_sig, SHA1_DIGEST_LENGTH)) { 290 zev_sig_cache.misses++; 291 mutex_exit(&zev_sig_cache.mutex); 292 return ENOENT; 293 } 294 memcpy(dst, cs->sigs[idx], SHA1_DIGEST_LENGTH); 295 zev_sig_cache.hits++; 296 297 mutex_exit(&zev_sig_cache.mutex); 298 return 0; 299 } 300 301 static void 302 zev_chksum_cache_put(uint8_t *sig, 303 zev_sig_cache_file_t *file, 304 zev_sig_cache_chksums_t *cs, 305 uint64_t off_l0) 306 { 307 zev_sig_cache_file_t *f; 308 zev_sig_cache_file_t *tmp; 309 int idx; 310 311 mutex_enter(&zev_sig_cache.mutex); 312 313 if (zev_sig_cache.max_cache_size == 0) { 314 /* cache disabled */ 315 mutex_exit(&zev_sig_cache.mutex); 316 return; 317 } 318 319 /* expire entries until there's room in the cache */ 320 f = list_tail(&zev_sig_cache.lru); 321 while (f && (zev_sig_cache.cache_size > zev_sig_cache.max_cache_size)){ 322 tmp = f; 323 f = list_prev(&zev_sig_cache.lru, f); 324 if (tmp->refcnt == 0) 325 zev_chksum_cache_file_free(tmp); 326 } 327 328 idx = (off_l0 % ZEV_L1_SIZE) / ZEV_L0_SIZE; 329 memcpy(cs->sigs[idx], sig, SHA1_DIGEST_LENGTH); 330 331 mutex_exit(&zev_sig_cache.mutex); 332 return; 333 } 334 335 /* verbatim from zfs_vnops.c (unfortunatly it's declared static, there) */ 336 static int 337 mappedread(vnode_t *vp, int nbytes, uio_t *uio) 338 { 339 znode_t *zp = VTOZ(vp); 340 objset_t *os = zp->z_zfsvfs->z_os; 341 int64_t start, off; 342 int len = nbytes; 343 int error = 0; 344 345 start = uio->uio_loffset; 346 off = start & PAGEOFFSET; 347 for (start &= PAGEMASK; len > 0; start += PAGESIZE) { 348 page_t *pp; 349 uint64_t bytes = MIN(PAGESIZE - off, len); 350 351 if (pp = page_lookup(vp, start, SE_SHARED)) { 352 caddr_t va; 353 354 va = zfs_map_page(pp, S_READ); 355 error = uiomove(va + off, bytes, UIO_READ, uio); 356 zfs_unmap_page(pp, va); 357 page_unlock(pp); 358 } else { 359 error = dmu_read_uio(os, zp->z_id, uio, bytes); 360 } 361 len -= bytes; 362 off = 0; 363 if (error) 364 break; 365 } 366 return (error); 367 } 368 369 static int 370 zev_safe_read(znode_t *zp, char *buf, uint64_t off, uint64_t len) 371 { 372 uio_t uio; 373 struct iovec iov; 374 ssize_t n; 375 ssize_t nbytes; 376 int error = 0; 377 vnode_t *vp = ZTOV(zp); 378 objset_t *os = zp->z_zfsvfs->z_os; 379 380 /* set up uio */ 381 382 iov.iov_base = buf; 383 iov.iov_len = ZEV_L0_SIZE; 384 385 uio.uio_iov = &iov; 386 uio.uio_iovcnt = 1; 387 uio.uio_segflg = (short)UIO_SYSSPACE; 388 uio.uio_llimit = RLIM64_INFINITY; 389 uio.uio_fmode = FREAD; 390 uio.uio_extflg = UIO_COPY_DEFAULT; 391 392 uio.uio_loffset = off; 393 uio.uio_resid = len; 394 395 again: 396 if (uio.uio_loffset >= zp->z_size) 397 return EINVAL; 398 399 /* don't read past EOF */ 400 n = MIN(uio.uio_resid, zp->z_size - uio.uio_loffset); 401 402 /* this block was essentially copied from zfs_read() in zfs_vnops.c */ 403 while (n > 0) { 404 nbytes = MIN(n, zfs_read_chunk_size - 405 P2PHASE(uio.uio_loffset, zfs_read_chunk_size)); 406 407 if (vn_has_cached_data(vp)) { 408 error = mappedread(vp, nbytes, &uio); 409 } else { 410 error = dmu_read_uio(os, zp->z_id, &uio, nbytes); 411 } 412 if (error) { 413 if (error = EINTR) 414 goto again; 415 /* convert checksum errors into IO errors */ 416 if (error == ECKSUM) 417 error = SET_ERROR(EIO); 418 break; 419 } 420 421 n -= nbytes; 422 } 423 424 if (error) 425 return error; 426 return len - uio.uio_resid; 427 } 428 429 static void 430 zev_l0_sig(uint8_t *sig, char *buf) 431 { 432 SHA1_CTX ctx; 433 434 SHA1Init(&ctx); 435 SHA1Update(&ctx, buf, ZEV_L0_SIZE); 436 SHA1Final(sig, &ctx); 437 return; 438 } 439 440 static void 441 zev_l0_blocksig(uint8_t *blk_sig, uint8_t *l0_sig, uint8_t block_no) 442 { 443 SHA1_CTX ctx; 444 445 SHA1Init(&ctx); 446 SHA1Update(&ctx, l0_sig, SHA1_DIGEST_LENGTH); 447 SHA1Update(&ctx, &block_no, sizeof(block_no)); 448 SHA1Final(blk_sig, &ctx); 449 return; 450 } 451 452 static void 453 zev_l1_add(uint8_t *sig_l1, uint8_t *sig_l0) 454 { 455 int i; 456 int s; 457 int carry = 0; 458 459 for (i = SHA1_DIGEST_LENGTH - 1; i >= 0; --i) { 460 s = sig_l1[i] + sig_l0[i] + carry; 461 carry = s > 255 ? 1 : 0; 462 sig_l1[i] = s & 0xff; 463 } 464 } 465 466 static int 467 zev_get_result_buffer(zev_sig_t **buffer, 468 uint64_t *buffer_len, 469 uint64_t max_buffer_len, 470 znode_t *zp, 471 uint64_t off, 472 uint64_t len, 473 zev_chksum_mode_t mode) 474 { 475 uint64_t blk_start; 476 uint64_t blk_end; 477 uint64_t l0_blocks; 478 uint64_t l1_blocks; 479 uint64_t sigs; 480 int buflen; 481 482 /* calculate result set size: how many checksums will we provide? */ 483 484 ASSERT(len > 0 || (mode == zev_truncate && len == 0)); 485 486 if (len == 0) { 487 /* truncate */ 488 l0_blocks = ((off % ZEV_L0_SIZE) == 0) ? 0 : 1; 489 l1_blocks = ((off % ZEV_L1_SIZE) == 0) ? 0 : 1; 490 } else { 491 /* how many lv1 checksums do we update? */ 492 blk_start = off / ZEV_L1_SIZE; 493 blk_end = (off + len - 1) / ZEV_L1_SIZE; 494 l1_blocks = blk_end - blk_start + 1; 495 /* how many lv0 checksums do we update? */ 496 blk_start = off / ZEV_L0_SIZE; 497 blk_end = (off + len - 1) / ZEV_L0_SIZE; 498 l0_blocks = blk_end - blk_start + 1; 499 } 500 501 sigs = l1_blocks + l0_blocks; 502 if (sigs == 0) { 503 *buffer = NULL; 504 *buffer_len = 0; 505 return 0; 506 } 507 508 buflen = sigs * sizeof(zev_sig_t); 509 if (max_buffer_len && (buflen > max_buffer_len)) { 510 *buffer = NULL; 511 *buffer_len = 0; 512 return ENOSPC; 513 } 514 *buffer_len = buflen; 515 *buffer = zev_alloc(buflen); 516 return 0; 517 } 518 519 static void 520 zev_append_sig(zev_sig_t *s, int level, uint64_t off, uint8_t *sig) 521 { 522 s->level = level; 523 s->block_offset = off; 524 memcpy(s->value, sig, SHA1_DIGEST_LENGTH); 525 } 526 527 /* 528 * Calculate all l0 and l1 checksums that are affected by the given range. 529 * 530 * This function assumes that the ranges it needs to read are already 531 * range-locked. 532 */ 533 int 534 zev_get_checksums(zev_sig_t **result, 535 uint64_t *result_buf_len, 536 uint64_t *signature_cnt, 537 uint64_t max_result_len, 538 znode_t *zp, 539 uint64_t off, 540 uint64_t len, 541 zev_chksum_mode_t mode) 542 { 543 uint64_t off_l1; 544 uint64_t len_l1; 545 uint64_t pos_l1; 546 uint64_t pos_l0; 547 char *buf; 548 int64_t ret; 549 uint8_t sig_l0[SHA1_DIGEST_LENGTH]; 550 uint8_t blk_sig_l0[SHA1_DIGEST_LENGTH]; 551 uint8_t sig_l1[SHA1_DIGEST_LENGTH]; 552 uint8_t l0_block_no; 553 zev_sig_t *sig; 554 int non_empty_l0_blocks; 555 zev_sig_cache_file_t *file; 556 zev_sig_cache_chksums_t *cs; 557 558 /* 559 * Note: for write events, the callback is called via 560 * zfs_write() -> zfs_log_write() -> zev_znode_write_cb() 561 * 562 * The transaction is not commited, yet. 563 * 564 * A write() syscall might be split into smaller chunks by zfs_write() 565 * 566 * zfs_write() has a range lock when this is called. (zfs_vnops.c:925) 567 * In zev mode, the range lock will encompass all data we need 568 * to calculate our checksums. 569 * 570 * The same is true for truncates with non-zero length. ("punch hole") 571 */ 572 573 ASSERT(len > 0 || (mode == zev_truncate && len == 0)); 574 *signature_cnt = 0; 575 576 /* 577 * Under certain circumstances we need the first l0 block's 578 * checksum, because we didn't store it in the database and 579 * can't easily get it from userspace. Not for this exact point 580 * in time, anyway. So we cheat a little. 581 */ 582 if (mode == zev_truncate && len == 0 && off == 4096) { 583 /* 584 * Normally, we'd report no checkums: 585 * - no l0 sum, because no remaining l0 block is changed 586 * - no l1 sum, because the file is now too short for l1 sums 587 * Let's pretend we changed the first l0 block, then. 588 * Luckily the entire file is range locked during truncate(). 589 */ 590 off = 0; 591 len = 4096; 592 } 593 594 /* start of this megabyte */ 595 off_l1 = P2ALIGN(off, ZEV_L1_SIZE); 596 /* full megabytes */ 597 if (len == 0) { 598 /* truncate(): we'll look at the last lv1 block, only. */ 599 len_l1 = ZEV_L1_SIZE; 600 } else { 601 len_l1 = len + (off - off_l1); 602 len_l1 = P2ROUNDUP(len_l1, ZEV_L1_SIZE); 603 } 604 605 file = zev_chksum_cache_file_get_and_hold(zp); 606 zev_chksum_cache_invalidate(file, zp, mode, off, len); 607 buf = zev_alloc(ZEV_L0_SIZE); 608 609 ret = zev_get_result_buffer(result, result_buf_len, max_result_len, 610 zp, off, len, mode); 611 if (ret) { 612 zev_free(buf, ZEV_L0_SIZE); 613 zev_chksum_cache_file_release(file); 614 return ret; 615 } 616 if (*result == NULL) { 617 /* we're done */ 618 zev_free(buf, ZEV_L0_SIZE); 619 zev_chksum_cache_file_release(file); 620 return 0; 621 } 622 sig = *result; 623 624 for (pos_l1 = off_l1; pos_l1 < (off_l1+len_l1); pos_l1 += ZEV_L1_SIZE) { 625 626 if (pos_l1 > zp->z_size) { 627 cmn_err(CE_WARN, "zev_get_checksums: off+len beyond " 628 "EOF. Unexpected behaviour; please fix!"); 629 zev_free(*result, *result_buf_len); 630 cmn_err(CE_WARN, "off=%" PRIu64 ", len=%" PRIu64 ", " 631 "dataset='%s', inode=%" PRIu64, 632 off, len, zp->z_zfsvfs->z_os-> 633 os_dsl_dataset->ds_dir->dd_myname, zp->z_id); 634 zev_free(*result, *result_buf_len); 635 *result = NULL; 636 break; 637 } 638 639 /* 640 * Since we have a reference to 'file' 'cs' can't be expired. 641 * Since our ranges are range locked, other threads woun't 642 * touch our checksum entries. (not even read them) 643 * Hence, we don't need to hold() or release() 'cs'. 644 */ 645 cs = zev_chksum_cache_get_lv1_entry(file, pos_l1); 646 647 l0_block_no = 0; 648 non_empty_l0_blocks = 0; 649 bzero(sig_l1, sizeof(sig_l1)); 650 for (pos_l0 = pos_l1; 651 pos_l0 < (pos_l1 + ZEV_L1_SIZE); 652 pos_l0 += ZEV_L0_SIZE){ 653 654 if (pos_l0 >= zp->z_size) 655 break; /* EOF */ 656 657 if (zev_chksum_cache_get(sig_l0, file,cs,pos_l0) != 0) { 658 659 /* signature is not cached, yet. */ 660 ret = zev_safe_read(zp, buf, 661 pos_l0, ZEV_L0_SIZE); 662 if (ret < 0) { 663 zev_free(*result, *result_buf_len); 664 zev_free(buf, ZEV_L0_SIZE); 665 zev_chksum_cache_file_release(file); 666 return ret; 667 } 668 /* pad buffer with zeros if necessary */ 669 if (ret < ZEV_L0_SIZE) 670 bzero(buf + ret, ZEV_L0_SIZE - ret); 671 672 /* calculate signature */ 673 zev_l0_sig(sig_l0, buf); 674 675 zev_chksum_cache_put(sig_l0, file, cs, pos_l0); 676 } 677 678 if (!memcmp(sig_l0, all_zero_sig, SHA1_DIGEST_LENGTH)) { 679 /* all-zero l0 block. omit signature. */ 680 l0_block_no++; 681 continue; 682 } 683 non_empty_l0_blocks++; 684 zev_l0_blocksig(blk_sig_l0, sig_l0, l0_block_no); 685 zev_l1_add(sig_l1, blk_sig_l0); 686 687 if (((pos_l0 + ZEV_L0_SIZE - 1) >= off) && 688 (pos_l0 <= (off + len - 1))) { 689 zev_append_sig(sig++, 0, pos_l0, sig_l0); 690 } 691 692 l0_block_no++; 693 } 694 695 if (non_empty_l0_blocks && (zp->z_size > ZEV_L0_SIZE)) 696 zev_append_sig(sig++, 1, pos_l1, sig_l1); 697 } 698 699 *signature_cnt = ((char *)sig - (char *)*result) / sizeof(zev_sig_t); 700 701 zev_free(buf, ZEV_L0_SIZE); 702 zev_chksum_cache_file_release(file); 703 return 0; 704 } 705 706 int 707 zev_ioc_get_signatures(intptr_t arg, int mode) 708 { 709 zev_ioctl_get_signatures_t gs; 710 file_t *fp; 711 int ret = 0; 712 znode_t *zp; 713 zev_sig_t *sig_buf = NULL; 714 uint64_t sig_buf_len; 715 uint64_t sig_cnt = 0; 716 uint64_t sig_len; 717 char *dst; 718 int range_locked = 0; 719 rl_t *rl; 720 ssize_t lock_off; 721 ssize_t lock_len; 722 723 if (ddi_copyin((void *)arg, &gs, sizeof(gs), mode) != 0) 724 return EFAULT; 725 fp = getf(gs.zev_fd); 726 if (fp == NULL) 727 return EBADF; 728 if (fp->f_vnode->v_vfsp->vfs_fstype != zfsfstype) { 729 ret = EINVAL; 730 goto out; 731 } 732 if (fp->f_vnode->v_type != VREG) { 733 ret = EINVAL; 734 goto out; 735 } 736 zp = VTOZ(fp->f_vnode); 737 if (gs.zev_offset >= zp->z_size) { 738 ret = EINVAL; 739 goto out; 740 } 741 742 /* range lock data */ 743 lock_off = P2ALIGN(gs.zev_offset, ZEV_L1_SIZE); 744 lock_len = gs.zev_len + (gs.zev_offset - lock_off); 745 lock_len = P2ROUNDUP(lock_len, ZEV_L1_SIZE); 746 rl = zfs_range_lock(zp, lock_off, lock_len, RL_READER); 747 range_locked = 1; 748 749 /* get checksums */ 750 ret = zev_get_checksums(&sig_buf, &sig_buf_len, &sig_cnt, 751 gs.zev_bufsize, 752 zp, gs.zev_offset, gs.zev_len, zev_write); 753 if (ret) 754 goto out; 755 756 /* copy to userland */ 757 sig_len = sig_cnt * sizeof(zev_sig_t); 758 gs.zev_signature_cnt = sig_cnt; 759 if (ddi_copyout(&gs, (void *)arg, sizeof(gs), mode) != 0) { 760 ret = EFAULT; 761 goto out; 762 } 763 if (sig_cnt && sig_buf) { 764 dst = (char *)arg + sizeof(gs); 765 if (ddi_copyout(sig_buf, (void *)dst, sig_len, mode) != 0) { 766 ret = EFAULT; 767 goto out; 768 } 769 } 770 out: 771 if (sig_buf) 772 zev_free(sig_buf, sig_buf_len); 773 if (range_locked) 774 zfs_range_unlock(rl); 775 releasef(gs.zev_fd); 776 return ret; 777 } 778 779 void 780 zev_symlink_checksum(zev_znode_symlink_t *rec, char *link) 781 { 782 char buf[ZEV_L0_SIZE]; 783 784 memset(buf, 0, sizeof(buf)); 785 strcpy(buf, link); 786 zev_l0_sig(rec->signature.value, buf); 787 rec->signature.level = 0; 788 rec->signature.block_offset = 0; 789 } 790 791 792 void 793 zev_create_checksum(zev_znode_create_t *rec, znode_t *zp) 794 { 795 char buf[ZEV_L0_SIZE]; 796 vnode_t *vp; 797 uint64_t rdev; 798 799 vp = ZTOV(zp); 800 if (vp->v_type == VBLK || vp->v_type == VCHR) { 801 sa_lookup(zp->z_sa_hdl, SA_ZPL_RDEV(zp->z_zfsvfs), 802 &rdev, sizeof(rdev)); 803 memset(buf, 0, sizeof(buf)); 804 snprintf(buf, sizeof(buf), "%c%d,%d", 805 vp->v_type == VBLK ? 'b' : 'c', 806 getmajor(rdev), 807 getminor(rdev)); 808 zev_l0_sig(rec->signature.value, buf); 809 } else { 810 memset(rec->signature.value, 0, sizeof(rec->signature.value)); 811 } 812 rec->signature.level = 0; 813 rec->signature.block_offset = 0; 814 } 815 816