rem: printf("error %s writing blocks %ld:%d (%d != %d)\n",
add: printf("error %s writing blocks %Ld:%d (%d != %d)\n",
context: flush_ents(cache_ent **ents, int n_ents){    int    i, j, k, ret = 0, bsize, iocnt, do_again = 0;    fs_off_t  start_bnum;    struct iovec *iov;        iov = get_iovec_array();    if (iov == NULL)        return ENOMEM;restart:    for(i=0; i < n_ents; i++) {        /* if true, then there's nothing to flush */        if ((ents[i]->flags & CE_DIRTY) == 0 && ents[i]->clone == NULL)            continue;        /* if true we can't touch the dirty data yet because it's locked */        if (ents[i]->clone == NULL && ents[i]->lock != 0)            continue;                bsize      = ents[i]->bsize;        start_bnum = ents[i]->block_num;        for(j=i+1; j < n_ents && (j - i) < NUM_FLUSH_BLOCKS; j++) {            if (ents[j]->dev != ents[i]->dev ||                ents[j]->block_num != start_bnum + (j - i))                break;            if (ents[j]->clone == NULL && ents[j]->lock != 0)                break;        }                if (j == i+1) {           /* only one block, just flush it directly */            if ((ret = flush_cache_ent(ents[i])) != 0)                break;            continue;        }        for(k=i,iocnt=0; k < j; k++,iocnt++) {            if (ents[k]->clone)                iov[iocnt].iov_base = ents[k]->clone;            else                iov[iocnt].iov_base = ents[k]->data;            iov[iocnt].iov_len = bsize;        }		if (chatty_io)	        printf("writev @ %Ld for %d blocks\n", start_bnum, iocnt);        ret = writev_pos(ents[i]->dev, start_bnum * (fs_off_t)bsize,                          &iov[0], iocnt);        if (ret != iocnt*bsize) {            int idx;            printf("flush_ents: writev failed: iocnt %d start bnum %ld "                   "bsize %d, ret %d\n", iocnt, start_bnum, bsize, ret);            for(idx=0; idx < iocnt; idx++)                printf("iov[%2d] = 0x%8x :: %d\n", idx, iov[idx].iov_base,                       iov[idx].iov_len);            printf("error %s writing blocks %ld:%d (%d != %d)\n",                   strerror(errno), start_bnum, iocnt, ret, iocnt*bsize);            ret = EINVAL;            break;        }        ret = 0;        for(k=i; k < j; k++) {            if (ents[k]->func) {                ents[k]->func(ents[k]->logged_bnum, 1, ents[k]->arg);                ents[k]->func = NULL;            }            if (ents[k]->clone) {                free(ents[k]->clone);                ents[k]->clone = NULL;            } else {                ents[k]->flags &= ~CE_DIRTY;            }        }                    i = j - 1;  /* i gets incremented by the outer for loop */    }    /*       here we have to go back through and flush any blocks that are       still dirty.  with an arched brow you astutely ask, "but how       could this happen given the above loop?"  Ahhh young grasshopper       I say, the path through the cache is long and twisty and fraught       with peril.  The reason it can happen is that a block can be both       cloned and dirty.  The above loop would only flush the cloned half       of the data, not the main dirty block.  So we have to go back       through and see if there are any blocks that are still dirty.  If       there are we go back to the top of the function and do the whole       thing over.  Kind of grody but it is necessary to insure the       correctness of the log for the Be file system.    */       if (do_again == 0) {        for(i=0; i < n_ents; i++) {            if ((ents[i]->flags & CE_DIRTY) == 0 || ents[i]->lock)                continue;            do_again = 1;            break;        }        if (do_again)            goto restart;    }        release_iovec_array(iov);    return ret;}