+ return 0;
+}
+
+char dbgcksum_file_name[PATH_MAX];
+
+static void dump_all_bulk_pages(struct obdo *oa, int count,
+ struct niobuf_local *local_nb,
+ __u32 server_cksum, __u32 client_cksum)
+{
+ struct file *filp;
+ int rc, i;
+ unsigned int len;
+ char *buf;
+
+ /* will only keep dump of pages on first error for the same range in
+ * file/fid, not during the resends/retries. */
+ snprintf(dbgcksum_file_name, sizeof(dbgcksum_file_name),
+ "%s-checksum_dump-ost-"DFID":[%llu-%llu]-%x-%x",
+ (strncmp(libcfs_debug_file_path_arr, "NONE", 4) != 0 ?
+ libcfs_debug_file_path_arr :
+ LIBCFS_DEBUG_FILE_PATH_DEFAULT),
+ oa->o_valid & OBD_MD_FLFID ? oa->o_parent_seq : (__u64)0,
+ oa->o_valid & OBD_MD_FLFID ? oa->o_parent_oid : 0,
+ oa->o_valid & OBD_MD_FLFID ? oa->o_parent_ver : 0,
+ local_nb[0].lnb_file_offset,
+ local_nb[count-1].lnb_file_offset +
+ local_nb[count-1].lnb_len - 1, client_cksum, server_cksum);
+ filp = filp_open(dbgcksum_file_name,
+ O_CREAT | O_EXCL | O_WRONLY | O_LARGEFILE, 0600);
+ if (IS_ERR(filp)) {
+ rc = PTR_ERR(filp);
+ if (rc == -EEXIST)
+ CDEBUG(D_INFO, "%s: can't open to dump pages with "
+ "checksum error: rc = %d\n", dbgcksum_file_name,
+ rc);
+ else
+ CERROR("%s: can't open to dump pages with checksum "
+ "error: rc = %d\n", dbgcksum_file_name, rc);
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ len = local_nb[i].lnb_len;
+ buf = kmap(local_nb[i].lnb_page);
+ while (len != 0) {
+ rc = cfs_kernel_write(filp, buf, len, &filp->f_pos);
+ if (rc < 0) {
+ CERROR("%s: wanted to write %u but got %d "
+ "error\n", dbgcksum_file_name, len, rc);
+ break;
+ }
+ len -= rc;
+ buf += rc;
+ CDEBUG(D_INFO, "%s: wrote %d bytes\n",
+ dbgcksum_file_name, rc);
+ }
+ kunmap(local_nb[i].lnb_page);
+ }
+
+ rc = ll_vfs_fsync_range(filp, 0, LLONG_MAX, 1);
+ if (rc)
+ CERROR("%s: sync returns %d\n", dbgcksum_file_name, rc);
+ filp_close(filp, NULL);
+ return;
+}
+
+static int check_read_checksum(struct niobuf_local *local_nb, int npages,
+ struct obd_export *exp, struct obdo *oa,
+ const struct lnet_process_id *peer,
+ __u32 client_cksum, __u32 server_cksum,
+ enum cksum_types server_cksum_type)
+{
+ char *msg;
+ enum cksum_types cksum_type;
+ loff_t start, end;
+
+ /* unlikely to happen and only if resend does not occur due to cksum
+ * control failure on Client */
+ if (unlikely(server_cksum == client_cksum)) {
+ CDEBUG(D_PAGE, "checksum %x confirmed upon retry\n",
+ client_cksum);
+ return 0;
+ }
+
+ if (exp->exp_obd->obd_checksum_dump)
+ dump_all_bulk_pages(oa, npages, local_nb, server_cksum,
+ client_cksum);
+
+ cksum_type = cksum_type_unpack(oa->o_valid & OBD_MD_FLFLAGS ?
+ oa->o_flags : 0);
+
+ if (cksum_type != server_cksum_type)
+ msg = "the server may have not used the checksum type specified"
+ " in the original request - likely a protocol problem";
+ else
+ msg = "should have changed on the client or in transit";
+
+ start = local_nb[0].lnb_file_offset;
+ end = local_nb[npages-1].lnb_file_offset +
+ local_nb[npages-1].lnb_len - 1;
+
+ LCONSOLE_ERROR_MSG(0x132, "%s: BAD READ CHECKSUM: %s: from %s inode "
+ DFID " object "DOSTID" extent [%llu-%llu], client returned csum"
+ " %x (type %x), server csum %x (type %x)\n",
+ exp->exp_obd->obd_name,
+ msg, libcfs_nid2str(peer->nid),
+ oa->o_valid & OBD_MD_FLFID ? oa->o_parent_seq : 0ULL,
+ oa->o_valid & OBD_MD_FLFID ? oa->o_parent_oid : 0,
+ oa->o_valid & OBD_MD_FLFID ? oa->o_parent_ver : 0,
+ POSTID(&oa->o_oi),
+ start, end, client_cksum, cksum_type, server_cksum,
+ server_cksum_type);
+
+ return 1;
+}
+
+static int tgt_pages2shortio(struct niobuf_local *local, int npages,
+ unsigned char *buf, int size)
+{
+ int i, off, len, copied = size;
+ char *ptr;
+
+ for (i = 0; i < npages; i++) {
+ off = local[i].lnb_page_offset & ~PAGE_MASK;
+ len = local[i].lnb_len;
+
+ CDEBUG(D_PAGE, "index %d offset = %d len = %d left = %d\n",
+ i, off, len, size);
+ if (len > size)
+ return -EINVAL;
+
+ ptr = ll_kmap_atomic(local[i].lnb_page, KM_USER0);
+ memcpy(buf + off, ptr, len);
+ ll_kunmap_atomic(ptr, KM_USER0);
+ buf += len;
+ size -= len;
+ }
+ return copied - size;