int ndmta_write_quantum (struct ndm_session *sess) { struct ndm_tape_agent * ta = sess->tape_acb; struct ndmchan * ch = &sess->plumb.image_stream->chan; uint32_t count = ta->mover_state.record_size; int did_something = 0; uint64_t max_read; uint64_t want_window_off; uint32_t block_size; uint32_t want_blockno; uint32_t cur_blockno; unsigned n_avail, n_read, record_off; char * data; uint32_t done_count = 0; ndmp9_error error; again: n_read = n_avail = ndmchan_n_avail_record (ch, count); if (n_avail < count) { /* allow to drain */ return did_something; } if (ta->pending_change_after_drain) { if (ndmchan_n_ready (ch) > 0) { /* allow to drain */ } else { ndmta_mover_apply_pending (sess); did_something++; } return did_something; } if (n_read > ta->mover_state.bytes_left_to_read) n_read = ta->mover_state.bytes_left_to_read; if (n_read < count) { /* Active, but paused awaiting MOVER_READ request */ return did_something; /* mover blocked */ } if (ta->mover_want_pos < ta->mover_state.window_offset || ta->mover_want_pos >= ta->mover_window_end) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_SEEK); goto again; } max_read = ta->mover_window_end - ta->mover_want_pos; if (n_read > max_read) n_read = max_read; want_window_off = ta->mover_want_pos - ta->mover_state.window_offset; /* make an estimate of the block size - the tape agent's block size, or * if it's in variable block size mode, the mover's record size: "When * in variable block mode, as indicated by a tape block_size value of * zero, the mover record size defines the actual block size used by * the tape subsystem." (NDMPv4 RFC, Section 3.6.2.1) */ block_size = ta->tape_state.block_size.value; if (!block_size) block_size = ta->mover_state.record_size; want_blockno = ta->mover_window_first_blockno + want_window_off / block_size; if (ta->tb_blockno != want_blockno) { uint32_t xsr_count, xsr_resid; ndmos_tape_sync_state(sess); cur_blockno = ta->tape_state.blockno.value; if (cur_blockno < want_blockno) { xsr_count = want_blockno - cur_blockno; error = ndmos_tape_mtio (sess, NDMP9_MTIO_FSR, xsr_count, &xsr_resid); if (error == NDMP9_EOF_ERR) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_EOF); goto again; } if (error != NDMP9_NO_ERR) { ndmta_mover_halt_pending (sess, NDMP9_MOVER_HALT_MEDIA_ERROR); goto again; } if (xsr_resid > 0) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_EOF); goto again; } } else if (cur_blockno > want_blockno) { xsr_count = cur_blockno - want_blockno; error = ndmos_tape_mtio (sess, NDMP9_MTIO_BSR, xsr_count, &xsr_resid); if (error != NDMP9_NO_ERR || xsr_resid > 0) { ndmta_mover_halt_pending (sess, NDMP9_MOVER_HALT_MEDIA_ERROR); goto again; } } else { /* in position */ } /* * We are about to read data into a tape buffer so make sure * we have it available. We delay allocating buffers to the * moment we first need them. */ if (!ta->tape_buffer) { ta->tape_buffer = NDMOS_API_MALLOC (NDMOS_CONST_TAPE_REC_MAX); if (!ta->tape_buffer) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_HALT_NA); goto again; } } data = ta->tape_buffer; done_count = 0; error = ndmos_tape_read (sess, data, count, &done_count); did_something++; if (error == NDMP9_EOF_ERR) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_EOF); goto again; } /* N.B. - handling of done_count = 0 here is hacked to support * non-blocking writes to a socket in amndmjob */ if (error != NDMP9_NO_ERR) { ndmta_mover_halt_pending (sess, NDMP9_MOVER_HALT_MEDIA_ERROR); goto again; } if (done_count == 0) { return did_something - 1; } if (done_count != count) { goto again; } ta->tb_blockno = want_blockno; /* re-calcluate this, since record_size may be > block_size, in which * case the record_num may not change for each block read from tape */ ta->mover_state.record_num = ta->mover_want_pos / ta->mover_state.record_size; } record_off = ta->mover_want_pos % ta->mover_state.record_size; n_avail = ta->mover_state.record_size - record_off; if (n_read > n_avail) n_read = n_avail; if (n_read != done_count) { printf("lost %lu bytes %lu %u\n", done_count - n_read, done_count, n_read); n_read = done_count; } /* * We are about to read data into a tape buffer so make sure * we have it available. We delay allocating buffers to the * moment we first need them. */ if (!ta->tape_buffer) { ta->tape_buffer = NDMOS_API_MALLOC (NDMOS_CONST_TAPE_REC_MAX); if (!ta->tape_buffer) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_HALT_NA); goto again; } } data = &ta->tape_buffer[record_off]; bcopy (data, ch->data + ch->end_ix, n_read); ch->end_ix += n_read; ta->mover_state.bytes_moved += n_read; ta->mover_want_pos += n_read; ta->mover_state.bytes_left_to_read -= n_read; did_something++; goto again; /* do as much as possible */ }
int ndmta_write_quantum (struct ndm_session *sess) { struct ndm_tape_agent * ta = &sess->tape_acb; struct ndmchan * ch = &sess->plumb.image_stream.chan; unsigned long count = ta->mover_state.record_size; int did_something = 0; unsigned long long max_read; unsigned long long want_window_off; unsigned long want_blockno; unsigned long cur_blockno; unsigned n_avail, n_read, record_off; char * data; unsigned long done_count; ndmp9_error error; again: n_read = n_avail = ndmchan_n_avail (ch); if (n_avail == 0) { /* allow to drain */ return did_something; } if (ta->pending_change_after_drain) { if (ndmchan_n_ready (ch) > 0) { /* allow to drain */ } else { ndmta_mover_apply_pending (sess); did_something++; } return did_something; } if (n_read > ta->mover_state.bytes_left_to_read) n_read = ta->mover_state.bytes_left_to_read; if (n_read == 0) { /* Active, but paused awaiting MOVER_READ request */ return did_something; /* mover blocked */ } if (ta->mover_want_pos < ta->mover_state.window_offset || ta->mover_want_pos >= ta->mover_window_end) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_SEEK); goto again; } max_read = ta->mover_window_end - ta->mover_want_pos; if (n_read > max_read) n_read = max_read; want_window_off = ta->mover_want_pos - ta->mover_state.window_offset; want_blockno = want_window_off / ta->mover_state.record_size; if (ta->tb_blockno != want_blockno) { unsigned long xsr_count, xsr_resid; ndmos_tape_sync_state(sess); cur_blockno = ta->tape_state.blockno.value; if (cur_blockno < want_blockno) { xsr_count = want_blockno - cur_blockno; error = ndmos_tape_mtio (sess, NDMP9_MTIO_FSR, xsr_count, &xsr_resid); if (error == NDMP9_EOF_ERR) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_EOF); goto again; } if (error != NDMP9_NO_ERR) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_MEDIA_ERROR); goto again; } if (xsr_resid > 0) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_EOF); goto again; } } else if (cur_blockno > want_blockno) { xsr_count = cur_blockno - want_blockno; error = ndmos_tape_mtio (sess, NDMP9_MTIO_BSR, xsr_count, &xsr_resid); if (error != NDMP9_NO_ERR || xsr_resid > 0) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_MEDIA_ERROR); goto again; } } else { /* in position */ } data = ta->tape_buffer; done_count = 0; error = ndmos_tape_read (sess, data, count, &done_count); did_something++; if (error == NDMP9_EOF_ERR) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_EOF); goto again; } if (error != NDMP9_NO_ERR) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_MEDIA_ERROR); goto again; } if (done_count == 0) { return did_something - 1; } if (done_count != count) { n_read = done_count; goto aaa; ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_MEDIA_ERROR); goto again; } ta->tb_blockno = want_blockno; } aaa: record_off = ta->mover_want_pos % ta->mover_state.record_size; n_avail = ta->mover_state.record_size - record_off; if (n_read > n_avail) n_read = n_avail; data = &ta->tape_buffer[record_off]; bcopy (data, ch->data + ch->end_ix, n_read); ch->end_ix += n_read; ta->mover_want_pos += n_read; ta->mover_state.bytes_left_to_read -= n_read; did_something++; goto again; /* do as much as possible */ }
int ndmta_write_quantum (struct ndm_session *sess) { struct ndm_tape_agent * ta = &sess->tape_acb; struct ndmchan * ch = &sess->plumb.image_stream.chan; unsigned long count = ta->mover_state.record_size; int did_something = 0; unsigned long long max_read; unsigned long long want_window_off; unsigned long block_size; unsigned long want_blockno; unsigned long cur_blockno; unsigned n_avail, n_read, record_off; char * data; unsigned long done_count; ndmp9_error error; again: n_read = n_avail = ndmchan_n_avail (ch); if (n_avail == 0) { /* allow to drain */ return did_something; } if (ta->pending_change_after_drain) { if (ndmchan_n_ready (ch) > 0) { /* allow to drain */ } else { ndmta_mover_apply_pending (sess); did_something++; } return did_something; } if (n_read > ta->mover_state.bytes_left_to_read) n_read = ta->mover_state.bytes_left_to_read; if (n_read == 0) { /* Active, but paused awaiting MOVER_READ request */ return did_something; /* mover blocked */ } if (ta->mover_want_pos < ta->mover_state.window_offset || ta->mover_want_pos >= ta->mover_window_end) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_SEEK); goto again; } max_read = ta->mover_window_end - ta->mover_want_pos; if (n_read > max_read) n_read = max_read; want_window_off = ta->mover_want_pos - ta->mover_state.window_offset; /* make an estimate of the block size - the tape agent's block size, or * if it's in variable block size mode, the mover's record size: "When * in variable block mode, as indicated by a tape block_size value of * zero, the mover record size defines the actual block size used by * the tape subsystem." (NDMPv4 RFC, Section 3.6.2.1) */ block_size = ta->tape_state.block_size.value; if (!block_size) block_size = ta->mover_state.record_size; want_blockno = ta->mover_window_first_blockno + want_window_off / block_size; if (ta->tb_blockno != want_blockno) { unsigned long xsr_count, xsr_resid; ndmos_tape_sync_state(sess); cur_blockno = ta->tape_state.blockno.value; if (cur_blockno < want_blockno) { xsr_count = want_blockno - cur_blockno; error = ndmos_tape_mtio (sess, NDMP9_MTIO_FSR, xsr_count, &xsr_resid); if (error == NDMP9_EOF_ERR) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_EOF); goto again; } if (error != NDMP9_NO_ERR) { ndmta_mover_halt_pending (sess, NDMP9_MOVER_HALT_MEDIA_ERROR); goto again; } if (xsr_resid > 0) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_EOF); goto again; } } else if (cur_blockno > want_blockno) { xsr_count = cur_blockno - want_blockno; error = ndmos_tape_mtio (sess, NDMP9_MTIO_BSR, xsr_count, &xsr_resid); if (error != NDMP9_NO_ERR || xsr_resid > 0) { ndmta_mover_halt_pending (sess, NDMP9_MOVER_HALT_MEDIA_ERROR); goto again; } } else { /* in position */ } data = ta->tape_buffer; done_count = 0; error = ndmos_tape_read (sess, data, count, &done_count); did_something++; if (error == NDMP9_EOF_ERR) { ndmta_mover_pause_pending (sess, NDMP9_MOVER_PAUSE_EOF); goto again; } if (error != NDMP9_NO_ERR || done_count != count) { ndmta_mover_halt_pending (sess, NDMP9_MOVER_HALT_MEDIA_ERROR); goto again; } ta->tb_blockno = want_blockno; /* re-calcluate this, since record_size may be > block_size, in which * case the record_num may not change for each block read from tape */ ta->mover_state.record_num = ta->mover_want_pos / ta->mover_state.record_size; } record_off = ta->mover_want_pos % ta->mover_state.record_size; n_avail = ta->mover_state.record_size - record_off; if (n_read > n_avail) n_read = n_avail; data = &ta->tape_buffer[record_off]; bcopy (data, ch->data + ch->end_ix, n_read); ch->end_ix += n_read; ta->mover_state.bytes_moved += n_read; ta->mover_want_pos += n_read; ta->mover_state.bytes_left_to_read -= n_read; did_something++; goto again; /* do as much as possible */ }