/* * generic quick sort, O(N * logN); * same as qsrt in ../fs/dir.c */ void qsort(void *mm, size_t n, size_t bc, int (*cmp)(const void *, const void *)) { register char *tp, *cr, *end; /* nothing to sort */ if (n <= 1) return; /* middle is base */ memswp(mm, (char (*)[bc])mm + (n >> 1), bc); /* divide into halfs */ tp = mm, end = tp + n * bc; for (cr = tp + bc; cr < end; cr += bc) if ((*cmp)(cr, mm) < 0) memswp(cr, tp += bc, bc); /* restore base */ memswp(mm, tp, bc); /* sort halfs */ qsort(mm, (tp - (char *)mm) / bc, bc, cmp); qsort(tp + bc, (end - tp) / bc - 1, bc, cmp); }
static int divide(void *base,size_t size,fCompare cmp,int left,int right) { char *pleft = (char*)base + left * size; char *piv = (char*)base + right * size; char *i = pleft; char *j = piv - size; do { /* right until the element is > piv */ while(cmp(i,piv) <= 0 && i < piv) i += size; /* left until the element is < piv */ while(cmp(j,piv) >= 0 && j > pleft) j -= size; /* swap */ if(i < j) memswp(i,j,size); } while(i < j); /* swap piv with element i */ if(cmp(i,piv) > 0) memswp(i,piv,size); return (uint)(i - (char*)base) / size; }
void qsort( void * base, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) ) { char * i; char * j; size_t thresh = T * size; char * base_ = (char *)base; char * limit = base_ + nmemb * size; if ( ( nmemb == 0 ) || ( size == 0 ) || ( base == NULL ) ) { return; } for ( ;; ) { if ( limit - base_ > thresh ) /* QSort for more than T elements. */ { /* We work from second to last - first will be pivot element. */ i = base_ + size; j = limit - size; /* We swap first with middle element, then sort that with second and last element so that eventually first element is the median of the three - avoiding pathological pivots. */ memswp( ( ( ( (size_t)( limit - base_ ) ) / size ) / 2 ) * size + base_, base_, size ); if ( compar( i, j ) > 0 ) memswp( i, j, size ); if ( compar( base_, j ) > 0 ) memswp( base_, j, size ); if ( compar( i, base_ ) > 0 ) memswp( i, base_, size ); /* Now we have the median for pivot element, entering main Quicksort. */ for ( ;; ) { do { /* move i right until *i >= pivot */ i += size; } while ( compar( i, base_ ) < 0 ); do { /* move j left until *j <= pivot */ j -= size; } while ( compar( j, base_ ) > 0 ); if ( i > j ) { /* break loop if pointers crossed */ break; } /* else swap elements, keep scanning */ memswp( i, j, size ); } /* move pivot into correct place */ memswp( base_, j, size ); /* recurse into larger subpartition, iterate on smaller */ if ( j - base_ > limit - i ) { /* left is larger */ qsort( base, ( j - base_ ) / size, size, compar ); base_ = i; } else { /* right is larger */ qsort( i, ( limit - i ) / size, size, compar ); limit = j; } } else /* insertion sort for less than T elements */ { for ( j = base_, i = j + size; i < limit; j = i, i += size ) { for ( ; compar( j, j + size ) > 0; j -= size ) { memswp( j, j + size, size ); if ( j == base_ ) { break; } } } break; } } return; }
static void fill_sha512(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_sha512 *vh = hdr_priv(hdr); struct fio_sha512_ctx sha512_ctx = { .buf = vh->sha512, }; fio_sha512_init(&sha512_ctx); fio_sha512_update(&sha512_ctx, p, len); } static void fill_sha256(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_sha256 *vh = hdr_priv(hdr); struct fio_sha256_ctx sha256_ctx = { .buf = vh->sha256, }; fio_sha256_init(&sha256_ctx); fio_sha256_update(&sha256_ctx, p, len); fio_sha256_final(&sha256_ctx); } static void fill_sha1(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_sha1 *vh = hdr_priv(hdr); struct fio_sha1_ctx sha1_ctx = { .H = vh->sha1, }; fio_sha1_init(&sha1_ctx); fio_sha1_update(&sha1_ctx, p, len); fio_sha1_final(&sha1_ctx); } static void fill_crc7(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_crc7 *vh = hdr_priv(hdr); vh->crc7 = fio_crc7(p, len); } static void fill_crc16(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_crc16 *vh = hdr_priv(hdr); vh->crc16 = fio_crc16(p, len); } static void fill_crc32(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_crc32 *vh = hdr_priv(hdr); vh->crc32 = fio_crc32(p, len); } static void fill_crc32c(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_crc32 *vh = hdr_priv(hdr); vh->crc32 = fio_crc32c(p, len); } static void fill_crc64(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_crc64 *vh = hdr_priv(hdr); vh->crc64 = fio_crc64(p, len); } static void fill_md5(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_md5 *vh = hdr_priv(hdr); struct fio_md5_ctx md5_ctx = { .hash = (uint32_t *) vh->md5_digest, }; fio_md5_init(&md5_ctx); fio_md5_update(&md5_ctx, p, len); fio_md5_final(&md5_ctx); } static void __fill_hdr(struct verify_header *hdr, int verify_type, uint32_t len, uint64_t rand_seed) { void *p = hdr; hdr->magic = FIO_HDR_MAGIC; hdr->verify_type = verify_type; hdr->len = len; hdr->rand_seed = rand_seed; hdr->crc32 = fio_crc32c(p, offsetof(struct verify_header, crc32)); } static void fill_hdr(struct verify_header *hdr, int verify_type, uint32_t len, uint64_t rand_seed) { if (verify_type != VERIFY_PATTERN_NO_HDR) __fill_hdr(hdr, verify_type, len, rand_seed); } static void populate_hdr(struct thread_data *td, struct io_u *io_u, struct verify_header *hdr, unsigned int header_num, unsigned int header_len) { unsigned int data_len; void *data, *p; p = (void *) hdr; fill_hdr(hdr, td->o.verify, header_len, io_u->rand_seed); data_len = header_len - hdr_size(td, hdr); data = p + hdr_size(td, hdr); switch (td->o.verify) { case VERIFY_MD5: dprint(FD_VERIFY, "fill md5 io_u %p, len %u\n", io_u, hdr->len); fill_md5(hdr, data, data_len); break; case VERIFY_CRC64: dprint(FD_VERIFY, "fill crc64 io_u %p, len %u\n", io_u, hdr->len); fill_crc64(hdr, data, data_len); break; case VERIFY_CRC32C: case VERIFY_CRC32C_INTEL: dprint(FD_VERIFY, "fill crc32c io_u %p, len %u\n", io_u, hdr->len); fill_crc32c(hdr, data, data_len); break; case VERIFY_CRC32: dprint(FD_VERIFY, "fill crc32 io_u %p, len %u\n", io_u, hdr->len); fill_crc32(hdr, data, data_len); break; case VERIFY_CRC16: dprint(FD_VERIFY, "fill crc16 io_u %p, len %u\n", io_u, hdr->len); fill_crc16(hdr, data, data_len); break; case VERIFY_CRC7: dprint(FD_VERIFY, "fill crc7 io_u %p, len %u\n", io_u, hdr->len); fill_crc7(hdr, data, data_len); break; case VERIFY_SHA256: dprint(FD_VERIFY, "fill sha256 io_u %p, len %u\n", io_u, hdr->len); fill_sha256(hdr, data, data_len); break; case VERIFY_SHA512: dprint(FD_VERIFY, "fill sha512 io_u %p, len %u\n", io_u, hdr->len); fill_sha512(hdr, data, data_len); break; case VERIFY_XXHASH: dprint(FD_VERIFY, "fill xxhash io_u %p, len %u\n", io_u, hdr->len); fill_xxhash(hdr, data, data_len); break; case VERIFY_META: dprint(FD_VERIFY, "fill meta io_u %p, len %u\n", io_u, hdr->len); fill_meta(hdr, td, io_u, header_num); break; case VERIFY_SHA1: dprint(FD_VERIFY, "fill sha1 io_u %p, len %u\n", io_u, hdr->len); fill_sha1(hdr, data, data_len); break; case VERIFY_PATTERN: case VERIFY_PATTERN_NO_HDR: /* nothing to do here */ break; default: log_err("fio: bad verify type: %d\n", td->o.verify); assert(0); } if (td->o.verify_offset && hdr_size(td, hdr)) memswp(p, p + td->o.verify_offset, hdr_size(td, hdr)); } /* * fill body of io_u->buf with random data and add a header with the * checksum of choice */ void populate_verify_io_u(struct thread_data *td, struct io_u *io_u) { if (td->o.verify == VERIFY_NULL) return; io_u->numberio = td->io_issues[io_u->ddir]; fill_pattern_headers(td, io_u, 0, 0); } int get_next_verify(struct thread_data *td, struct io_u *io_u) { struct io_piece *ipo = NULL; /* * this io_u is from a requeue, we already filled the offsets */ if (io_u->file) return 0; if (!RB_EMPTY_ROOT(&td->io_hist_tree)) { struct rb_node *n = rb_first(&td->io_hist_tree); ipo = rb_entry(n, struct io_piece, rb_node); /* * Ensure that the associated IO has completed */ read_barrier(); if (ipo->flags & IP_F_IN_FLIGHT) goto nothing; rb_erase(n, &td->io_hist_tree); assert(ipo->flags & IP_F_ONRB); ipo->flags &= ~IP_F_ONRB; } else if (!flist_empty(&td->io_hist_list)) { ipo = flist_first_entry(&td->io_hist_list, struct io_piece, list); /* * Ensure that the associated IO has completed */ read_barrier(); if (ipo->flags & IP_F_IN_FLIGHT) goto nothing; flist_del(&ipo->list); assert(ipo->flags & IP_F_ONLIST); ipo->flags &= ~IP_F_ONLIST; } if (ipo) { td->io_hist_len--; io_u->offset = ipo->offset; io_u->buflen = ipo->len; io_u->numberio = ipo->numberio; io_u->file = ipo->file; io_u_set(io_u, IO_U_F_VER_LIST); if (ipo->flags & IP_F_TRIMMED) io_u_set(io_u, IO_U_F_TRIMMED); if (!fio_file_open(io_u->file)) { int r = td_io_open_file(td, io_u->file); if (r) { dprint(FD_VERIFY, "failed file %s open\n", io_u->file->file_name); return 1; } } get_file(ipo->file); assert(fio_file_open(io_u->file)); io_u->ddir = DDIR_READ; io_u->xfer_buf = io_u->buf; io_u->xfer_buflen = io_u->buflen; remove_trim_entry(td, ipo); free(ipo); dprint(FD_VERIFY, "get_next_verify: ret io_u %p\n", io_u); if (!td->o.verify_pattern_bytes) { io_u->rand_seed = __rand(&td->verify_state); if (sizeof(int) != sizeof(long *)) io_u->rand_seed *= __rand(&td->verify_state); } return 0; } nothing: dprint(FD_VERIFY, "get_next_verify: empty\n"); return 1; }
int verify_io_u(struct thread_data *td, struct io_u **io_u_ptr) { struct verify_header *hdr; struct io_u *io_u = *io_u_ptr; unsigned int header_size, hdr_inc, hdr_num = 0; void *p; int ret; if (td->o.verify == VERIFY_NULL || io_u->ddir != DDIR_READ) return 0; /* * If the IO engine is faking IO (like null), then just pretend * we verified everything. */ if (td->io_ops->flags & FIO_FAKEIO) return 0; if (io_u->flags & IO_U_F_TRIMMED) { ret = verify_trimmed_io_u(td, io_u); goto done; } hdr_inc = get_hdr_inc(td, io_u); ret = 0; for (p = io_u->buf; p < io_u->buf + io_u->buflen; p += hdr_inc, hdr_num++) { struct vcont vc = { .io_u = io_u, .hdr_num = hdr_num, .td = td, }; unsigned int verify_type; if (ret && td->o.verify_fatal) break; header_size = __hdr_size(td->o.verify); if (td->o.verify_offset) memswp(p, p + td->o.verify_offset, header_size); hdr = p; /* * Make rand_seed check pass when have verifysort or * verify_backlog. */ if (td->o.verifysort || (td->flags & TD_F_VER_BACKLOG)) io_u->rand_seed = hdr->rand_seed; if (td->o.verify != VERIFY_PATTERN_NO_HDR) { ret = verify_header(io_u, hdr, hdr_num, hdr_inc); if (ret) return ret; } if (td->o.verify != VERIFY_NONE) verify_type = td->o.verify; else verify_type = hdr->verify_type; switch (verify_type) { case VERIFY_MD5: ret = verify_io_u_md5(hdr, &vc); break; case VERIFY_CRC64: ret = verify_io_u_crc64(hdr, &vc); break; case VERIFY_CRC32C: case VERIFY_CRC32C_INTEL: ret = verify_io_u_crc32c(hdr, &vc); break; case VERIFY_CRC32: ret = verify_io_u_crc32(hdr, &vc); break; case VERIFY_CRC16: ret = verify_io_u_crc16(hdr, &vc); break; case VERIFY_CRC7: ret = verify_io_u_crc7(hdr, &vc); break; case VERIFY_SHA256: ret = verify_io_u_sha256(hdr, &vc); break; case VERIFY_SHA512: ret = verify_io_u_sha512(hdr, &vc); break; case VERIFY_XXHASH: ret = verify_io_u_xxhash(hdr, &vc); break; case VERIFY_META: ret = verify_io_u_meta(hdr, &vc); break; case VERIFY_SHA1: ret = verify_io_u_sha1(hdr, &vc); break; case VERIFY_PATTERN: case VERIFY_PATTERN_NO_HDR: ret = verify_io_u_pattern(hdr, &vc); break; default: log_err("Bad verify type %u\n", hdr->verify_type); ret = EINVAL; } if (ret && verify_type != hdr->verify_type) log_err("fio: verify type mismatch (%u media, %u given)\n", hdr->verify_type, verify_type); } done: if (ret && td->o.verify_fatal) fio_mark_td_terminate(td); return ret; }
void qsort( void * base, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) ) { char * i; char * j; _PDCLIB_size_t thresh = T * size; char * base_ = (char *)base; char * limit = base_ + nmemb * size; PREPARE_STACK; for ( ;; ) { if ( (size_t)( limit - base_ ) > thresh ) /* QSort for more than T elements. */ { /* We work from second to last - first will be pivot element. */ i = base_ + size; j = limit - size; /* We swap first with middle element, then sort that with second and last element so that eventually first element is the median of the three - avoiding pathological pivots. TODO: Instead of middle element, chose one randomly. */ memswp( ( ( ( (size_t)( limit - base_ ) ) / size ) / 2 ) * size + base_, base_, size ); if ( compar( i, j ) > 0 ) memswp( i, j, size ); if ( compar( base_, j ) > 0 ) memswp( base_, j, size ); if ( compar( i, base_ ) > 0 ) memswp( i, base_, size ); /* Now we have the median for pivot element, entering main Quicksort. */ for ( ;; ) { do { /* move i right until *i >= pivot */ i += size; } while ( compar( i, base_ ) < 0 ); do { /* move j left until *j <= pivot */ j -= size; } while ( compar( j, base_ ) > 0 ); if ( i > j ) { /* break loop if pointers crossed */ break; } /* else swap elements, keep scanning */ memswp( i, j, size ); } /* move pivot into correct place */ memswp( base_, j, size ); /* larger subfile base / limit to stack, sort smaller */ if ( j - base_ > limit - i ) { /* left is larger */ PUSH( base_, j ); base_ = i; } else { /* right is larger */ PUSH( i, limit ); limit = j; } } else /* insertion sort for less than T elements */ { for ( j = base_, i = j + size; i < limit; j = i, i += size ) { for ( ; compar( j, j + size ) > 0; j -= size ) { memswp( j, j + size, size ); if ( j == base_ ) { break; } } } if ( stackptr != stack ) /* if any entries on stack */ { POP( base_, limit ); } else /* else stack empty, done */ { break; } } } }
static void fill_sha512(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_sha512 *vh = hdr_priv(hdr); struct fio_sha512_ctx sha512_ctx = { .buf = vh->sha512, }; fio_sha512_init(&sha512_ctx); fio_sha512_update(&sha512_ctx, p, len); } static void fill_sha256(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_sha256 *vh = hdr_priv(hdr); struct fio_sha256_ctx sha256_ctx = { .buf = vh->sha256, }; fio_sha256_init(&sha256_ctx); fio_sha256_update(&sha256_ctx, p, len); } static void fill_sha1(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_sha1 *vh = hdr_priv(hdr); struct fio_sha1_ctx sha1_ctx = { .H = vh->sha1, }; fio_sha1_init(&sha1_ctx); fio_sha1_update(&sha1_ctx, p, len); } static void fill_crc7(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_crc7 *vh = hdr_priv(hdr); vh->crc7 = fio_crc7(p, len); } static void fill_crc16(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_crc16 *vh = hdr_priv(hdr); vh->crc16 = fio_crc16(p, len); } static void fill_crc32(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_crc32 *vh = hdr_priv(hdr); vh->crc32 = fio_crc32(p, len); } static void fill_crc32c(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_crc32 *vh = hdr_priv(hdr); vh->crc32 = fio_crc32c(p, len); } static void fill_crc64(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_crc64 *vh = hdr_priv(hdr); vh->crc64 = fio_crc64(p, len); } static void fill_md5(struct verify_header *hdr, void *p, unsigned int len) { struct vhdr_md5 *vh = hdr_priv(hdr); struct fio_md5_ctx md5_ctx = { .hash = (uint32_t *) vh->md5_digest, }; fio_md5_init(&md5_ctx); fio_md5_update(&md5_ctx, p, len); } static void populate_hdr(struct thread_data *td, struct io_u *io_u, struct verify_header *hdr, unsigned int header_num, unsigned int header_len) { unsigned int data_len; void *data, *p; p = (void *) hdr; hdr->magic = FIO_HDR_MAGIC; hdr->verify_type = td->o.verify; hdr->len = header_len; hdr->rand_seed = io_u->rand_seed; hdr->crc32 = fio_crc32c(p, offsetof(struct verify_header, crc32)); data_len = header_len - hdr_size(hdr); data = p + hdr_size(hdr); switch (td->o.verify) { case VERIFY_MD5: dprint(FD_VERIFY, "fill md5 io_u %p, len %u\n", io_u, hdr->len); fill_md5(hdr, data, data_len); break; case VERIFY_CRC64: dprint(FD_VERIFY, "fill crc64 io_u %p, len %u\n", io_u, hdr->len); fill_crc64(hdr, data, data_len); break; case VERIFY_CRC32C: case VERIFY_CRC32C_INTEL: dprint(FD_VERIFY, "fill crc32c io_u %p, len %u\n", io_u, hdr->len); fill_crc32c(hdr, data, data_len); break; case VERIFY_CRC32: dprint(FD_VERIFY, "fill crc32 io_u %p, len %u\n", io_u, hdr->len); fill_crc32(hdr, data, data_len); break; case VERIFY_CRC16: dprint(FD_VERIFY, "fill crc16 io_u %p, len %u\n", io_u, hdr->len); fill_crc16(hdr, data, data_len); break; case VERIFY_CRC7: dprint(FD_VERIFY, "fill crc7 io_u %p, len %u\n", io_u, hdr->len); fill_crc7(hdr, data, data_len); break; case VERIFY_SHA256: dprint(FD_VERIFY, "fill sha256 io_u %p, len %u\n", io_u, hdr->len); fill_sha256(hdr, data, data_len); break; case VERIFY_SHA512: dprint(FD_VERIFY, "fill sha512 io_u %p, len %u\n", io_u, hdr->len); fill_sha512(hdr, data, data_len); break; case VERIFY_META: dprint(FD_VERIFY, "fill meta io_u %p, len %u\n", io_u, hdr->len); fill_meta(hdr, td, io_u, header_num); break; case VERIFY_SHA1: dprint(FD_VERIFY, "fill sha1 io_u %p, len %u\n", io_u, hdr->len); fill_sha1(hdr, data, data_len); break; case VERIFY_PATTERN: /* nothing to do here */ break; default: log_err("fio: bad verify type: %d\n", td->o.verify); assert(0); } if (td->o.verify_offset) memswp(p, p + td->o.verify_offset, hdr_size(hdr)); } /* * fill body of io_u->buf with random data and add a header with the * checksum of choice */ void populate_verify_io_u(struct thread_data *td, struct io_u *io_u) { if (td->o.verify == VERIFY_NULL) return; fill_pattern_headers(td, io_u, 0, 0); } int get_next_verify(struct thread_data *td, struct io_u *io_u) { struct io_piece *ipo = NULL; /* * this io_u is from a requeue, we already filled the offsets */ if (io_u->file) return 0; if (!RB_EMPTY_ROOT(&td->io_hist_tree)) { struct rb_node *n = rb_first(&td->io_hist_tree); ipo = rb_entry(n, struct io_piece, rb_node); rb_erase(n, &td->io_hist_tree); assert(ipo->flags & IP_F_ONRB); ipo->flags &= ~IP_F_ONRB; } else if (!flist_empty(&td->io_hist_list)) { ipo = flist_entry(td->io_hist_list.next, struct io_piece, list); flist_del(&ipo->list); assert(ipo->flags & IP_F_ONLIST); ipo->flags &= ~IP_F_ONLIST; } if (ipo) { td->io_hist_len--; io_u->offset = ipo->offset; io_u->buflen = ipo->len; io_u->file = ipo->file; io_u->flags |= IO_U_F_VER_LIST; if (ipo->flags & IP_F_TRIMMED) io_u->flags |= IO_U_F_TRIMMED; if (!fio_file_open(io_u->file)) { int r = td_io_open_file(td, io_u->file); if (r) { dprint(FD_VERIFY, "failed file %s open\n", io_u->file->file_name); return 1; } } get_file(ipo->file); assert(fio_file_open(io_u->file)); io_u->ddir = DDIR_READ; io_u->xfer_buf = io_u->buf; io_u->xfer_buflen = io_u->buflen; remove_trim_entry(td, ipo); free(ipo); dprint(FD_VERIFY, "get_next_verify: ret io_u %p\n", io_u); return 0; } dprint(FD_VERIFY, "get_next_verify: empty\n"); return 1; } void fio_verify_init(struct thread_data *td) { if (td->o.verify == VERIFY_CRC32C_INTEL || td->o.verify == VERIFY_CRC32C) { crc32c_intel_probe(); } } static void *verify_async_thread(void *data) { struct thread_data *td = data; struct io_u *io_u; int ret = 0; if (td->o.verify_cpumask_set && fio_setaffinity(td->pid, td->o.verify_cpumask)) { log_err("fio: failed setting verify thread affinity\n"); goto done; } do { FLIST_HEAD(list); read_barrier(); if (td->verify_thread_exit) break; pthread_mutex_lock(&td->io_u_lock); while (flist_empty(&td->verify_list) && !td->verify_thread_exit) { ret = pthread_cond_wait(&td->verify_cond, &td->io_u_lock); if (ret) { pthread_mutex_unlock(&td->io_u_lock); break; } } flist_splice_init(&td->verify_list, &list); pthread_mutex_unlock(&td->io_u_lock); if (flist_empty(&list)) continue; while (!flist_empty(&list)) { io_u = flist_entry(list.next, struct io_u, verify_list); flist_del(&io_u->verify_list); ret = verify_io_u(td, io_u); put_io_u(td, io_u); if (!ret) continue; if (td_non_fatal_error(td, ERROR_TYPE_VERIFY_BIT, ret)) { update_error_count(td, ret); td_clear_error(td); ret = 0; } } } while (!ret); if (ret) { td_verror(td, ret, "async_verify"); if (td->o.verify_fatal) td->terminate = 1; } done: pthread_mutex_lock(&td->io_u_lock); td->nr_verify_threads--; pthread_mutex_unlock(&td->io_u_lock); pthread_cond_signal(&td->free_cond); return NULL; } int verify_async_init(struct thread_data *td) { int i, ret; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); td->verify_thread_exit = 0; td->verify_threads = malloc(sizeof(pthread_t) * td->o.verify_async); for (i = 0; i < td->o.verify_async; i++) { ret = pthread_create(&td->verify_threads[i], &attr, verify_async_thread, td); if (ret) { log_err("fio: async verify creation failed: %s\n", strerror(ret)); break; } ret = pthread_detach(td->verify_threads[i]); if (ret) { log_err("fio: async verify thread detach failed: %s\n", strerror(ret)); break; } td->nr_verify_threads++; } pthread_attr_destroy(&attr); if (i != td->o.verify_async) { log_err("fio: only %d verify threads started, exiting\n", i); td->verify_thread_exit = 1; write_barrier(); pthread_cond_broadcast(&td->verify_cond); return 1; } return 0; }
int verify_io_u(struct thread_data *td, struct io_u *io_u) { struct verify_header *hdr; unsigned int header_size, hdr_inc, hdr_num = 0; void *p; int ret; if (td->o.verify == VERIFY_NULL || io_u->ddir != DDIR_READ) return 0; if (io_u->flags & IO_U_F_TRIMMED) { ret = verify_trimmed_io_u(td, io_u); goto done; } hdr_inc = get_hdr_inc(td, io_u); ret = 0; for (p = io_u->buf; p < io_u->buf + io_u->buflen; p += hdr_inc, hdr_num++) { struct vcont vc = { .io_u = io_u, .hdr_num = hdr_num, .td = td, }; unsigned int verify_type; if (ret && td->o.verify_fatal) break; header_size = __hdr_size(td->o.verify); if (td->o.verify_offset) memswp(p, p + td->o.verify_offset, header_size); hdr = p; if (!verify_header(io_u, hdr)) { log_err("verify: bad magic header %x, wanted %x at " "file %s offset %llu, length %u\n", hdr->magic, FIO_HDR_MAGIC, io_u->file->file_name, io_u->offset + hdr_num * hdr->len, hdr->len); return EILSEQ; } if (td->o.verify != VERIFY_NONE) verify_type = td->o.verify; else verify_type = hdr->verify_type; switch (verify_type) { case VERIFY_MD5: ret = verify_io_u_md5(hdr, &vc); break; case VERIFY_CRC64: ret = verify_io_u_crc64(hdr, &vc); break; case VERIFY_CRC32C: case VERIFY_CRC32C_INTEL: ret = verify_io_u_crc32c(hdr, &vc); break; case VERIFY_CRC32: ret = verify_io_u_crc32(hdr, &vc); break; case VERIFY_CRC16: ret = verify_io_u_crc16(hdr, &vc); break; case VERIFY_CRC7: ret = verify_io_u_crc7(hdr, &vc); break; case VERIFY_SHA256: ret = verify_io_u_sha256(hdr, &vc); break; case VERIFY_SHA512: ret = verify_io_u_sha512(hdr, &vc); break; case VERIFY_META: ret = verify_io_u_meta(hdr, &vc); break; case VERIFY_SHA1: ret = verify_io_u_sha1(hdr, &vc); break; case VERIFY_PATTERN: ret = verify_io_u_pattern(hdr, &vc); break; default: log_err("Bad verify type %u\n", hdr->verify_type); ret = EINVAL; } if (ret && verify_type != hdr->verify_type) log_err("fio: verify type mismatch (%u media, %u given)\n", hdr->verify_type, verify_type); } done: if (ret && td->o.verify_fatal) td->terminate = 1; return ret; }
int ReadGrib2Record (DataSource &fp, sChar f_unit, double **Grib_Data, uInt4 *grib_DataLen, grib_MetaData *meta, IS_dataType *IS, int subgNum, double majEarth, double minEarth, int simpVer, sInt4 *f_endMsg, CPL_UNUSED LatLon *lwlf, CPL_UNUSED LatLon *uprt) { sInt4 l3264b; /* Number of bits in a sInt4. Needed by FORTRAN * unpack library to determine if system has a 4 * byte_ sInt4 or an 8 byte sInt4. */ char *buff; /* Holds the info between records. */ uInt4 buffLen; /* Length of info between records. */ sInt4 sect0[SECT0LEN_WORD]; /* Holds the current Section 0. */ uInt4 gribLen; /* Length of the current GRIB message. */ sInt4 nd5; /* Size of grib message rounded up to the nearest * sInt4. */ char *c_ipack; /* A char ptr to the message stored in IS->ipack */ sInt4 local_ns[8]; /* Local copy of section lengths. */ sInt4 nd2x3; /* Total number of grid points. */ short int table50; /* Type of packing used. (See code table 5.0) * (GS5_SIMPLE==0, GS5_CMPLX==2, GS5_CMPLXSEC==3) */ sInt4 nidat; /* Size of section 2 if it contains integer data. */ sInt4 nrdat; /* Size of section 2 if it contains float data. */ sInt4 inew; /* 1 if this is the first grid we are reading. 0 if * this is the second or later grid from the same * GRIB message. */ sInt4 iclean = 0; /* 0 embed the missing values, 1 don't. */ int j; /* Counter used to find the desired subgrid. */ sInt4 kfildo = 5; /* FORTRAN Unit number for diagnostic info. Ignored, * unless library is compiled a particular way. */ sInt4 ibitmap; /* 0 means no bitmap returned, otherwise 1. */ float xmissp; /* The primary missing value. If iclean = 0, this * value is embeded in grid, otherwise it is the * value returned from the GRIB message. */ float xmisss; /* The secondary missing value. If iclean = 0, this * value is embeded in grid, otherwise it is the * value returned from the GRIB message. */ sInt4 jer[UNPK_NUM_ERRORS * 2]; /* Any Error codes along with their * * severity levels generated using the * * unpack GRIB2 library. */ sInt4 ndjer = UNPK_NUM_ERRORS; /* The number of rows in JER( ). */ sInt4 kjer; /* The actual number of errors returned in JER. */ size_t i; /* counter as we loop through jer. */ double unitM, unitB; /* values in y = m x + b used for unit conversion. */ char unitName[15]; /* Holds the string name of the current unit. */ int unitLen; /* String length of string name of current unit. */ int version; /* Which version of GRIB is in this message. */ sInt4 cnt; /* Used to help compact the weather table. */ int x1, y1; /* The original grid coordinates of the lower left * corner of the subgrid. */ int x2, y2; /* The original grid coordinates of the upper right * corner of the subgrid. */ uChar f_subGrid; /* True if we have a subgrid. */ sInt4 Nx, Ny; /* original size of the data. */ /* * f_endMsg is 1 if in the past we either completed reading a message, * or we haven't read any messages. In either case we need to read the * next message from file. * If f_endMsg is false, then there is more to read from IS->ipack, so we * don't want to throw it out, nor have to re-read ipack from disk. */ l3264b = sizeof (sInt4) * 8; buff = NULL; buffLen = 0; if (*f_endMsg == 1) { if (ReadSECT0 (fp, &buff, &buffLen, -1, sect0, &gribLen, &version) < 0) { preErrSprintf ("Inside ReadGrib2Record\n"); free (buff); return -1; } meta->GribVersion = version; if (version == 1) { if (ReadGrib1Record (fp, f_unit, Grib_Data, grib_DataLen, meta, IS, sect0, gribLen, majEarth, minEarth) != 0) { preErrSprintf ("Problems with ReadGrib1Record called by " "ReadGrib2Record\n"); free (buff); return -1; } *f_endMsg = 1; free (buff); return 0; } else if (version == -1) { if (ReadTDLPRecord (fp, Grib_Data, grib_DataLen, meta, IS, sect0, gribLen, majEarth, minEarth) != 0) { preErrSprintf ("Problems with ReadGrib1Record called by " "ReadGrib2Record\n"); free (buff); return -1; } free (buff); return 0; } /* * Make room for entire message, and read it in. */ /* nd5 needs to be gribLen in (sInt4) units rounded up. */ nd5 = (gribLen + 3) / 4; if (nd5 > IS->ipackLen) { IS->ipackLen = nd5; IS->ipack = (sInt4 *) realloc ((void *) (IS->ipack), (IS->ipackLen) * sizeof (sInt4)); } c_ipack = (char *) IS->ipack; /* Init last sInt4 to 0, to make sure that the padded bytes are 0. */ IS->ipack[nd5 - 1] = 0; /* Init first 4 sInt4 to sect0. */ memcpy (c_ipack, sect0, SECT0LEN_WORD * 4); /* Read in the rest of the message. */ if (fp.DataSourceFread (c_ipack + SECT0LEN_WORD * 4, sizeof (char), (gribLen - SECT0LEN_WORD * 4)) != (gribLen - SECT0LEN_WORD * 4)) { errSprintf ("GribLen = %ld, SECT0Len_WORD = %d\n", gribLen, SECT0LEN_WORD); errSprintf ("Ran out of file\n"); free (buff); return -1; } /* * Make sure the arrays are large enough for call to unpacker library. */ /* FindSectLen Does not want (ipack / c_ipack) word swapped, because * that would make it much more confusing to find bytes in c_ipack. */ if (FindSectLen (c_ipack, gribLen, local_ns, &nd2x3, &table50) < 0) { preErrSprintf ("Inside ReadGrib2Record.. Calling FindSectLen\n"); free (buff); return -2; } /* Make sure all 'is' arrays except ns[7] are MAX (IS.ns[] , * local_ns[]). See note 1 for reason to exclude ns[7] from MAX (). */ for (i = 0; i < 7; i++) { if (local_ns[i] > IS->ns[i]) { IS->ns[i] = local_ns[i]; IS->is[i] = (sInt4 *) realloc ((void *) (IS->is[i]), IS->ns[i] * sizeof (sInt4)); } } /* Allocate room for sect 2. If local_ns[2] = -1 there is no sect 2. */ if (local_ns[2] == -1) { nidat = 10; nrdat = 10; } else { /* * See note 2) We have a section 2, so use: * MAX (32 * local_ns[2],SECT2_INTSIZE) * and MAX (32 * local_ns[2],SECT2_FLOATSIZE) * for size of section 2 unpacked. */ nidat = (32 * local_ns[2] < SECT2_INIT_SIZE) ? SECT2_INIT_SIZE : 32 * local_ns[2]; nrdat = nidat; } if (nidat > IS->nidat) { IS->nidat = nidat; IS->idat = (sInt4 *) realloc ((void *) IS->idat, IS->nidat * sizeof (sInt4)); } if (nrdat > IS->nrdat) { IS->nrdat = nrdat; IS->rdat = (float *) realloc ((void *) IS->rdat, IS->nrdat * sizeof (float)); } /* Make sure we have room for the GRID part of the output. */ if (nd2x3 > IS->nd2x3) { IS->nd2x3 = nd2x3; IS->iain = (sInt4 *) realloc ((void *) IS->iain, IS->nd2x3 * sizeof (sInt4)); IS->ib = (sInt4 *) realloc ((void *) IS->ib, IS->nd2x3 * sizeof (sInt4)); } /* See note 3) If table50 == 3, unpacker library needs nd5 >= nd2x3. */ if ((table50 == 3) || (table50 == 0)) { if (nd5 < nd2x3) { nd5 = nd2x3; if (nd5 > IS->ipackLen) { IS->ipackLen = nd5; IS->ipack = (sInt4 *) realloc ((void *) (IS->ipack), IS->ipackLen * sizeof (sInt4)); } /* Don't need to do the following, but we do in case code * changes. */ c_ipack = (char *) IS->ipack; } } IS->nd5 = nd5; /* Unpacker library requires ipack to be MSB. */ /* #ifdef DEBUG if (1==1) { FILE *fp = fopen ("test.bin", "wb"); fwrite (IS->ipack, sizeof (sInt4), IS->nd5, fp); fclose (fp); } #endif */ #ifdef LITTLE_ENDIAN memswp (IS->ipack, sizeof (sInt4), IS->nd5); #endif } else { gribLen = IS->ipack[3]; } free (buff); /* Loop through the grib message looking for the subgNum grid. subgNum * goes from 0 to n-1. */ for (j = 0; j <= subgNum; j++) { if (j == 0) { inew = 1; } else { inew = 0; } /* Note we are getting data back either as a float or an int, but not * both, so we don't need to allocated room for both. */ unpk_grib2 (&kfildo, (float *) (IS->iain), IS->iain, &(IS->nd2x3), IS->idat, &(IS->nidat), IS->rdat, &(IS->nrdat), IS->is[0], &(IS->ns[0]), IS->is[1], &(IS->ns[1]), IS->is[2], &(IS->ns[2]), IS->is[3], &(IS->ns[3]), IS->is[4], &(IS->ns[4]), IS->is[5], &(IS->ns[5]), IS->is[6], &(IS->ns[6]), IS->is[7], &(IS->ns[7]), IS->ib, &ibitmap, IS->ipack, &(IS->nd5), &xmissp, &xmisss, &inew, &iclean, &l3264b, f_endMsg, jer, &ndjer, &kjer); /* * Check for error messages... * If we get an error message, print it, and return. */ for (i = 0; i < (uInt4) kjer; i++) { if (jer[ndjer + i] == 0) { /* no error. */ } else if (jer[ndjer + i] == 1) { /* Warning. */ #ifdef DEBUG printf ("Warning: Unpack library warning code (%d %d)\n", jer[i], jer[ndjer + i]); #endif } else { /* BAD Error. */ errSprintf ("ERROR: Unpack library error code (%ld %ld)\n", jer[i], jer[ndjer + i]); return -3; } } } /* Parse the meta data out. */ if (MetaParse (meta, IS->is[0], IS->ns[0], IS->is[1], IS->ns[1], IS->is[2], IS->ns[2], IS->rdat, IS->nrdat, IS->idat, IS->nidat, IS->is[3], IS->ns[3], IS->is[4], IS->ns[4], IS->is[5], IS->ns[5], gribLen, xmissp, xmisss, simpVer) != 0) { #ifdef DEBUG FILE *fp; if ((fp = fopen ("dump.is0", "wt")) != NULL) { for (i = 0; i < 8; i++) { fprintf (fp, "---Section %d---\n", (int) i); for (j = 1; j <= IS->ns[i]; j++) { fprintf (fp, "IS%d Item %d = %d\n", (int) i, (int) j, IS->is[i][j - 1]); } } fclose (fp); } #endif preErrSprintf ("Inside ReadGrib2Record.. Problems in MetaParse\n"); return -4; } if ((majEarth > 6000) && (majEarth < 7000)) { if ((minEarth > 6000) && (minEarth < 7000)) { meta->gds.f_sphere = 0; meta->gds.majEarth = majEarth; meta->gds.minEarth = minEarth; } else { meta->gds.f_sphere = 1; meta->gds.majEarth = majEarth; meta->gds.minEarth = majEarth; } } /* Figure out an equation to pass to ParseGrid to convert the units for * this grid. */ /* if (ComputeUnit (meta->pds2.prodType, meta->pds2.sect4.templat, meta->pds2.sect4.cat, meta->pds2.sect4.subcat, f_unit, &unitM, &unitB, unitName) == 0) { */ if (ComputeUnit (meta->convert, meta->unitName, f_unit, &unitM, &unitB, unitName) == 0) { unitLen = strlen (unitName); meta->unitName = (char *) realloc ((void *) (meta->unitName), 1 + unitLen * sizeof (char)); strncpy (meta->unitName, unitName, unitLen); meta->unitName[unitLen] = '\0'; } /* compute the subgrid. */ /* if ((lwlf->lat != -100) && (uprt->lat != -100)) { Nx = meta->gds.Nx; Ny = meta->gds.Ny; if (computeSubGrid (lwlf, &x1, &y1, uprt, &x2, &y2, &(meta->gds), &newGds) != 0) { preErrSprintf ("ERROR: In compute subgrid.\n"); return 1; } // I couldn't decide if I should "permanently" change the GDS or not. // when I wrote computeSubGrid. If next line stays, really should // rewrite computeSubGrid. memcpy (&(meta->gds), &newGds, sizeof (gdsType)); f_subGrid = 1; } else { Nx = meta->gds.Nx; Ny = meta->gds.Ny; x1 = 1; x2 = Nx; y1 = 1; y2 = Ny; f_subGrid = 0; } */ Nx = meta->gds.Nx; Ny = meta->gds.Ny; x1 = 1; x2 = Nx; y1 = 1; y2 = Ny; f_subGrid = 0; /* Figure out if we need iain or ain, and set it to Grib_Data. At the * same time handle any bitmaps, and compute some statistics. */ if ((f_subGrid) && (meta->gds.scan != 64)) { errSprintf ("Can not do a subgrid of non scanmode 64 grid yet.\n"); return -3; } if (strcmp (meta->element, "Wx") != 0) { ParseGrid (&(meta->gridAttrib), Grib_Data, grib_DataLen, Nx, Ny, meta->gds.scan, IS->iain, ibitmap, IS->ib, unitM, unitB, 0, NULL, f_subGrid, x1, y1, x2, y2); } else { /* Handle weather grid. ParseGrid looks up the values... If they are * "<Invalid>" it sets it to missing (or creates one). If the table * entry is used it sets f_valid to 2. */ ParseGrid (&(meta->gridAttrib), Grib_Data, grib_DataLen, Nx, Ny, meta->gds.scan, IS->iain, ibitmap, IS->ib, unitM, unitB, 1, (sect2_WxType *) &(meta->pds2.sect2.wx), f_subGrid, x1, y1, x2, y2); /* compact the table to only those which are actually used. */ cnt = 0; for (i = 0; i < meta->pds2.sect2.wx.dataLen; i++) { if (meta->pds2.sect2.wx.ugly[i].f_valid == 2) { meta->pds2.sect2.wx.ugly[i].validIndex = cnt; cnt++; } else if (meta->pds2.sect2.wx.ugly[i].f_valid == 3) { meta->pds2.sect2.wx.ugly[i].f_valid = 0; meta->pds2.sect2.wx.ugly[i].validIndex = cnt; cnt++; } else { meta->pds2.sect2.wx.ugly[i].validIndex = -1; } } } /* Figure out some other non-section oriented meta data. */ /* strftime (meta->refTime, 20, "%Y%m%d%H%M", gmtime (&(meta->pds2.refTime))); */ Clock_Print (meta->refTime, 20, meta->pds2.refTime, "%Y%m%d%H%M", 0); /* strftime (meta->validTime, 20, "%Y%m%d%H%M", gmtime (&(meta->pds2.sect4.validTime))); */ Clock_Print (meta->validTime, 20, meta->pds2.sect4.validTime, "%Y%m%d%H%M", 0); meta->deltTime = (sInt4) (meta->pds2.sect4.validTime - meta->pds2.refTime); return 0; }
int verify_io_u(struct thread_data *td, struct io_u *io_u) { struct verify_header *hdr; unsigned int header_size, hdr_inc, hdr_num = 0; void *p; int ret; if (td->o.verify == VERIFY_NULL || io_u->ddir != DDIR_READ) return 0; if (io_u->flags & IO_U_F_TRIMMED) { ret = verify_trimmed_io_u(td, io_u); goto done; } hdr_inc = get_hdr_inc(td, io_u); ret = 0; for (p = io_u->buf; p < io_u->buf + io_u->buflen; p += hdr_inc, hdr_num++) { struct vcont vc = { .io_u = io_u, .hdr_num = hdr_num, .td = td, }; unsigned int verify_type; if (ret && td->o.verify_fatal) break; header_size = __hdr_size(td->o.verify); if (td->o.verify_offset) memswp(p, p + td->o.verify_offset, header_size); hdr = p; /* * Make rand_seed check pass when have verifysort or * verify_backlog. */ if (td->o.verifysort || (td->flags & TD_F_VER_BACKLOG)) io_u->rand_seed = hdr->rand_seed; ret = verify_header(io_u, hdr); switch (ret) { case 0: break; case 1: log_err("verify: bad magic header %x, wanted %x at " "file %s offset %llu, length %u\n", hdr->magic, FIO_HDR_MAGIC, io_u->file->file_name, io_u->offset + hdr_num * hdr->len, hdr->len); return EILSEQ; break; case 2: log_err("fio: verify header exceeds buffer length (%u " "> %lu)\n", hdr->len, io_u->buflen); return EILSEQ; break; case 3: log_err("verify: bad header rand_seed %"PRIu64 ", wanted %"PRIu64" at file %s offset %llu, " "length %u\n", hdr->rand_seed, io_u->rand_seed, io_u->file->file_name, io_u->offset + hdr_num * hdr->len, hdr->len); return EILSEQ; break; case 4: return EILSEQ; break; default: log_err("verify: unknown header error at file %s " "offset %llu, length %u\n", io_u->file->file_name, io_u->offset + hdr_num * hdr->len, hdr->len); return EILSEQ; } if (td->o.verify != VERIFY_NONE) verify_type = td->o.verify; else verify_type = hdr->verify_type; switch (verify_type) { case VERIFY_MD5: ret = verify_io_u_md5(hdr, &vc); break; case VERIFY_CRC64: ret = verify_io_u_crc64(hdr, &vc); break; case VERIFY_CRC32C: case VERIFY_CRC32C_INTEL: ret = verify_io_u_crc32c(hdr, &vc); break; case VERIFY_CRC32: ret = verify_io_u_crc32(hdr, &vc); break; case VERIFY_CRC16: ret = verify_io_u_crc16(hdr, &vc); break; case VERIFY_CRC7: ret = verify_io_u_crc7(hdr, &vc); break; case VERIFY_SHA256: ret = verify_io_u_sha256(hdr, &vc); break; case VERIFY_SHA512: ret = verify_io_u_sha512(hdr, &vc); break; case VERIFY_XXHASH: ret = verify_io_u_xxhash(hdr, &vc); break; case VERIFY_META: ret = verify_io_u_meta(hdr, &vc); break; case VERIFY_SHA1: ret = verify_io_u_sha1(hdr, &vc); break; case VERIFY_PATTERN: ret = verify_io_u_pattern(hdr, &vc); break; default: log_err("Bad verify type %u\n", hdr->verify_type); ret = EINVAL; } if (ret && verify_type != hdr->verify_type) log_err("fio: verify type mismatch (%u media, %u given)\n", hdr->verify_type, verify_type); } done: if (ret && td->o.verify_fatal) td->terminate = 1; return ret; }