2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 * record_write.c -- Volume (tape/disk) record write functions
23 * Kern Sibbald, April MMI
24 * added BB02 format October MMII
25 * added aligned format November MMXII
33 /* Imported functions */
35 static const int dbgep = 250; /* debug execution path */
36 static const int dbgel = 250; /* debug Enter/Leave code */
47 * Write an ameta (normal) header record to the block.
49 static bool write_header_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
53 Dmsg0(dbgep, "=== wpath 11 write_header_to_block\n");
54 ASSERT2(!block->adata, "Attempt to write header to adata block!");
55 rec->remlen = block->buf_len - block->binbuf;
56 /* Require enough room to write a full header */
57 if (rec->remlen < WRITE_RECHDR_LENGTH) {
58 Dmsg0(dbgep, "=== wpath 12 write_header_to_block\n");
59 Dmsg5(190, "remlen<WRITE_RECHDR_LEN adata=%d remlen=%d<%d reclen buf_len=%d binbuf=%d\n",
60 block->adata, rec->remlen, WRITE_RECHDR_LENGTH, block->buf_len, block->binbuf);
61 rec->remainder = rec->data_len + WRITE_RECHDR_LENGTH;
64 ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
66 Dmsg0(dbgep, "=== wpath 13 write_header_to_block\n");
67 ser_uint32(rec->VolSessionId);
68 ser_uint32(rec->VolSessionTime);
70 Dmsg0(dbgep, "=== wpath 14 write_header_to_block\n");
71 block->VolSessionId = rec->VolSessionId;
72 block->VolSessionTime = rec->VolSessionTime;
74 ser_int32(rec->FileIndex);
75 ser_int32(rec->Stream);
76 ser_uint32(rec->data_len);
78 block->bufp += WRITE_RECHDR_LENGTH;
79 block->binbuf += WRITE_RECHDR_LENGTH;
82 rec->remlen -= WRITE_RECHDR_LENGTH;
83 rec->remainder = rec->data_len;
84 if (rec->FileIndex > 0) {
85 Dmsg0(dbgep, "=== wpath 15 write_header_to_block\n");
86 /* If data record, update what we have in this block */
87 if (block->FirstIndex == 0) {
88 Dmsg0(dbgep, "=== wpath 16 write_header_to_block\n");
89 block->FirstIndex = rec->FileIndex;
91 block->LastIndex = rec->FileIndex;
94 //dump_block(dcr->dev, block, "Add header");
99 * If the prior ameta block was not big enough to hold the
100 * whole record, write a continuation header record.
102 static void write_continue_header_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
106 Dmsg0(dbgep, "=== wpath 17 write_cont_hdr_to_block\n");
107 ASSERT2(!block->adata, "Attempt to write adata header!");
108 rec->remlen = block->buf_len - block->binbuf;
110 /* No space left to write the continue header */
111 if (rec->remlen == 0) {
116 * We have unwritten bytes from a previous
117 * time. Presumably we have a new buffer (possibly
118 * containing a volume label), so the new header
119 * should be able to fit in the block -- otherwise we have
120 * an error. Note, we have to continue splitting the
121 * data record if it is longer than the block.
123 * First, write the header.
125 * Every time we write a header and it is a continuation
126 * of a previous partially written record, we store the
127 * Stream as -Stream in the record header.
129 ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
130 if (BLOCK_VER == 1) {
131 Dmsg0(dbgep, "=== wpath 18 write_cont_hdr_to_block\n");
132 ser_uint32(rec->VolSessionId);
133 ser_uint32(rec->VolSessionTime);
135 Dmsg0(dbgep, "=== wpath 19 write_cont_hdr_to_block\n");
136 block->VolSessionId = rec->VolSessionId;
137 block->VolSessionTime = rec->VolSessionTime;
139 ser_int32(rec->FileIndex);
140 if (rec->remainder > rec->data_len) {
141 Dmsg0(dbgep, "=== wpath 20 write_cont_hdr_to_block\n");
142 ser_int32(rec->Stream); /* normal full header */
143 ser_uint32(rec->data_len);
144 rec->remainder = rec->data_len; /* must still do data record */
146 Dmsg0(dbgep, "=== wpath 21 write_cont_hdr_to_block\n");
147 ser_int32(-rec->Stream); /* mark this as a continuation record */
148 ser_uint32(rec->remainder); /* bytes to do */
151 /* Require enough room to write a full header */
152 ASSERT(rec->remlen >= WRITE_RECHDR_LENGTH);
154 block->bufp += WRITE_RECHDR_LENGTH;
155 block->binbuf += WRITE_RECHDR_LENGTH;
156 rec->remlen -= WRITE_RECHDR_LENGTH;
157 if (rec->FileIndex > 0) {
158 Dmsg0(dbgep, "=== wpath 22 write_cont_hdr_to_block\n");
159 /* If data record, update what we have in this block */
160 if (block->FirstIndex == 0) {
161 Dmsg0(dbgep, "=== wpath 23 write_cont_hdr_to_block\n");
162 block->FirstIndex = rec->FileIndex;
164 block->LastIndex = rec->FileIndex;
167 Dmsg3(150, "=== write_cont_hdr ptr=%p begin=%p off=%d\n", block->bufp,
168 block->buf, block->bufp-block->buf);
171 //dump_block(dcr->dev, block, "Add cont header");
175 * Now write non-aligned data to an ameta block
177 static bool write_data_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
179 Dmsg0(dbgep, "=== wpath 24 write_data_to_block\n");
180 ASSERT2(!block->adata, "Attempt to write adata to metadata file!");
181 rec->remlen = block->buf_len - block->binbuf;
182 /* Write as much of data as possible */
183 if (rec->remlen >= rec->remainder) {
184 Dmsg0(dbgep, "=== wpath 25 write_data_to_block\n");
185 memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
187 block->bufp += rec->remainder;
188 block->binbuf += rec->remainder;
191 if (rec->state_bits & REC_NO_SPLIT) {
192 return false; /* do not split record */
194 Dmsg0(dbgep, "=== wpath 26 write_data_to_block\n");
195 memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
197 block->bufp += rec->remlen;
198 block->binbuf += rec->remlen;
199 rec->remainder -= rec->remlen;
200 return false; /* did partial transfer */
203 /* Adata label data */
204 Dmsg3(190, "write_data adata=%d blkAddr=%lld off=%d\n",
205 block->adata, block->BlockAddr, block->bufp-block->buf);
207 //dump_block(dcr->dev, block, "Add data/adata");
212 * Write a record to the block -- handles writing out full
213 * blocks by writing them to the device.
215 * Returns: false means the block could not be written to tape/disk.
216 * true on success (all bytes written to the block).
218 bool DCR::write_record(DEV_RECORD *rec)
221 Dmsg0(dbgep, "=== wpath 33 write_record\n");
222 while (!write_record_to_block(this, rec)) {
223 Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
225 if (jcr->is_canceled()) {
229 if (!write_block_to_device()) {
230 Dmsg0(dbgep, "=== wpath 34 write_record\n");
231 Pmsg2(000, "Got write_block_to_dev error on device %s. %s\n",
232 dev->print_name(), dev->bstrerror());
236 Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
244 * Write a record to the block
246 * Returns: false on failure (none or partially written)
247 * true on success (all bytes written)
249 * and remainder returned in packet.
251 * We require enough room for the header, and we deal with
252 * two special cases. 1. Only part of the record may have
253 * been transferred the last time (when remainder is
254 * non-zero), and 2. The remaining bytes to write may not
255 * all fit into the block.
257 * Ensure we leave with same ameta/adata set as enter.
259 bool write_record_to_block(DCR *dcr, DEV_RECORD *rec)
261 char buf1[100], buf2[100];
262 bool save_adata = dcr->block->adata;
266 Dmsg0(dbgep, "=== wpath 35 enter write_record_to_block\n");
267 Dmsg7(250, "write_record_to_block() state=%d FI=%s SessId=%d"
268 " Strm=%s len=%d rem=%d remainder=%d\n", rec->wstate,
269 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
270 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
271 rec->remlen, rec->remainder);
272 Dmsg4(250, "write_rec Strm=%s len=%d rem=%d remainder=%d\n",
273 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
274 rec->remlen, rec->remainder);
276 if (!dcr->dev->do_pre_write_checks(dcr, rec)) {
281 Dmsg0(dbgep, "=== wpath 37 top of for loop\n");
282 ASSERT(dcr->block->binbuf == (uint32_t) (dcr->block->bufp - dcr->block->buf));
283 ASSERT(dcr->block->buf_len >= dcr->block->binbuf);
285 switch (rec->wstate) {
287 Dmsg0(dbgep, "=== wpath 38 st_none\n");
288 /* Figure out what to do */
289 rec->wstate = st_header;
290 /* If labeling adata, special path */
291 if (dcr->adata_label) {
292 Dmsg1(dbgep, "=== wpath adata_label set adata=%d\n", dcr->dev->adata);
293 rec->wstate = st_adata_label;
296 if (rec->FileIndex < 0) {
297 /* Label record -- ameta label */
298 Dmsg3(dbgep, "=== wpath label adata=%d Strm=%d FI=%d\n",
299 dcr->dev->adata, rec->Stream, rec->FileIndex);
300 rec->wstate = st_header;
304 dcr->dev->select_data_stream(dcr, rec);
305 continue; /* go to next state */
311 * If rec->remainder is non-zero, we have been called a
312 * second (or subsequent) time to finish writing a record
313 * that did not previously fit into the block.
315 Dmsg0(dbgep, "=== wpath 42 st_header\n");
317 if (!write_header_to_block(dcr, dcr->ameta_block, rec)) {
318 Dmsg0(dbgep, "=== wpath 43 st_header\n");
319 rec->wstate = st_cont_header;
322 Dmsg0(dbgep, "=== wpath 44 st_header\n");
323 rec->wstate = st_data;
327 Dmsg0(dbgep, "=== wpath 45 st_cont_header\n");
329 write_continue_header_to_block(dcr, dcr->ameta_block, rec);
330 rec->wstate = st_data;
331 if (rec->remlen == 0) {
332 Dmsg0(dbgep, "=== wpath 46 st_cont_header\n");
338 * We come here only once for each record
344 * Part of it may have already been transferred, and we
345 * may not have enough room to transfer the whole this time.
347 Dmsg0(dbgep, "=== wpath 47 st_data\n");
349 if (rec->remainder > 0) {
350 Dmsg0(dbgep, "=== wpath 48 st_data\n");
351 if (!write_data_to_block(dcr, dcr->ameta_block, rec)) {
352 Dmsg0(dbgep, "=== wpath 49 st_data\n");
353 if (rec->state_bits & REC_NO_SPLIT) {
354 rec->wstate = st_header;
356 rec->wstate = st_cont_header;
361 rec->state_bits &= ~REC_NO_SPLIT; /* clear possible no split bit */
362 rec->remainder = 0; /* did whole transfer */
363 rec->wstate = st_none;
367 if (!dcr->dev->write_adata_label(dcr, rec)) {
373 * We come here only once for each record
376 dcr->dev->write_adata(dcr, rec);
380 dcr->dev->write_cont_adata(dcr, rec);
384 * Note, the following two cases are handled differently
385 * in write_adata_record_header() so take care if you want to
386 * eliminate one of them.
388 case st_cont_adata_rechdr:
389 Dmsg2(200, "=== cont rechdr remainder=%d reclen=%d\n", rec->remainder, dcr->adata_block->reclen);
390 Dmsg0(200, "st_cont_adata_rechdr\n");
391 /* Fall through wanted */
392 case st_adata_rechdr:
393 switch(dcr->dev->write_adata_rechdr(dcr, rec)) {
404 Dmsg0(dbgep, "=== wpath 67!!!! default\n");
405 Dmsg0(50, "Something went wrong. Default state.\n");
406 rec->wstate = st_none;