3 * block.c -- tape block handling functions
5 * Kern Sibbald, March MMI
11 Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of
16 the License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public
24 License along with this program; if not, write to the Free
25 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
34 extern int debug_level;
37 * Dump the block header, then walk through
38 * the block printing out the record headers.
40 void dump_block(DEV_BLOCK *b, char *msg)
44 char Id[BLKHDR_ID_LENGTH+1];
45 uint32_t CheckSum, BlockCheckSum;
48 uint32_t VolSessionId, VolSessionTime, data_len;
52 unser_begin(b->buf, BLKHDR_LENGTH);
53 unser_uint32(CheckSum);
54 unser_uint32(block_len);
55 unser_uint32(BlockNumber);
56 unser_bytes(Id, BLKHDR_ID_LENGTH);
57 ASSERT(unser_length(b->buf) == BLKHDR_LENGTH);
58 Id[BLKHDR_ID_LENGTH] = 0;
60 if (block_len > 100000) {
61 Dmsg3(20, "Dump block %s %s blocksize too big %d\n", msg, b, block_len);
65 BlockCheckSum = bcrc32((uint8_t *)b->buf+BLKHDR_CS_LENGTH,
66 block_len-BLKHDR_CS_LENGTH);
67 Dmsg6(10, "Dump block %s %x: size=%d BlkNum=%d\n\
68 Hdrcksum=%x cksum=%x\n",
69 msg, b, block_len, BlockNumber, CheckSum, BlockCheckSum);
70 p = b->buf + BLKHDR_LENGTH;
71 while (p < (b->buf + block_len+RECHDR_LENGTH)) {
72 unser_begin(p, RECHDR_LENGTH);
73 unser_uint32(VolSessionId);
74 unser_uint32(VolSessionTime);
75 unser_int32(FileIndex);
77 unser_uint32(data_len);
78 Dmsg6(10, "Rec: VId=%d VT=%d FI=%s Strm=%s len=%d p=%x\n",
79 VolSessionId, VolSessionTime, FI_to_ascii(FileIndex), stream_to_ascii(Stream),
81 p += data_len + RECHDR_LENGTH;
87 * Create a new block structure.
88 * We pass device so that the block can inherit the
89 * min and max block sizes.
91 DEV_BLOCK *new_block(DEVICE *dev)
93 DEV_BLOCK *block = (DEV_BLOCK *)get_memory(sizeof(DEV_BLOCK));
95 memset(block, 0, sizeof(DEV_BLOCK));
97 if (dev->max_block_size == 0) {
98 block->buf_len = DEFAULT_BLOCK_SIZE;
100 block->buf_len = dev->max_block_size;
102 if (block->buf_len % TAPE_BSIZE != 0) {
103 Mmsg2(&dev->errmsg, _("Block size %d forced to be multiple of %d\n"),
104 block->buf_len, TAPE_BSIZE);
105 Emsg0(M_WARNING, 0, dev->errmsg);
106 block->buf_len = ((block->buf_len + TAPE_BSIZE - 1) / TAPE_BSIZE) * TAPE_BSIZE;
108 block->block_len = block->buf_len; /* default block size */
109 block->buf = get_memory(block->buf_len);
110 if (block->buf == NULL) {
111 Mmsg0(&dev->errmsg, _("Unable to malloc block buffer.\n"));
112 Emsg0(M_FATAL, 0, dev->errmsg);
116 Dmsg1(90, "Returning new block=%x\n", block);
123 void free_block(DEV_BLOCK *block)
125 Dmsg1(199, "free_block buffer %x\n", block->buf);
126 free_memory(block->buf);
127 Dmsg1(199, "free_block block %x\n", block);
128 free_memory((POOLMEM *)block);
131 /* Empty the block -- for writing */
132 void empty_block(DEV_BLOCK *block)
134 block->binbuf = BLKHDR_LENGTH;
135 block->bufp = block->buf + block->binbuf;
137 block->failed_write = FALSE;
141 * Create block header just before write. The space
142 * in the buffer should have already been reserved by
145 static void ser_block_header(DEV_BLOCK *block)
148 uint32_t CheckSum = 0;
149 uint32_t block_len = block->binbuf;
151 Dmsg1(190, "ser_block_header: block_len=%d\n", block_len);
152 ser_begin(block->buf, BLKHDR_LENGTH);
153 ser_uint32(CheckSum);
154 ser_uint32(block_len);
155 ser_uint32(block->BlockNumber);
156 ser_bytes(BLKHDR_ID, BLKHDR_ID_LENGTH);
157 ASSERT(ser_length(block->buf) == BLKHDR_LENGTH);
159 /* Checksum whole block except for the checksum */
160 CheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH,
161 block_len-BLKHDR_CS_LENGTH);
162 Dmsg1(190, "ser_bloc_header: checksum=%x\n", CheckSum);
163 ser_begin(block->buf, BLKHDR_LENGTH);
164 ser_uint32(CheckSum);
168 * Unserialized the block header for reading block.
169 * This includes setting all the buffer pointers correctly.
171 * Returns: 0 on failure (not a block)
174 static int unser_block_header(DEVICE *dev, DEV_BLOCK *block)
177 char Id[BLKHDR_ID_LENGTH+1];
178 uint32_t CheckSum, BlockCheckSum;
181 uint32_t BlockNumber;
183 unser_begin(block->buf, BLKHDR_LENGTH);
184 unser_uint32(CheckSum);
185 unser_uint32(block_len);
186 unser_uint32(BlockNumber);
187 unser_bytes(Id, BLKHDR_ID_LENGTH);
188 ASSERT(unser_length(block->buf) == BLKHDR_LENGTH);
190 Id[BLKHDR_ID_LENGTH] = 0;
191 block->bufp = block->buf + BLKHDR_LENGTH;
192 if (strncmp(Id, BLKHDR_ID, BLKHDR_ID_LENGTH) != 0) {
193 Mmsg2(&dev->errmsg, _("Buffer ID error. Wanted: %s, got %s. Buffer discarded.\n"),
195 Emsg0(M_ERROR, 0, dev->errmsg);
199 ASSERT(block_len < MAX_BLOCK_LENGTH); /* temp sanity check */
201 Dmsg1(190, "unser_block_header block_len=%d\n", block_len);
202 /* Find end of block or end of buffer whichever is smaller */
203 if (block_len > block->read_len) {
204 EndBlock = block->read_len;
206 EndBlock = block_len;
208 block->binbuf = EndBlock - BLKHDR_LENGTH;
209 block->block_len = block_len;
210 block->BlockNumber = BlockNumber;
211 Dmsg3(190, "Read binbuf = %d %d block_len=%d\n", block->binbuf,
212 BLKHDR_LENGTH, block_len);
213 if (block_len > block->buf_len) {
214 Mmsg2(&dev->errmsg, _("Block length %d is greater than buffer %d\n"),
215 block_len, block->buf_len);
216 Emsg0(M_ERROR, 0, dev->errmsg);
219 if (block_len <= block->read_len) {
220 BlockCheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH,
221 block_len-BLKHDR_CS_LENGTH);
222 if (BlockCheckSum != CheckSum) {
223 Dmsg2(00, "Block checksum mismatch: calc=%x blk=%x\n", BlockCheckSum,
225 Mmsg2(&dev->errmsg, _("Block checksum mismatch: calc=%x blk=%x\n"), BlockCheckSum,
234 * Write a block to the device, with locking and unlocking
236 * Returns: 1 on success
240 int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
244 if (!write_block_to_dev(dev, block)) {
245 stat = fixup_device_block_write_error(jcr, dev, block);
252 * Write a block to the device
254 * Returns: 1 on success or EOT
257 int write_block_to_dev(DEVICE *dev, DEV_BLOCK *block)
260 uint32_t wlen; /* length to write */
262 ASSERT(block->binbuf == ((uint32_t) (block->bufp - block->buf)));
264 /* dump_block(block, "before write"); */
265 if (dev->state & ST_WEOT) {
266 Dmsg0(90, "return write_block_to_dev with ST_WEOT\n");
269 wlen = block->binbuf;
270 if (wlen <= BLKHDR_LENGTH) { /* Does block have data in it? */
271 Dmsg0(190, "return write_block_to_dev no data to write\n");
275 * Clear to the end of the buffer if it is not full,
276 * and on tape devices, apply min and fixed blocking.
278 if (wlen != block->buf_len) {
279 uint32_t blen; /* current buffer length */
281 Dmsg2(200, "binbuf=%d buf_len=%d\n", block->binbuf, block->buf_len);
284 /* Adjust write size to min/max for tapes only */
285 if (dev->state & ST_TAPE) {
286 if (wlen < dev->min_block_size) {
287 wlen = ((dev->min_block_size + TAPE_BSIZE - 1) / TAPE_BSIZE) * TAPE_BSIZE;
289 if (dev->min_block_size == dev->max_block_size) {
290 wlen = block->buf_len; /* fixed block size already rounded */
294 memset(block->bufp, 0, wlen-blen); /* clear garbage */
299 block->BlockNumber = dev->block_num;
300 ser_block_header(block);
302 /* Limit maximum Volume size to value specified by user */
303 if ((dev->max_volume_size > 0) &&
304 ((dev->VolCatInfo.VolCatBytes + block->binbuf)) >= dev->max_volume_size) {
305 dev->state |= ST_WEOT;
306 Dmsg0(10, "==== Output bytes Triggered medium max capacity.\n");
307 Mmsg2(&dev->errmsg, _("Max. Volume capacity %" lld " exceeded on device %s.\n"),
308 dev->max_volume_size, dev->dev_name);
309 block->failed_write = TRUE;
310 /* ****FIXME**** write EOD record here */
311 weof_dev(dev, 1); /* end the tape */
312 weof_dev(dev, 1); /* write second eof */
316 dev->VolCatInfo.VolCatWrites++;
317 if ((uint32_t) (stat=write(dev->fd, block->buf, wlen)) != wlen) {
318 /* We should check for errno == ENOSPC, BUT many
319 * devices simply report EIO when it is full.
320 * with a little more thought we may be able to check
321 * capacity and distinguish real errors and EOT
322 * conditions. In any case, we probably want to
323 * simulate an End of Medium.
325 /***FIXME**** if we wrote a partial record, back up over it */
326 dev->state |= ST_EOF | ST_EOT | ST_WEOT;
327 clrerror_dev(dev, -1);
329 Dmsg2(0, "=== Write error %d: ERR=%s\n", dev->dev_errno,
330 strerror(dev->dev_errno));
332 if (dev->dev_errno == 0) {
333 dev->dev_errno = ENOSPC; /* out of space */
335 Mmsg2(&dev->errmsg, _("Write error on device %s. ERR=%s.\n"),
336 dev->dev_name, strerror(dev->dev_errno));
337 block->failed_write = TRUE;
338 weof_dev(dev, 1); /* end the tape */
339 weof_dev(dev, 1); /* write second eof */
342 dev->VolCatInfo.VolCatBytes += block->binbuf;
343 dev->VolCatInfo.VolCatBlocks++;
344 dev->file_bytes += block->binbuf;
346 /* Limit maximum File size on volume to user specified value */
347 if ((dev->max_file_size > 0) &&
348 dev->file_bytes >= dev->max_file_size) {
349 weof_dev(dev, 1); /* write eof */
352 Dmsg2(190, "write_block: wrote block %d bytes=%d\n", dev->block_num,
359 * Read block with locking
362 int read_block_from_device(DEVICE *dev, DEV_BLOCK *block)
365 Dmsg0(90, "Enter read_block_from_device\n");
367 stat = read_block_from_dev(dev, block);
369 Dmsg0(90, "Leave read_block_from_device\n");
374 * Read the next block into the block structure and unserialize
375 * the block header. For a file, the block may be partially
376 * or completely in the current buffer.
378 int read_block_from_dev(DEVICE *dev, DEV_BLOCK *block)
382 Dmsg0(90, "Full read() in read_block_from_device()\n");
383 if ((stat=read(dev->fd, block->buf, block->buf_len)) < 0) {
385 /* ***FIXME**** add code to detect buffer too small, and
386 reallocate buffer, backspace, and reread.
390 Dmsg1(90, "Read device got: ERR=%s\n", strerror(errno));
391 clrerror_dev(dev, -1);
393 Mmsg2(&dev->errmsg, _("Read error on device %s. ERR=%s.\n"),
394 dev->dev_name, strerror(dev->dev_errno));
397 Dmsg1(90, "Read device got %d bytes\n", stat);
398 if (stat == 0) { /* Got EOF ! */
399 dev->block_num = block->read_len = 0;
400 Mmsg1(&dev->errmsg, _("Read zero bytes on device %s.\n"), dev->dev_name);
401 if (dev->state & ST_EOF) { /* EOF alread read? */
402 dev->state |= ST_EOT; /* yes, 2 EOFs => EOT */
405 dev->file++; /* increment file */
406 dev->state |= ST_EOF; /* set EOF read */
407 return 0; /* return eof */
409 /* Continue here for successful read */
410 block->read_len = stat; /* save length read */
411 if (block->read_len < BLKHDR_LENGTH) {
412 Mmsg2(&dev->errmsg, _("Very short block of %d bytes on device %s discarded.\n"),
413 block->read_len, dev->dev_name);
414 dev->state |= ST_SHORT; /* set short block */
415 block->read_len = block->binbuf = 0;
416 return 0; /* return error */
418 if (!unser_block_header(dev, block)) {
422 if (block->block_len > block->read_len) {
423 Mmsg2(&dev->errmsg, _("Short block of %d bytes on device %s discarded.\n"),
424 block->read_len, dev->dev_name);
425 dev->state |= ST_SHORT; /* set short block */
426 block->read_len = block->binbuf = 0;
427 return 0; /* return error */
430 /* Make sure block size is not too big (temporary
431 * sanity check) and that we read the full block.
433 ASSERT(block->block_len < MAX_BLOCK_LENGTH);
435 dev->state &= ~(ST_EOF|ST_SHORT); /* clear EOF and short block */
439 * If we read a short block on disk,
440 * seek to beginning of next block. This saves us
441 * from shuffling blocks around in the buffer. Take a
442 * look at this from an efficiency stand point later, but
443 * it should only happen once at the end of each job.
445 Dmsg0(200, "At end of read block\n");
446 if (block->read_len > block->block_len && !(dev->state & ST_TAPE)) {
448 Dmsg3(200, "Block: %d read_len %d > %d block_len\n", dev->block_num,
449 block->read_len, block->block_len);
450 lseek(dev->fd, block->block_len-block->read_len, SEEK_CUR);
451 Dmsg2(90, "Did lseek blk_size=%d rdlen=%d\n", block->block_len,
454 Dmsg2(200, "Exit read_block read_len=%d block_len=%d\n",
455 block->read_len, block->block_len);