- cfs_kunmap(page);
- }
-
- adler32 = cpu_to_le32(adler32);
- memcpy(buf, &adler32, sizeof(adler32));
- return 0;
-}
-
-static int do_bulk_checksum_crc32(struct ptlrpc_bulk_desc *desc, void *buf)
-{
- struct page *page;
- int off;
- char *ptr;
- __u32 crc32 = ~0;
- int len, i;
-
- for (i = 0; i < desc->bd_iov_count; i++) {
- page = desc->bd_iov[i].kiov_page;
- off = desc->bd_iov[i].kiov_offset & ~CFS_PAGE_MASK;
- ptr = cfs_kmap(page) + off;
- len = desc->bd_iov[i].kiov_len;
-
- crc32 = crc32_le(crc32, ptr, len);
-
- cfs_kunmap(page);
- }
-
- crc32 = cpu_to_le32(crc32);
- memcpy(buf, &crc32, sizeof(crc32));
- return 0;
-}
-
-static int do_bulk_checksum(struct ptlrpc_bulk_desc *desc, __u32 alg, void *buf)
-{
- struct crypto_tfm *tfm;
- struct scatterlist *sl;
- int i, rc = 0;
-
- LASSERT(alg > BULK_HASH_ALG_NULL &&
- alg < BULK_HASH_ALG_MAX);
-
- if (alg == BULK_HASH_ALG_ADLER32)
- return do_bulk_checksum_adler32(desc, buf);
- if (alg == BULK_HASH_ALG_CRC32)
- return do_bulk_checksum_crc32(desc, buf);
-
- tfm = crypto_alloc_tfm(hash_types[alg].sht_tfm_name, 0);
- if (tfm == NULL) {
- CERROR("Unable to allocate TFM %s\n", hash_types[alg].sht_name);
- return -ENOMEM;
- }
-
- OBD_ALLOC(sl, sizeof(*sl) * desc->bd_iov_count);
- if (sl == NULL) {
- rc = -ENOMEM;
- goto out_tfm;
- }
-
- for (i = 0; i < desc->bd_iov_count; i++) {
- sl[i].page = desc->bd_iov[i].kiov_page;
- sl[i].offset = desc->bd_iov[i].kiov_offset & ~CFS_PAGE_MASK;
- sl[i].length = desc->bd_iov[i].kiov_len;
- }
-
- crypto_digest_init(tfm);
- crypto_digest_update(tfm, sl, desc->bd_iov_count);
- crypto_digest_final(tfm, buf);
-
- OBD_FREE(sl, sizeof(*sl) * desc->bd_iov_count);
-
-out_tfm:
- crypto_free_tfm(tfm);
- return rc;
-}
-
-#else /* !__KERNEL__ */
-
-static int do_bulk_checksum(struct ptlrpc_bulk_desc *desc, __u32 alg, void *buf)
-{
- __u32 csum32 = ~0;
- int i;
-
- LASSERT(alg == BULK_HASH_ALG_ADLER32 || alg == BULK_HASH_ALG_CRC32);
-
- if (alg == BULK_HASH_ALG_ADLER32)
- csum32 = 1;
- else
- csum32 = ~0;
-
- for (i = 0; i < desc->bd_iov_count; i++) {
- char *ptr = desc->bd_iov[i].iov_base;
- int len = desc->bd_iov[i].iov_len;
-
- if (alg == BULK_HASH_ALG_ADLER32)
- csum32 = zlib_adler32(csum32, ptr, len);
- else
- csum32 = crc32_le(csum32, ptr, len);
- }
-
- *((__u32 *) buf) = csum32;
- return 0;
-}
-
-#endif
-
-/*
- * perform algorithm @alg checksum on @desc, store result in @buf.
- * if anything goes wrong, leave 'alg' be BULK_HASH_ALG_NULL.
- */
-static
-int generate_bulk_csum(struct ptlrpc_bulk_desc *desc, __u32 alg,
- struct ptlrpc_bulk_sec_desc *bsd, int bsdsize)
-{
- int rc;
-
- LASSERT(bsd);
- LASSERT(alg < BULK_HASH_ALG_MAX);
-
- bsd->bsd_hash_alg = BULK_HASH_ALG_NULL;
-
- if (alg == BULK_HASH_ALG_NULL)
- return 0;
-
- LASSERT(bsdsize >= sizeof(*bsd) + hash_types[alg].sht_size);
-
- rc = do_bulk_checksum(desc, alg, bsd->bsd_csum);
- if (rc == 0)
- bsd->bsd_hash_alg = alg;
-
- return rc;
-}
-
-static
-int verify_bulk_csum(struct ptlrpc_bulk_desc *desc, int read,
- struct ptlrpc_bulk_sec_desc *bsdv, int bsdvsize,
- struct ptlrpc_bulk_sec_desc *bsdr, int bsdrsize)
-{
- char *csum_p;
- char *buf = NULL;
- int csum_size, rc = 0;
-
- LASSERT(bsdv);
- LASSERT(bsdv->bsd_hash_alg < BULK_HASH_ALG_MAX);
-
- if (bsdr)
- bsdr->bsd_hash_alg = BULK_HASH_ALG_NULL;
-
- if (bsdv->bsd_hash_alg == BULK_HASH_ALG_NULL)
- return 0;
-
- /* for all supported algorithms */
- csum_size = hash_types[bsdv->bsd_hash_alg].sht_size;
-
- if (bsdvsize < sizeof(*bsdv) + csum_size) {
- CERROR("verifier size %d too small, require %d\n",
- bsdvsize, (int) sizeof(*bsdv) + csum_size);
- return -EINVAL;
- }
-
- if (bsdr) {
- LASSERT(bsdrsize >= sizeof(*bsdr) + csum_size);
- csum_p = (char *) bsdr->bsd_csum;
- } else {
- OBD_ALLOC(buf, csum_size);
- if (buf == NULL)
- return -EINVAL;
- csum_p = buf;
- }
-
- rc = do_bulk_checksum(desc, bsdv->bsd_hash_alg, csum_p);
-
- if (memcmp(bsdv->bsd_csum, csum_p, csum_size)) {
- CERROR("BAD %s CHECKSUM (%s), data mutated during "
- "transfer!\n", read ? "READ" : "WRITE",
- hash_types[bsdv->bsd_hash_alg].sht_name);
- rc = -EINVAL;
- } else {
- CDEBUG(D_SEC, "bulk %s checksum (%s) verified\n",
- read ? "read" : "write",
- hash_types[bsdv->bsd_hash_alg].sht_name);
- }
-
- if (bsdr) {
- bsdr->bsd_hash_alg = bsdv->bsd_hash_alg;
- memcpy(bsdr->bsd_csum, csum_p, csum_size);
- } else {
- LASSERT(buf);
- OBD_FREE(buf, csum_size);
- }
-
- return rc;
-}
-
-int bulk_csum_cli_request(struct ptlrpc_bulk_desc *desc, int read,
- __u32 alg, struct lustre_msg *rmsg, int roff)
-{
- struct ptlrpc_bulk_sec_desc *bsdr;
- int rsize, rc = 0;
-
- rsize = rmsg->lm_buflens[roff];
- bsdr = lustre_msg_buf(rmsg, roff, sizeof(*bsdr));
-
- LASSERT(bsdr);
- LASSERT(rsize >= sizeof(*bsdr));
- LASSERT(alg < BULK_HASH_ALG_MAX);
-
- if (read) {
- bsdr->bsd_hash_alg = alg;
- } else {
- rc = generate_bulk_csum(desc, alg, bsdr, rsize);
- if (rc)
- CERROR("bulk write: client failed to compute "
- "checksum: %d\n", rc);
-
- /* For sending we only compute the wrong checksum instead
- * of corrupting the data so it is still correct on a redo */
- if (rc == 0 && OBD_FAIL_CHECK(OBD_FAIL_OSC_CHECKSUM_SEND) &&
- bsdr->bsd_hash_alg != BULK_HASH_ALG_NULL)
- bsdr->bsd_csum[0] ^= 0x1;
- }
-
- return rc;
-}
-EXPORT_SYMBOL(bulk_csum_cli_request);
-
-int bulk_csum_cli_reply(struct ptlrpc_bulk_desc *desc, int read,
- struct lustre_msg *rmsg, int roff,
- struct lustre_msg *vmsg, int voff)
-{
- struct ptlrpc_bulk_sec_desc *bsdv, *bsdr;
- int rsize, vsize;
-
- rsize = rmsg->lm_buflens[roff];
- vsize = vmsg->lm_buflens[voff];
- bsdr = lustre_msg_buf(rmsg, roff, 0);
- bsdv = lustre_msg_buf(vmsg, voff, 0);
-
- if (bsdv == NULL || vsize < sizeof(*bsdv)) {
- CERROR("Invalid checksum verifier from server: size %d\n",
- vsize);
- return -EINVAL;
- }
-
- LASSERT(bsdr);
- LASSERT(rsize >= sizeof(*bsdr));
- LASSERT(vsize >= sizeof(*bsdv));
-
- if (bsdr->bsd_hash_alg != bsdv->bsd_hash_alg) {
- CERROR("bulk %s: checksum algorithm mismatch: client request "
- "%s but server reply with %s. try to use the new one "
- "for checksum verification\n",
- read ? "read" : "write",
- hash_types[bsdr->bsd_hash_alg].sht_name,
- hash_types[bsdv->bsd_hash_alg].sht_name);
- }
-
- if (read)
- return verify_bulk_csum(desc, 1, bsdv, vsize, NULL, 0);
- else {
- char *cli, *srv, *new = NULL;
- int csum_size = hash_types[bsdr->bsd_hash_alg].sht_size;
-
- LASSERT(bsdr->bsd_hash_alg < BULK_HASH_ALG_MAX);
- if (bsdr->bsd_hash_alg == BULK_HASH_ALG_NULL)
- return 0;
-
- if (vsize < sizeof(*bsdv) + csum_size) {
- CERROR("verifier size %d too small, require %d\n",
- vsize, (int) sizeof(*bsdv) + csum_size);
- return -EINVAL;
- }
-
- cli = (char *) (bsdr + 1);
- srv = (char *) (bsdv + 1);
-
- if (!memcmp(cli, srv, csum_size)) {
- /* checksum confirmed */
- CDEBUG(D_SEC, "bulk write checksum (%s) confirmed\n",
- hash_types[bsdr->bsd_hash_alg].sht_name);
- return 0;
- }
-
- /* checksum mismatch, re-compute a new one and compare with
- * others, give out proper warnings. */
- OBD_ALLOC(new, csum_size);
- if (new == NULL)
- return -ENOMEM;
-
- do_bulk_checksum(desc, bsdr->bsd_hash_alg, new);
-
- if (!memcmp(new, srv, csum_size)) {
- CERROR("BAD WRITE CHECKSUM (%s): pages were mutated "
- "on the client after we checksummed them\n",
- hash_types[bsdr->bsd_hash_alg].sht_name);
- } else if (!memcmp(new, cli, csum_size)) {
- CERROR("BAD WRITE CHECKSUM (%s): pages were mutated "
- "in transit\n",
- hash_types[bsdr->bsd_hash_alg].sht_name);
- } else {
- CERROR("BAD WRITE CHECKSUM (%s): pages were mutated "
- "in transit, and the current page contents "
- "don't match the originals and what the server "
- "received\n",
- hash_types[bsdr->bsd_hash_alg].sht_name);
- }
- OBD_FREE(new, csum_size);
-
- return -EINVAL;
- }
-}
-EXPORT_SYMBOL(bulk_csum_cli_reply);