/* * Pretty printer */ void ndmchan_pp (struct ndmchan *ch, char *buf) { int show_ra = 0; char * bp = buf; char * p; sprintf (bp, "name=%s", ch->name); while (*bp) bp++; switch (ch->mode) { case NDMCHAN_MODE_IDLE: p = "idle"; break; case NDMCHAN_MODE_RESIDENT: p = "resident"; show_ra = 1; break; case NDMCHAN_MODE_READ: p = "read"; show_ra = 1; break; case NDMCHAN_MODE_WRITE: p = "write"; show_ra = 1; break; case NDMCHAN_MODE_READCHK: p = "readchk"; break; case NDMCHAN_MODE_LISTEN: p = "listen"; break; case NDMCHAN_MODE_PENDING: p = "pending"; break; case NDMCHAN_MODE_CLOSED: p = "closed"; break; default: p = "mode=???"; break; } sprintf (bp, " %s ", p); while (*bp) bp++; if (show_ra) { sprintf (bp, "ready=%d avail=%d ", ndmchan_n_ready(ch), ndmchan_n_avail(ch)); while (*bp) bp++; } if (ch->ready) strcat (bp, "-rdy"); if (ch->check) strcat (bp, "-chk"); if (ch->eof) strcat (bp, "-eof"); if (ch->error) strcat (bp, "-err"); }
enum ndmchan_read_interpretation ndmchan_read_interpret (struct ndmchan *ch, char **data_p, unsigned *n_ready_p) { unsigned n_ready; n_ready = *n_ready_p = ndmchan_n_ready (ch); *data_p = &ch->data[ch->beg_ix]; if (ch->error) { if (n_ready == 0) { return NDMCHAN_RI_DONE_ERROR; } else { return NDMCHAN_RI_DRAIN_ERROR; } } if (ch->eof) { if (n_ready == 0) { return NDMCHAN_RI_DONE_EOF; } else { return NDMCHAN_RI_DRAIN_EOF; } } if (n_ready == 0) { return NDMCHAN_RI_EMPTY; } if (n_ready == ch->data_size) { return NDMCHAN_RI_READY_FULL; } return NDMCHAN_RI_READY; }
int ndmda_quantum_stderr (struct ndm_session *sess) { struct ndm_data_agent * da = sess->data_acb; struct ndmchan * ch = &da->formatter_error; int did_something = 0; char * p; char * data; char * pend; unsigned n_ready; again: n_ready = ndmchan_n_ready (ch); if (n_ready == 0) return did_something; data = p = &ch->data[ch->beg_ix]; pend = p + n_ready; while (p < pend && *p != '\n') p++; if (p < pend && *p == '\n') { *p++ = 0; ndma_send_logmsg (sess, NDMP9_LOG_NORMAL, sess->plumb.data, "%s", data); ch->beg_ix += p - data; did_something++; goto again; } if (!ch->eof) return did_something; /* content w/o newline, and EOF */ /* p == pend */ if (ch->end_ix >= ch->data_size) { if (data != ch->data) { ndmchan_compress (ch); goto again; } /* that's one huge message */ p--; /* lose last byte */ } ch->data[ch->end_ix++] = '\n'; did_something++; goto again; }
int ndmchan_pre_poll (struct ndmchan *chtab[], unsigned n_chtab) { struct ndmchan * ch; unsigned int i, n_check; n_check = 0; for (i = 0; i < n_chtab; i++) { ch = chtab[i]; ch->ready = 0; ch->check = 0; if (ch->error) continue; switch (ch->mode) { default: case NDMCHAN_MODE_IDLE: case NDMCHAN_MODE_PENDING: case NDMCHAN_MODE_RESIDENT: case NDMCHAN_MODE_CLOSED: continue; case NDMCHAN_MODE_LISTEN: case NDMCHAN_MODE_READCHK: break; case NDMCHAN_MODE_READ: if (ch->eof) continue; if (ndmchan_n_avail (ch) == 0) continue; break; case NDMCHAN_MODE_WRITE: if (ndmchan_n_ready (ch) == 0) continue; break; } ch->check = 1; n_check++; } return n_check; }
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_read_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 n_ready; char * data; unsigned long done_count; ndmp9_error error; again: n_ready = ndmchan_n_ready (ch); if (ch->eof) { if (n_ready == 0) { /* done */ if (ch->saved_errno) ndmta_mover_halt (sess, NDMP9_MOVER_HALT_CONNECT_ERROR); else ndmta_mover_halt (sess, NDMP9_MOVER_HALT_CONNECT_CLOSED); did_something++; return did_something; } if (n_ready < count) { int n_pad = count - n_ready; unsigned n_avail; while (n_pad > 0) { n_avail = ndmchan_n_avail (ch); if (n_avail == 0) { /* Uh-oh */ } data = &ch->data[ch->end_ix]; if (n_avail > n_pad) n_avail = n_pad; bzero (data, n_avail); ch->end_ix += n_avail; n_pad -= n_avail; } n_ready = ndmchan_n_ready (ch); } } if (n_ready < count) { return did_something; /* blocked */ } if (ta->mover_want_pos >= ta->mover_window_end) { ndmta_mover_pause (sess, NDMP9_MOVER_PAUSE_SEEK); did_something++; return did_something; } data = &ch->data[ch->beg_ix]; done_count = 0; error = ndmos_tape_write (sess, data, count, &done_count); switch (error) { case NDMP9_NO_ERR: if (done_count != count) { /* This ain't suppose to happen */ } ta->mover_state.bytes_moved += count; ta->mover_want_pos += count; ch->beg_ix += count; did_something++; goto again; /* write as much to tape as possible */ case NDMP9_EOM_ERR: ndmta_mover_pause (sess, NDMP9_MOVER_PAUSE_EOM); did_something++; break; default: ndmta_mover_pause (sess, NDMP9_MOVER_PAUSE_MEDIA_ERROR); did_something++; break; } return did_something; }
int ndmda_quantum_image (struct ndm_session *sess) { struct ndm_data_agent * da = sess->data_acb; struct ndmchan * from_chan; struct ndmchan * to_chan; unsigned n_ready, n_avail, n_copy; int is_backup = 0; switch (da->data_state.operation) { default: assert (0); from_chan = 0; to_chan = 0; break; case NDMP9_DATA_OP_BACKUP: from_chan = &da->formatter_image; to_chan = &sess->plumb.image_stream->chan; is_backup = 1; break; case NDMP9_DATA_OP_RECOVER: case NDMP9_DATA_OP_RECOVER_FILEHIST: from_chan = &sess->plumb.image_stream->chan; to_chan = &da->formatter_image; break; } again: n_copy = n_ready = ndmchan_n_ready (from_chan); if (n_ready == 0) { if (from_chan->eof) { to_chan->eof = 1; if (ndmchan_n_ready (to_chan) == 0) { if (is_backup) { ndmda_data_halt (sess, NDMP9_DATA_HALT_SUCCESSFUL); } } } return 0; /* data blocked */ } n_avail = ndmchan_n_avail (to_chan); if (n_copy > n_avail) n_copy = n_avail; if (da->enable_hist) { if (n_copy > da->pass_resid) n_copy = da->pass_resid; } if (n_copy > 0) { bcopy (&from_chan->data[from_chan->beg_ix], &to_chan->data[to_chan->end_ix], n_copy); from_chan->beg_ix += n_copy; to_chan->end_ix += n_copy; da->data_state.bytes_processed += n_copy; da->pass_resid -= n_copy; goto again; /* do as much as possible */ } return 0; }
int ndmda_quantum_wrap (struct ndm_session *sess) { struct ndm_data_agent * da = sess->data_acb; struct ndmchan * ch = &da->formatter_wrap; int did_something = 0; char * p; char * data; char * pend; unsigned n_ready; int is_recover = 0; switch (da->data_state.operation) { default: assert (0); break; case NDMP9_DATA_OP_BACKUP: break; case NDMP9_DATA_OP_RECOVER: case NDMP9_DATA_OP_RECOVER_FILEHIST: is_recover = 1; break; } again: n_ready = ndmchan_n_ready (ch); if (n_ready == 0) { if (ch->eof && is_recover) { ndmda_data_halt (sess, NDMP9_DATA_HALT_SUCCESSFUL); } return did_something; } data = p = &ch->data[ch->beg_ix]; pend = p + n_ready; while (p < pend && *p != '\n') p++; if (p < pend && *p == '\n') { *p++ = 0; ndmda_wrap_in (sess, data); ch->beg_ix += p - data; did_something++; goto again; } if (!ch->eof) return did_something; /* content w/o newline, and EOF */ /* p == pend */ if (ch->end_ix >= ch->data_size) { if (data != ch->data) { ndmchan_compress (ch); goto again; } /* that's one huge message */ p--; /* lose last byte */ } ch->data[ch->end_ix++] = '\n'; did_something++; goto again; }
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 ndmchan_post_poll (struct ndmchan *chtab[], unsigned n_chtab) { struct ndmchan * ch; unsigned int i; int rc, len, n_ready; n_ready = 0; for (i = 0; i < n_chtab; i++) { ch = chtab[i]; if (!ch->ready) continue; switch (ch->mode) { case NDMCHAN_MODE_READ: len = ndmchan_n_avail (ch); if (len <= 0) continue; n_ready++; rc = read (ch->fd, &ch->data[ch->end_ix], len); if (rc < 0) { if (errno != NDMOS_CONST_EWOULDBLOCK) { ch->error = ch->eof = 1; ch->saved_errno = errno; if (!ch->saved_errno) ch->saved_errno = -1; } else { /* no bytes read */ } } else if (rc == 0) { ch->eof = 1; ch->error = 0; ch->saved_errno = 0; } else { ch->end_ix += rc; } break; case NDMCHAN_MODE_WRITE: len = ndmchan_n_ready (ch); if (len <= 0) continue; n_ready++; rc = write (ch->fd, &ch->data[ch->beg_ix], len); if (rc < 0) { if (errno != NDMOS_CONST_EWOULDBLOCK) { ch->eof = 1; ch->error = 1; ch->saved_errno = errno; if (!ch->saved_errno) ch->saved_errno = -1; } else { /* no bytes written */ /* EWOULDBLOCK but ready? */ } } else if (rc == 0) { /* NDMOS_CONST_EWOULDBLOCK? */ ch->eof = 1; ch->error = 1; ch->saved_errno = 0; } else { ch->beg_ix += rc; } break; } } return n_ready; }
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 */ }