Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

scsi: iscsi_tcp: Switch to using the crc32c library

Now that the crc32c() library function directly takes advantage of
architecture-specific optimizations, it is unnecessary to go through the
crypto API. Just use crc32c(). This is much simpler, and it improves
performance due to eliminating the crypto API overhead.

Signed-off-by: Eric Biggers <ebiggers@google.com>
Link: https://lore.kernel.org/r/20250207041724.70733-1-ebiggers@kernel.org
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Eric Biggers and committed by
Martin K. Petersen
92186c14 035b9fa0

+56 -115
+1 -1
drivers/scsi/Kconfig
··· 303 303 config ISCSI_TCP 304 304 tristate "iSCSI Initiator over TCP/IP" 305 305 depends on SCSI && INET 306 + select CRC32 306 307 select CRYPTO 307 308 select CRYPTO_MD5 308 - select CRYPTO_CRC32C 309 309 select SCSI_ISCSI_ATTRS 310 310 help 311 311 The iSCSI Driver provides a host with the ability to access storage
+8 -52
drivers/scsi/iscsi_tcp.c
··· 17 17 * Zhenyu Wang 18 18 */ 19 19 20 - #include <crypto/hash.h> 21 20 #include <linux/types.h> 22 21 #include <linux/inet.h> 23 22 #include <linux/slab.h> ··· 467 468 * sufficient room. 468 469 */ 469 470 if (conn->hdrdgst_en) { 470 - iscsi_tcp_dgst_header(tcp_sw_conn->tx_hash, hdr, hdrlen, 471 - hdr + hdrlen); 471 + iscsi_tcp_dgst_header(hdr, hdrlen, hdr + hdrlen); 472 472 hdrlen += ISCSI_DIGEST_SIZE; 473 473 } 474 474 ··· 492 494 { 493 495 struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 494 496 struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; 495 - struct ahash_request *tx_hash = NULL; 497 + u32 *tx_crcp = NULL; 496 498 unsigned int hdr_spec_len; 497 499 498 500 ISCSI_SW_TCP_DBG(conn, "offset=%d, datalen=%d %s\n", offset, len, ··· 505 507 WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len)); 506 508 507 509 if (conn->datadgst_en) 508 - tx_hash = tcp_sw_conn->tx_hash; 510 + tx_crcp = &tcp_sw_conn->tx_crc; 509 511 510 512 return iscsi_segment_seek_sg(&tcp_sw_conn->out.data_segment, 511 - sg, count, offset, len, 512 - NULL, tx_hash); 513 + sg, count, offset, len, NULL, tx_crcp); 513 514 } 514 515 515 516 static void ··· 517 520 { 518 521 struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 519 522 struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; 520 - struct ahash_request *tx_hash = NULL; 523 + u32 *tx_crcp = NULL; 521 524 unsigned int hdr_spec_len; 522 525 523 526 ISCSI_SW_TCP_DBG(conn, "datalen=%zd %s\n", len, conn->datadgst_en ? ··· 529 532 WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len)); 530 533 531 534 if (conn->datadgst_en) 532 - tx_hash = tcp_sw_conn->tx_hash; 535 + tx_crcp = &tcp_sw_conn->tx_crc; 533 536 534 537 iscsi_segment_init_linear(&tcp_sw_conn->out.data_segment, 535 - data, len, NULL, tx_hash); 538 + data, len, NULL, tx_crcp); 536 539 } 537 540 538 541 static int iscsi_sw_tcp_pdu_init(struct iscsi_task *task, ··· 580 583 struct iscsi_cls_conn *cls_conn; 581 584 struct iscsi_tcp_conn *tcp_conn; 582 585 struct iscsi_sw_tcp_conn *tcp_sw_conn; 583 - struct crypto_ahash *tfm; 584 586 585 587 cls_conn = iscsi_tcp_conn_setup(cls_session, sizeof(*tcp_sw_conn), 586 588 conn_idx); ··· 592 596 tcp_sw_conn->queue_recv = iscsi_recv_from_iscsi_q; 593 597 594 598 mutex_init(&tcp_sw_conn->sock_lock); 595 - 596 - tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC); 597 - if (IS_ERR(tfm)) 598 - goto free_conn; 599 - 600 - tcp_sw_conn->tx_hash = ahash_request_alloc(tfm, GFP_KERNEL); 601 - if (!tcp_sw_conn->tx_hash) 602 - goto free_tfm; 603 - ahash_request_set_callback(tcp_sw_conn->tx_hash, 0, NULL, NULL); 604 - 605 - tcp_sw_conn->rx_hash = ahash_request_alloc(tfm, GFP_KERNEL); 606 - if (!tcp_sw_conn->rx_hash) 607 - goto free_tx_hash; 608 - ahash_request_set_callback(tcp_sw_conn->rx_hash, 0, NULL, NULL); 609 - 610 - tcp_conn->rx_hash = tcp_sw_conn->rx_hash; 599 + tcp_conn->rx_crcp = &tcp_sw_conn->rx_crc; 611 600 612 601 return cls_conn; 613 - 614 - free_tx_hash: 615 - ahash_request_free(tcp_sw_conn->tx_hash); 616 - free_tfm: 617 - crypto_free_ahash(tfm); 618 - free_conn: 619 - iscsi_conn_printk(KERN_ERR, conn, 620 - "Could not create connection due to crc32c " 621 - "loading error. Make sure the crc32c " 622 - "module is built as a module or into the " 623 - "kernel\n"); 624 - iscsi_tcp_conn_teardown(cls_conn); 625 - return NULL; 626 602 } 627 603 628 604 static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn) ··· 632 664 static void iscsi_sw_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) 633 665 { 634 666 struct iscsi_conn *conn = cls_conn->dd_data; 635 - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 636 - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; 637 667 638 668 iscsi_sw_tcp_release_conn(conn); 639 - 640 - ahash_request_free(tcp_sw_conn->rx_hash); 641 - if (tcp_sw_conn->tx_hash) { 642 - struct crypto_ahash *tfm; 643 - 644 - tfm = crypto_ahash_reqtfm(tcp_sw_conn->tx_hash); 645 - ahash_request_free(tcp_sw_conn->tx_hash); 646 - crypto_free_ahash(tfm); 647 - } 648 - 649 669 iscsi_tcp_conn_teardown(cls_conn); 650 670 } 651 671
+2 -2
drivers/scsi/iscsi_tcp.h
··· 41 41 void (*old_write_space)(struct sock *); 42 42 43 43 /* data and header digests */ 44 - struct ahash_request *tx_hash; /* CRC32C (Tx) */ 45 - struct ahash_request *rx_hash; /* CRC32C (Rx) */ 44 + u32 tx_crc; /* CRC32C (Tx) */ 45 + u32 rx_crc; /* CRC32C (Rx) */ 46 46 47 47 /* MIB custom statistics */ 48 48 uint32_t sendpage_failures_cnt;
+39 -50
drivers/scsi/libiscsi_tcp.c
··· 15 15 * Zhenyu Wang 16 16 */ 17 17 18 - #include <crypto/hash.h> 18 + #include <linux/crc32c.h> 19 19 #include <linux/types.h> 20 20 #include <linux/list.h> 21 21 #include <linux/inet.h> ··· 168 168 segment->size = ISCSI_DIGEST_SIZE; 169 169 segment->copied = 0; 170 170 segment->sg = NULL; 171 - segment->hash = NULL; 171 + segment->crcp = NULL; 172 172 } 173 173 174 174 /** ··· 191 191 struct iscsi_segment *segment, int recv, 192 192 unsigned copied) 193 193 { 194 - struct scatterlist sg; 195 194 unsigned int pad; 196 195 197 196 ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copied %u %u size %u %s\n", 198 197 segment->copied, copied, segment->size, 199 198 recv ? "recv" : "xmit"); 200 - if (segment->hash && copied) { 201 - /* 202 - * If a segment is kmapd we must unmap it before sending 203 - * to the crypto layer since that will try to kmap it again. 204 - */ 205 - iscsi_tcp_segment_unmap(segment); 199 + if (segment->crcp && copied) { 200 + if (segment->data) { 201 + *segment->crcp = crc32c(*segment->crcp, 202 + segment->data + segment->copied, 203 + copied); 204 + } else { 205 + const void *data; 206 206 207 - if (!segment->data) { 208 - sg_init_table(&sg, 1); 209 - sg_set_page(&sg, sg_page(segment->sg), copied, 210 - segment->copied + segment->sg_offset + 211 - segment->sg->offset); 212 - } else 213 - sg_init_one(&sg, segment->data + segment->copied, 214 - copied); 215 - ahash_request_set_crypt(segment->hash, &sg, NULL, copied); 216 - crypto_ahash_update(segment->hash); 207 + data = kmap_local_page(sg_page(segment->sg)); 208 + *segment->crcp = crc32c(*segment->crcp, 209 + data + segment->copied + 210 + segment->sg_offset + 211 + segment->sg->offset, 212 + copied); 213 + kunmap_local(data); 214 + } 217 215 } 218 216 219 217 segment->copied += copied; ··· 256 258 * Set us up for transferring the data digest. hdr digest 257 259 * is completely handled in hdr done function. 258 260 */ 259 - if (segment->hash) { 260 - ahash_request_set_crypt(segment->hash, NULL, 261 - segment->digest, 0); 262 - crypto_ahash_final(segment->hash); 261 + if (segment->crcp) { 262 + put_unaligned_le32(~*segment->crcp, segment->digest); 263 263 iscsi_tcp_segment_splice_digest(segment, 264 264 recv ? segment->recv_digest : segment->digest); 265 265 return 0; ··· 278 282 * given buffer, and returns the number of bytes 279 283 * consumed, which can actually be less than @len. 280 284 * 281 - * If hash digest is enabled, the function will update the 282 - * hash while copying. 285 + * If CRC is enabled, the function will update the CRC while copying. 283 286 * Combining these two operations doesn't buy us a lot (yet), 284 287 * but in the future we could implement combined copy+crc, 285 288 * just way we do for network layer checksums. ··· 306 311 } 307 312 308 313 inline void 309 - iscsi_tcp_dgst_header(struct ahash_request *hash, const void *hdr, 310 - size_t hdrlen, unsigned char digest[ISCSI_DIGEST_SIZE]) 314 + iscsi_tcp_dgst_header(const void *hdr, size_t hdrlen, 315 + unsigned char digest[ISCSI_DIGEST_SIZE]) 311 316 { 312 - struct scatterlist sg; 313 - 314 - sg_init_one(&sg, hdr, hdrlen); 315 - ahash_request_set_crypt(hash, &sg, digest, hdrlen); 316 - crypto_ahash_digest(hash); 317 + put_unaligned_le32(~crc32c(~0, hdr, hdrlen), digest); 317 318 } 318 319 EXPORT_SYMBOL_GPL(iscsi_tcp_dgst_header); 319 320 ··· 334 343 */ 335 344 static inline void 336 345 __iscsi_segment_init(struct iscsi_segment *segment, size_t size, 337 - iscsi_segment_done_fn_t *done, struct ahash_request *hash) 346 + iscsi_segment_done_fn_t *done, u32 *crcp) 338 347 { 339 348 memset(segment, 0, sizeof(*segment)); 340 349 segment->total_size = size; 341 350 segment->done = done; 342 351 343 - if (hash) { 344 - segment->hash = hash; 345 - crypto_ahash_init(hash); 352 + if (crcp) { 353 + segment->crcp = crcp; 354 + *crcp = ~0; 346 355 } 347 356 } 348 357 349 358 inline void 350 359 iscsi_segment_init_linear(struct iscsi_segment *segment, void *data, 351 - size_t size, iscsi_segment_done_fn_t *done, 352 - struct ahash_request *hash) 360 + size_t size, iscsi_segment_done_fn_t *done, u32 *crcp) 353 361 { 354 - __iscsi_segment_init(segment, size, done, hash); 362 + __iscsi_segment_init(segment, size, done, crcp); 355 363 segment->data = data; 356 364 segment->size = size; 357 365 } ··· 360 370 iscsi_segment_seek_sg(struct iscsi_segment *segment, 361 371 struct scatterlist *sg_list, unsigned int sg_count, 362 372 unsigned int offset, size_t size, 363 - iscsi_segment_done_fn_t *done, 364 - struct ahash_request *hash) 373 + iscsi_segment_done_fn_t *done, u32 *crcp) 365 374 { 366 375 struct scatterlist *sg; 367 376 unsigned int i; 368 377 369 - __iscsi_segment_init(segment, size, done, hash); 378 + __iscsi_segment_init(segment, size, done, crcp); 370 379 for_each_sg(sg_list, sg, sg_count, i) { 371 380 if (offset < sg->length) { 372 381 iscsi_tcp_segment_init_sg(segment, sg, offset); ··· 382 393 * iscsi_tcp_hdr_recv_prep - prep segment for hdr reception 383 394 * @tcp_conn: iscsi connection to prep for 384 395 * 385 - * This function always passes NULL for the hash argument, because when this 396 + * This function always passes NULL for the crcp argument, because when this 386 397 * function is called we do not yet know the final size of the header and want 387 398 * to delay the digest processing until we know that. 388 399 */ ··· 423 434 iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn) 424 435 { 425 436 struct iscsi_conn *conn = tcp_conn->iscsi_conn; 426 - struct ahash_request *rx_hash = NULL; 437 + u32 *rx_crcp = NULL; 427 438 428 439 if (conn->datadgst_en && 429 440 !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) 430 - rx_hash = tcp_conn->rx_hash; 441 + rx_crcp = tcp_conn->rx_crcp; 431 442 432 443 iscsi_segment_init_linear(&tcp_conn->in.segment, 433 444 conn->data, tcp_conn->in.datalen, 434 - iscsi_tcp_data_recv_done, rx_hash); 445 + iscsi_tcp_data_recv_done, rx_crcp); 435 446 } 436 447 437 448 /** ··· 719 730 720 731 if (tcp_conn->in.datalen) { 721 732 struct iscsi_tcp_task *tcp_task = task->dd_data; 722 - struct ahash_request *rx_hash = NULL; 733 + u32 *rx_crcp = NULL; 723 734 struct scsi_data_buffer *sdb = &task->sc->sdb; 724 735 725 736 /* ··· 732 743 */ 733 744 if (conn->datadgst_en && 734 745 !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) 735 - rx_hash = tcp_conn->rx_hash; 746 + rx_crcp = tcp_conn->rx_crcp; 736 747 737 748 ISCSI_DBG_TCP(conn, "iscsi_tcp_begin_data_in( " 738 749 "offset=%d, datalen=%d)\n", ··· 745 756 tcp_task->data_offset, 746 757 tcp_conn->in.datalen, 747 758 iscsi_tcp_process_data_in, 748 - rx_hash); 759 + rx_crcp); 749 760 spin_unlock(&conn->session->back_lock); 750 761 return rc; 751 762 } ··· 867 878 return 0; 868 879 } 869 880 870 - iscsi_tcp_dgst_header(tcp_conn->rx_hash, hdr, 881 + iscsi_tcp_dgst_header(hdr, 871 882 segment->total_copied - ISCSI_DIGEST_SIZE, 872 883 segment->digest); 873 884
+6 -10
include/scsi/libiscsi_tcp.h
··· 15 15 struct iscsi_tcp_conn; 16 16 struct iscsi_segment; 17 17 struct sk_buff; 18 - struct ahash_request; 19 18 20 19 typedef int iscsi_segment_done_fn_t(struct iscsi_tcp_conn *, 21 20 struct iscsi_segment *); ··· 26 27 unsigned int total_size; 27 28 unsigned int total_copied; 28 29 29 - struct ahash_request *hash; 30 + u32 *crcp; 30 31 unsigned char padbuf[ISCSI_PAD_LEN]; 31 32 unsigned char recv_digest[ISCSI_DIGEST_SIZE]; 32 33 unsigned char digest[ISCSI_DIGEST_SIZE]; ··· 60 61 * stop to terminate */ 61 62 /* control data */ 62 63 struct iscsi_tcp_recv in; /* TCP receive context */ 63 - /* CRC32C (Rx) LLD should set this is they do not offload */ 64 - struct ahash_request *rx_hash; 64 + /* CRC32C (Rx) LLD should set this if they do not offload */ 65 + u32 *rx_crcp; 65 66 }; 66 67 67 68 struct iscsi_tcp_task { ··· 98 99 99 100 extern void iscsi_segment_init_linear(struct iscsi_segment *segment, 100 101 void *data, size_t size, 101 - iscsi_segment_done_fn_t *done, 102 - struct ahash_request *hash); 102 + iscsi_segment_done_fn_t *done, u32 *crcp); 103 103 extern int 104 104 iscsi_segment_seek_sg(struct iscsi_segment *segment, 105 105 struct scatterlist *sg_list, unsigned int sg_count, 106 106 unsigned int offset, size_t size, 107 - iscsi_segment_done_fn_t *done, 108 - struct ahash_request *hash); 107 + iscsi_segment_done_fn_t *done, u32 *crcp); 109 108 110 109 /* digest helpers */ 111 - extern void iscsi_tcp_dgst_header(struct ahash_request *hash, const void *hdr, 112 - size_t hdrlen, 110 + extern void iscsi_tcp_dgst_header(const void *hdr, size_t hdrlen, 113 111 unsigned char digest[ISCSI_DIGEST_SIZE]); 114 112 extern struct iscsi_cls_conn * 115 113 iscsi_tcp_conn_setup(struct iscsi_cls_session *cls_session, int dd_data_size,