X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fstored%2Fblock.c;h=832da0ee2542fc18d5e4226e214c16c1c09f7f68;hb=6bea24b0386f7076c4bdba4c3ce7ffb2953511b3;hp=5a3028403e38d761e5ee2e8feb7d31f26784e93a;hpb=0a9df1396b3b144f5593c39cc14534bcb7827fac;p=bacula%2Fbacula diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index 5a3028403e..832da0ee25 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -38,7 +38,7 @@ extern int debug_level; * Dump the block header, then walk through * the block printing out the record headers. */ -void dump_block(DEV_BLOCK *b, char *msg) +void dump_block(DEV_BLOCK *b, const char *msg) { ser_declare; char *p; @@ -116,17 +116,28 @@ DEV_BLOCK *new_block(DEVICE *dev) block->dev = dev; block->block_len = block->buf_len; /* default block size */ block->buf = get_memory(block->buf_len); - if (block->buf == NULL) { - Mmsg0(&dev->errmsg, _("Unable to malloc block buffer.\n")); - Emsg0(M_FATAL, 0, dev->errmsg); - return NULL; - } empty_block(block); block->BlockVer = BLOCK_VER; /* default write version */ Dmsg1(90, "Returning new block=%x\n", block); return block; } + +/* + * Duplicate an existing block (eblock) + */ +DEV_BLOCK *dup_block(DEV_BLOCK *eblock) +{ + DEV_BLOCK *block = (DEV_BLOCK *)get_memory(sizeof(DEV_BLOCK)); + int buf_len = sizeof_pool_memory(eblock->buf); + + memcpy(block, eblock, sizeof(DEV_BLOCK)); + block->buf = get_memory(buf_len); + memcpy(block->buf, eblock->buf, buf_len); + return block; +} + + /* * Only the first block checksum error was reported. * If there are more, report it now. @@ -134,7 +145,7 @@ DEV_BLOCK *new_block(DEVICE *dev) void print_block_read_errors(JCR *jcr, DEV_BLOCK *block) { if (block->read_errors > 1) { - Jmsg(jcr, M_ERROR, 0, _("%d block read errors ignored.\n"), + Jmsg(jcr, M_ERROR, 0, _("%d block read errors not printed.\n"), block->read_errors); } } @@ -166,7 +177,7 @@ void empty_block(DEV_BLOCK *block) * in the buffer should have already been reserved by * init_block. */ -static void ser_block_header(DEV_BLOCK *block) +void ser_block_header(DEV_BLOCK *block) { ser_declare; uint32_t CheckSum = 0; @@ -221,13 +232,16 @@ static int unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) block->BlockVer = 1; block->bufp = block->buf + bhl; if (strncmp(Id, BLKHDR1_ID, BLKHDR_ID_LENGTH) != 0) { - Mmsg2(&dev->errmsg, _("Buffer ID error. Wanted: %s, got %s. Buffer discarded.\n"), + dev->dev_errno = EIO; + Mmsg2(&dev->errmsg, _("Volume data error! Wanted ID: %s, got %s. Buffer discarded.\n"), BLKHDR1_ID, Id); if (block->read_errors == 0 || verbose >= 2) { Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); } block->read_errors++; - return 0; + if (!forge_on) { + return 0; + } } } else if (Id[3] == '2') { unser_uint32(block->VolSessionId); @@ -236,32 +250,46 @@ static int unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) block->BlockVer = 2; block->bufp = block->buf + bhl; if (strncmp(Id, BLKHDR2_ID, BLKHDR_ID_LENGTH) != 0) { - Mmsg2(&dev->errmsg, _("Buffer ID error. Wanted: %s, got %s. Buffer discarded.\n"), + dev->dev_errno = EIO; + Mmsg2(&dev->errmsg, _("Volume data error! Wanted ID: %s, got %s. Buffer discarded.\n"), BLKHDR2_ID, Id); if (block->read_errors == 0 || verbose >= 2) { Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); } block->read_errors++; - return 0; + if (!forge_on) { + return 0; + } } } else { - Mmsg1(&dev->errmsg, _("Expected block-id BB01 or BB02, got %s. Buffer discarded.\n"), Id); + dev->dev_errno = EIO; + Mmsg1(&dev->errmsg, _("Volume data error! Wanted block-id BB02, got %s. Buffer discarded.\n"), Id); if (block->read_errors == 0 || verbose >= 2) { Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); } block->read_errors++; - return 0; + if (!forge_on) { + return 0; + } + unser_uint32(block->VolSessionId); + unser_uint32(block->VolSessionTime); + bhl = BLKHDR2_LENGTH; + block->BlockVer = 2; + block->bufp = block->buf + bhl; } /* Sanity check */ if (block_len > MAX_BLOCK_LENGTH) { - Mmsg1(&dev->errmsg, _("Block length %u is insane (too large), probably due to a bad archive.\n"), + dev->dev_errno = EIO; + Mmsg1(&dev->errmsg, _("Volume data error! Block length %u is insane (too large), probably due to a bad archive.\n"), block_len); if (block->read_errors == 0 || verbose >= 2) { Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); } block->read_errors++; - return 0; + if (!forge_on) { + return 0; + } } Dmsg1(190, "unser_block_header block_len=%d\n", block_len); @@ -280,13 +308,16 @@ static int unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) BlockCheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH, block_len-BLKHDR_CS_LENGTH); if (BlockCheckSum != CheckSum) { - Mmsg3(&dev->errmsg, _("Block checksum mismatch in block %u: calc=%x blk=%x\n"), + dev->dev_errno = EIO; + Mmsg3(&dev->errmsg, _("Volume data error! Block checksum mismatch in block %u: calc=%x blk=%x\n"), (unsigned)BlockNumber, BlockCheckSum, CheckSum); if (block->read_errors == 0 || verbose >= 2) { Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); } block->read_errors++; - return 0; + if (!forge_on) { + return 0; + } } } return 1; @@ -299,40 +330,55 @@ static int unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) * : 0 on failure * */ -int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) +int write_block_to_device(DCR *dcr, DEV_BLOCK *block) { int stat = 1; - lock_device(dev); + DEVICE *dev = dcr->dev; + JCR *jcr = dcr->jcr; + + + if (dcr->spooling) { + stat = write_block_to_spool_file(dcr, block); + return stat; + } + + if (!dcr->dev_locked) { + lock_device(dev); + } /* * If a new volume has been mounted since our last write * Create a JobMedia record for the previous volume written, * and set new parameters to write this volume - * The saem applies for if we are in a new file. + * The same applies for if we are in a new file. */ - if (jcr->NewVol || jcr->NewFile) { + if (dcr->NewVol || dcr->NewFile) { /* Create a jobmedia record for this job */ if (!dir_create_jobmedia_record(jcr)) { + dev->dev_errno = EIO; Jmsg(jcr, M_ERROR, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), jcr->VolCatInfo.VolCatName, jcr->Job); set_new_volume_parameters(jcr, dev); - unlock_device(dev); - return 0; + stat = 0; + goto bail_out; } - if (jcr->NewVol) { + if (dcr->NewVol) { /* Note, setting a new volume also handles any pending new file */ set_new_volume_parameters(jcr, dev); - jcr->NewFile = false; /* this handled for new file too */ + dcr->NewFile = false; /* this handled for new file too */ } else { set_new_file_parameters(jcr, dev); } } - if (!write_block_to_dev(jcr, dev, block)) { + if (!write_block_to_dev(dcr, block)) { stat = fixup_device_block_write_error(jcr, dev, block); } - unlock_device(dev); +bail_out: + if (!dcr->dev_locked) { + unlock_device(dev); + } return stat; } @@ -342,12 +388,14 @@ int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) * Returns: 1 on success or EOT * 0 on hard error */ -int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) +int write_block_to_dev(DCR *dcr, DEV_BLOCK *block) { ssize_t stat = 0; uint32_t wlen; /* length to write */ int hit_max1, hit_max2; bool ok; + DEVICE *dev = dcr->dev; + JCR *jcr = dcr->jcr; #ifdef NO_TAPE_WRITE_TEST empty_block(block); @@ -358,6 +406,7 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) /* dump_block(block, "before write"); */ if (dev->state & ST_WEOT) { Dmsg0(100, "return write_block_to_dev with ST_WEOT\n"); + dev->dev_errno = ENOSPC; Jmsg(jcr, M_FATAL, 0, _("Cannot write block. Device at EOM.\n")); return 0; } @@ -378,12 +427,15 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) /* Adjust write size to min/max for tapes only */ if (dev->state & ST_TAPE) { - if (wlen < dev->min_block_size) { - wlen = ((dev->min_block_size + TAPE_BSIZE - 1) / TAPE_BSIZE) * TAPE_BSIZE; - } /* check for fixed block size */ if (dev->min_block_size == dev->max_block_size) { wlen = block->buf_len; /* fixed block size already rounded */ + /* Check for min block size */ + } else if (wlen < dev->min_block_size) { + wlen = ((dev->min_block_size + TAPE_BSIZE - 1) / TAPE_BSIZE) * TAPE_BSIZE; + /* Ensure size is rounded */ + } else { + wlen = ((wlen + TAPE_BSIZE - 1) / TAPE_BSIZE) * TAPE_BSIZE; } } if (wlen-blen > 0) { @@ -408,7 +460,7 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) max_cap = dev->VolCatInfo.VolCatMaxBytes; } Jmsg(jcr, M_INFO, 0, _("User defined maximum volume capacity %s exceeded on device %s.\n"), - edit_uint64(max_cap, ed1), dev->dev_name); + edit_uint64_with_commas(max_cap, ed1), dev->dev_name); block->write_failed = true; if (weof_dev(dev, 1) != 0) { /* end tape */ Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); @@ -423,51 +475,55 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) dev->VolCatInfo.VolCatErrors++; } dev->state |= (ST_EOF | ST_EOT | ST_WEOT); + dev->dev_errno = ENOSPC; return 0; } /* Limit maximum File size on volume to user specified value */ - if (dev_state(dev, ST_TAPE)) { - if ((dev->max_file_size > 0) && - (dev->file_addr+block->binbuf) >= dev->max_file_size) { + if ((dev->max_file_size > 0) && + (dev->file_size+block->binbuf) >= dev->max_file_size) { + if (dev_state(dev, ST_TAPE) && weof_dev(dev, 1) != 0) { /* write eof */ /* Write EOF */ - if (weof_dev(dev, 1) != 0) { /* write eof */ - Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); - block->write_failed = true; - dev->VolCatInfo.VolCatErrors++; - dev->state |= (ST_EOF | ST_EOT | ST_WEOT); - Dmsg0(100, "dir_update_volume_info\n"); - dev->VolCatInfo.VolCatFiles = dev->file; - dir_update_volume_info(jcr, dev, 0); - return 0; - } - - /* Do bookkeeping to handle EOF just written */ + Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); + block->write_failed = true; + dev->VolCatInfo.VolCatErrors++; + dev->state |= (ST_EOF | ST_EOT | ST_WEOT); Dmsg0(100, "dir_update_volume_info\n"); dev->VolCatInfo.VolCatFiles = dev->file; dir_update_volume_info(jcr, dev, 0); - if (!dir_create_jobmedia_record(jcr)) { - Jmsg(jcr, M_ERROR, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), - jcr->VolCatInfo.VolCatName, jcr->Job); + dev->dev_errno = ENOSPC; + return 0; + } + + /* Create a JobMedia record so restore can seek */ + Dmsg0(100, "dir_update_volume_info\n"); + dev->VolCatInfo.VolCatFiles = dev->file; + dir_update_volume_info(jcr, dev, 0); + if (!dir_create_jobmedia_record(jcr)) { + dev->dev_errno = EIO; + Jmsg(jcr, M_ERROR, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), + dcr->VolCatInfo.VolCatName, jcr->Job); + if (!forge_on) { return 0; + } + } + dev->file_size = 0; /* reset file size */ + /* + * Walk through all attached jcrs indicating the file has changed + */ + Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName); + for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) { + if (mjcr->JobId == 0) { + continue; /* ignore console */ } - /* - * Walk through all attached jcrs indicating the file has changed - */ - Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName); - for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) { - if (mjcr->JobId == 0) { - continue; /* ignore console */ - } - mjcr->NewFile = true; /* set reminder to do set_new_file_params */ - } - set_new_file_parameters(jcr, dev); + mjcr->dcr->NewFile = true; /* set reminder to do set_new_file_params */ } + set_new_file_parameters(jcr, dev); } dev->VolCatInfo.VolCatWrites++; - Dmsg1(300, "Write block of %u bytes\n", wlen); + Dmsg1(200, "Write block of %u bytes\n", wlen); stat = write(dev->fd, block->buf, (size_t)wlen); if (stat != (ssize_t)wlen) { /* We should check for errno == ENOSPC, BUT many @@ -489,7 +545,7 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) if (dev->dev_errno == 0) { dev->dev_errno = ENOSPC; /* out of space */ } - Jmsg(jcr, M_ERROR, 0, _("Write error at %u:%u on device %s. ERR=%s.\n"), + Jmsg4(jcr, M_ERROR, 0, _("Write error at %u:%u on device %s. ERR=%s.\n"), dev->file, dev->block_num, dev->dev_name, strerror(dev->dev_errno)); } else { dev->dev_errno = ENOSPC; /* out of space */ @@ -574,7 +630,6 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) dev->VolCatInfo.VolCatBytes += block->binbuf; dev->VolCatInfo.VolCatBlocks++; - dev->file_addr += wlen; dev->EndBlock = dev->block_num; dev->EndFile = dev->file; dev->block_num++; @@ -582,19 +637,22 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) /* Update jcr values */ if (dev_state(dev, ST_TAPE)) { - jcr->EndBlock = dev->EndBlock; - jcr->EndFile = dev->EndFile; + dcr->EndBlock = dev->EndBlock; + dcr->EndFile = dev->EndFile; } else { - jcr->EndBlock = (uint32_t)dev->file_addr; - jcr->EndFile = (uint32_t)(dev->file_addr >> 32); + /* Save address of start of block just written */ + dcr->EndBlock = (uint32_t)dev->file_addr; + dcr->EndFile = (uint32_t)(dev->file_addr >> 32); } - if (jcr->VolFirstIndex == 0 && block->FirstIndex > 0) { - jcr->VolFirstIndex = block->FirstIndex; + if (dcr->VolFirstIndex == 0 && block->FirstIndex > 0) { + dcr->VolFirstIndex = block->FirstIndex; } if (block->LastIndex > 0) { - jcr->VolLastIndex = block->LastIndex; + dcr->VolLastIndex = block->LastIndex; } - jcr->WroteVol = true; + dcr->WroteVol = true; + dev->file_addr += wlen; /* update file address */ + dev->file_size += wlen; Dmsg2(190, "write_block: wrote block %d bytes=%d\n", dev->block_num, wlen); @@ -628,7 +686,11 @@ int read_block_from_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_bloc int looping; uint32_t BlockNumber; int retry; + DCR *dcr = jcr->dcr; + if (!dcr) { + Jmsg0(jcr, M_ABORT, 0, _("DCR is NULL!\n")); + } if (dev_state(dev, ST_EOT)) { return 0; } @@ -637,6 +699,7 @@ int read_block_from_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_bloc block->buf_len); reread: if (looping > 1) { + dev->dev_errno = EIO; Mmsg1(&dev->errmsg, _("Block buffer size looping problem on device %s\n"), dev->dev_name); Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); @@ -655,8 +718,8 @@ reread: Dmsg1(90, "Read device got: ERR=%s\n", strerror(errno)); clrerror_dev(dev, -1); block->read_len = 0; - Mmsg2(&dev->errmsg, _("Read error on device %s. ERR=%s.\n"), - dev->dev_name, strerror(dev->dev_errno)); + Mmsg4(&dev->errmsg, _("Read error at file:block %d:%d on device %s. ERR=%s.\n"), + dev->file, dev->block_num, dev->dev_name, strerror(dev->dev_errno)); Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); if (dev->state & ST_EOF) { /* EOF just seen? */ dev->state |= ST_EOT; /* yes, error => EOT */ @@ -680,7 +743,8 @@ reread: /* Continue here for successful read */ block->read_len = stat; /* save length read */ if (block->read_len < BLKHDR2_LENGTH) { - Mmsg2(&dev->errmsg, _("Very short block of %d bytes on device %s discarded.\n"), + dev->dev_errno = EIO; + Mmsg2(&dev->errmsg, _("Volume data error! Very short block of %d bytes on device %s discarded.\n"), block->read_len, dev->dev_name); Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); dev->state |= ST_SHORT; /* set short block */ @@ -700,6 +764,7 @@ reread: * and go re-read. */ if (block->block_len > block->buf_len) { + dev->dev_errno = EIO; Mmsg2(&dev->errmsg, _("Block length %u is greater than buffer %u. Attempting recovery.\n"), block->block_len, block->buf_len); Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); @@ -717,6 +782,7 @@ reread: off_t pos = lseek(dev->fd, (off_t)0, SEEK_CUR); /* get curr pos */ pos -= block->read_len; lseek(dev->fd, pos, SEEK_SET); + dev->file_addr = pos; } Mmsg1(&dev->errmsg, _("Setting block buffer size to %u bytes.\n"), block->block_len); Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg); @@ -732,7 +798,8 @@ reread: } if (block->block_len > block->read_len) { - Mmsg3(&dev->errmsg, _("Short block at %u of %d bytes on device %s discarded.\n"), + dev->dev_errno = EIO; + Mmsg3(&dev->errmsg, _("Volume data error! Short block at %u of %d bytes on device %s discarded.\n"), dev->block_num, block->read_len, dev->dev_name); Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); dev->state |= ST_SHORT; /* set short block */ @@ -746,19 +813,22 @@ reread: dev->VolCatInfo.VolCatBytes += block->block_len; dev->VolCatInfo.VolCatBlocks++; - dev->file_addr += block->block_len; dev->EndBlock = dev->block_num; dev->EndFile = dev->file; dev->block_num++; /* Update jcr values */ if (dev->state & ST_TAPE) { - jcr->EndBlock = dev->EndBlock; - jcr->EndFile = dev->EndFile; + dcr->EndBlock = dev->EndBlock; + dcr->EndFile = dev->EndFile; } else { - jcr->EndBlock = (uint32_t)dev->file_addr; - jcr->EndFile = (uint32_t)(dev->file_addr >> 32); + dcr->EndBlock = (uint32_t)dev->file_addr; + dcr->EndFile = (uint32_t)(dev->file_addr >> 32); + dev->block_num = dcr->EndBlock; + dev->file = dcr->EndFile; } + dev->file_addr += block->block_len; + dev->file_size += block->block_len; /* * If we read a short block on disk, @@ -780,6 +850,7 @@ reread: lseek(dev->fd, pos, SEEK_SET); Dmsg2(100, "Did lseek blk_size=%d rdlen=%d\n", block->block_len, block->read_len); + dev->file_addr = pos; } Dmsg2(200, "Exit read_block read_len=%d block_len=%d\n", block->read_len, block->block_len);