From 92ef14aeaed5e593a12b395c2bc7dc6d65a8c937 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Wed, 8 Oct 2003 15:22:42 +0000 Subject: [PATCH] Fixing and optimization of tape positioning for restores git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@736 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/kernstodo | 6 +- bacula/src/dird/bsr.c | 34 +++++++--- bacula/src/dird/catreq.c | 3 +- bacula/src/dird/next_vol.c | 8 +-- bacula/src/dird/ua_cmds.c | 4 +- bacula/src/dird/ua_restore.c | 4 +- bacula/src/dird/ua_select.c | 2 +- bacula/src/stored/match_bsr.c | 69 +++++++++++++++++--- bacula/src/stored/protos.h | 1 + bacula/src/stored/read_record.c | 112 ++++++++++++++++++++------------ bacula/src/stored/record.h | 2 + 11 files changed, 173 insertions(+), 72 deletions(-) diff --git a/bacula/kernstodo b/bacula/kernstodo index 945e2fb50a..c21fbecea0 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -35,6 +35,11 @@ For 1.33 Testing/Documentation: SuSE. For 1.33 +- I want to restore by file to some date. +- Implement fast block rejection. +- Is it really important to make Job name the same to find the + Full backup to avoid promoting an Incremental job? +- Start label, then run job when tape labeled, it should broadcast. - Implement a RunAfterFailedJob - Zap illegal characters in job name for mail files (e.g. /). - From Lars Köllers: @@ -1036,4 +1041,3 @@ Done: (see kernsdone for more) job. Use find_job_pool() modified in ua_output.c - Test connect timeouts. - Fix FreeBSD build with tcp_wrapper -- should not have -lnsl - diff --git a/bacula/src/dird/bsr.c b/bacula/src/dird/bsr.c index 2a362192c1..24b30db695 100644 --- a/bacula/src/dird/bsr.c +++ b/bacula/src/dird/bsr.c @@ -67,9 +67,10 @@ static void free_findex(RBSR_FINDEX *fi) * We are called here once for each JobMedia record * for each Volume. */ -static void write_findex(UAContext *ua, RBSR_FINDEX *fi, +static uint32_t write_findex(UAContext *ua, RBSR_FINDEX *fi, int32_t FirstIndex, int32_t LastIndex, FILE *fd) { + uint32_t count = 0; for ( ; fi; fi=fi->next) { int32_t findex, findex2; if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) || @@ -79,11 +80,14 @@ static void write_findex(UAContext *ua, RBSR_FINDEX *fi, findex2 = fi->findex2 > LastIndex ? LastIndex : fi->findex2; if (findex == findex2) { fprintf(fd, "FileIndex=%d\n", findex); + count++; } else { fprintf(fd, "FileIndex=%d-%d\n", findex, findex2); + count += findex2 - findex + 1; } } } + return count; } /* @@ -133,10 +137,10 @@ void free_bsr(RBSR *bsr) { if (bsr) { free_findex(bsr->fi); - free_bsr(bsr->next); if (bsr->VolParams) { free(bsr->VolParams); } + free_bsr(bsr->next); free(bsr); } } @@ -219,6 +223,7 @@ int write_bsr_file(UAContext *ua, RBSR *bsr) static void write_bsr(UAContext *ua, RBSR *bsr, FILE *fd) { if (bsr) { + uint32_t count; /* * For a given volume, loop over all the JobMedia records. * VolCount is the number of JobMedia records. @@ -232,15 +237,26 @@ static void write_bsr(UAContext *ua, RBSR *bsr, FILE *fd) fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName); fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId); fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime); - fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile, - bsr->VolParams[i].EndFile); - fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock, - bsr->VolParams[i].EndBlock); - + if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) { + fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile); + } else { + fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile, + bsr->VolParams[i].EndFile); + } + if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) { + fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartBlock); + } else { + fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock, + bsr->VolParams[i].EndBlock); + } // Dmsg2(000, "bsr VolParam FI=%u LI=%u\n", // bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex); - write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex, - bsr->VolParams[i].LastIndex, fd); + + count = write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex, + bsr->VolParams[i].LastIndex, fd); + if (count) { + fprintf(fd, "Count=%u\n", count); + } } write_bsr(ua, bsr->next, fd); } diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c index 05f7f1e884..457cc402b1 100644 --- a/bacula/src/dird/catreq.c +++ b/bacula/src/dird/catreq.c @@ -164,7 +164,8 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) Dmsg2(100, "Vol Info for %s: %s", jcr->Job, bs->msg); } else { /* Not suitable volume */ - bnet_fsend(bs, "1998 Volume \"%s\" %s.\n", mr.VolumeName, reason); + bnet_fsend(bs, "1998 Volume \"%s\" status is %s, %s.\n", mr.VolumeName, + mr.VolStatus, reason); } } else { diff --git a/bacula/src/dird/next_vol.c b/bacula/src/dird/next_vol.c index 043fd1ac93..ddb4e125b7 100644 --- a/bacula/src/dird/next_vol.c +++ b/bacula/src/dird/next_vol.c @@ -207,13 +207,13 @@ bool is_volume_valid_or_recyclable(JCR *jcr, MEDIA_DBR *mr, char **reason) return true; } else { /* In principle this shouldn't happen */ - *reason = "recycling of current volume failed"; + *reason = "and recycling of current volume failed"; return false; } } /* At this point, the volume is not valid for writing */ - *reason = "not Append, Purged or Recycle"; + *reason = "but should be Append, Purged or Recycle"; /* * What we're trying to do here is see if the current volume is @@ -241,11 +241,11 @@ bool is_volume_valid_or_recyclable(JCR *jcr, MEDIA_DBR *mr, char **reason) Jmsg(jcr, M_INFO, 0, "Recycled current volume \"%s\"\n", mr->VolumeName); return true; /* Good volume */ } else { - *reason = "not Append, Purged or Recycle (recycling of the " + *reason = "but should be Append, Purged or Recycle (recycling of the " "current volume failed)"; } } else { - *reason = "not Append, Purged or Recycle (cannot automatically " + *reason = "but should be Append, Purged or Recycle (cannot automatically " "recycle current volume, as it still contains unpruned data)"; } } diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 7acb0d1216..2aa5729bb7 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -54,7 +54,7 @@ extern int runcmd(UAContext *ua, char *cmd); extern int retentioncmd(UAContext *ua, char *cmd); extern int prunecmd(UAContext *ua, char *cmd); extern int purgecmd(UAContext *ua, char *cmd); -extern int restorecmd(UAContext *ua, char *cmd); +extern int restore_cmd(UAContext *ua, char *cmd); extern int label_cmd(UAContext *ua, char *cmd); extern int relabel_cmd(UAContext *ua, char *cmd); extern int update_slots(UAContext *ua); /* ua_label.c */ @@ -105,7 +105,7 @@ static struct cmdstruct commands[] = { { N_("quit"), quit_cmd, _("quit")}, { N_("relabel"), relabel_cmd, _("relabel a tape")}, { N_("release"), release_cmd, _("release ")}, - { N_("restore"), restorecmd, _("restore files")}, + { N_("restore"), restore_cmd, _("restore files")}, { N_("run"), runcmd, _("run ")}, { N_("setdebug"), setdebug_cmd, _("sets debug level")}, { N_("show"), show_cmd, _("show (resource records) [jobs | pools | ... | all]")}, diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index 88e40b4d27..0ca2ab0da9 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -109,7 +109,7 @@ static int get_client_name(UAContext *ua, RESTORE_CTX *rx); * Restore files * */ -int restorecmd(UAContext *ua, char *cmd) +int restore_cmd(UAContext *ua, char *cmd) { RESTORE_CTX rx; /* restore context */ JOB *job = NULL; @@ -223,6 +223,7 @@ int restorecmd(UAContext *ua, char *cmd) static void free_rx(RESTORE_CTX *rx) { free_bsr(rx->bsr); + rx->bsr = NULL; if (rx->JobIds) { free_pool_memory(rx->JobIds); rx->JobIds = NULL; @@ -895,6 +896,7 @@ static void free_name_list(NAME_LIST *name_list) } if (name_list->name) { free(name_list->name); + name_list->name = NULL; } name_list->max_ids = 0; name_list->num_ids = 0; diff --git a/bacula/src/dird/ua_select.c b/bacula/src/dird/ua_select.c index f3afec0d05..4a32478317 100644 --- a/bacula/src/dird/ua_select.c +++ b/bacula/src/dird/ua_select.c @@ -341,7 +341,7 @@ int select_client_dbr(UAContext *ua, CLIENT_DBR *cr) return 0; } if (num_clients <= 0) { - bsendmsg(ua, _("No clients defined. Run a job to create one.\n")); + bsendmsg(ua, _("No clients defined. You must run a job before using this command.\n")); return 0; } diff --git a/bacula/src/stored/match_bsr.c b/bacula/src/stored/match_bsr.c index 2208038885..1aaef0e755 100755 --- a/bacula/src/stored/match_bsr.c +++ b/bacula/src/stored/match_bsr.c @@ -157,10 +157,10 @@ BSR *find_next_bsr(BSR *root_bsr, DEVICE *dev) if (!root_bsr || !root_bsr->use_positioning || !root_bsr->reposition || !dev_is_tape(dev)) { - Dmsg2(100, "use_pos=%d repos=%d\n", root_bsr->use_positioning, - root_bsr->reposition); + Dmsg2(100, "No nxt_bsr use_pos=%d repos=%d\n", root_bsr->use_positioning, root_bsr->reposition); return NULL; } + Dmsg2(100, "use_pos=%d repos=%d\n", root_bsr->use_positioning, root_bsr->reposition); root_bsr->mount_next_volume = false; for (bsr=root_bsr; bsr; bsr=bsr->next) { if (bsr->done || !match_volume(bsr, bsr->volume, &dev->VolHdr, 1)) { @@ -231,6 +231,34 @@ static BSR *find_smallest_volfile(BSR *found_bsr, BSR *bsr) return return_bsr; } +/* + * Called to tell the matcher that the end of + * the current file has been reached. + * The bsr argument is not used, but is included + * for consistency with the other match calls. + * + * Returns: true if we should reposition + * : false otherwise. + */ +bool match_set_eof(BSR *bsr, DEV_RECORD *rec) +{ + BSR *rbsr = rec->bsr; + Dmsg1(100, "match_set %d\n", rbsr != NULL); + if (!rbsr) { + return false; + } + rec->bsr = NULL; + rbsr->found++; + if (rbsr->count && rbsr->found >= rbsr->count) { + rbsr->done = true; + rbsr->root->reposition = true; + Dmsg2(100, "match_set_eof reposition count=%d found=%d\n", + rbsr->count, rbsr->found); + return true; + } + return false; +} + /* * Match all the components of current record * returns 1 on match @@ -243,33 +271,54 @@ static int match_all(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, if (bsr->done) { goto no_match; } - if (bsr->count && bsr->found >= bsr->count) { - bsr->done = true; - bsr->root->reposition = true; - Dmsg0(100, "bsr done from count\n"); - goto no_match; - } if (!match_volume(bsr, bsr->volume, volrec, 1)) { goto no_match; } if (!match_volfile(bsr, bsr->volfile, rec, 1)) { + Dmsg2(100, "Fail on file. bsr=%d rec=%d\n", bsr->volfile->efile, + rec->File); goto no_match; } if (!match_sesstime(bsr, bsr->sesstime, rec, 1)) { + Dmsg2(100, "Fail on sesstime. bsr=%d rec=%d\n", + bsr->sesstime->sesstime, rec->VolSessionTime); goto no_match; } /* NOTE!! This test MUST come after the sesstime test */ if (!match_sessid(bsr, bsr->sessid, rec)) { + Dmsg2(100, "Fail on sessid. bsr=%d rec=%d\n", + bsr->sessid->sessid, rec->VolSessionId); goto no_match; } /* NOTE!! This test MUST come after sesstime and sessid tests */ if (!match_findex(bsr, bsr->FileIndex, rec, 1)) { + Dmsg2(100, "Fail on findex. bsr=%d rec=%d\n", + bsr->FileIndex->findex2, rec->FileIndex); goto no_match; } + /* + * If a count was specified and we have a FileIndex, assume + * it is a Bacula created bsr (or the equivalent). We + * then save the bsr where the match occurred so that + * after processing the record or records, we can update + * the found count. I.e. rec->bsr points to the bsr that + * satisfied the match. + */ + if (bsr->count && bsr->FileIndex) { + rec->bsr = bsr; + return 1; /* this is a complete match */ + } + + /* + * The selections below are not used by Bacula's + * restore command, and don't work because of + * the rec->bsr = bsr optimization above. + */ if (!match_jobid(bsr, bsr->JobId, sessrec, 1)) { goto no_match; + } if (!match_job(bsr, bsr->job, sessrec, 1)) { goto no_match; @@ -286,7 +335,6 @@ static int match_all(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, if (!match_stream(bsr, bsr->stream, rec, 1)) { goto no_match; } - bsr->found++; return 1; no_match: @@ -409,7 +457,8 @@ static int match_volfile(BSR *bsr, BSR_VOLFILE *volfile, DEV_RECORD *rec, bool d if (volfile->done && done) { bsr->done = true; bsr->root->reposition = true; - Dmsg0(100, "bsr done from volfile\n"); + Dmsg2(100, "bsr done from volfile rec=%d volefile=%d\n", + rec->File, volfile->efile); } return 0; } diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 8ad2262660..228cc20151 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -155,6 +155,7 @@ int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, int match_bsr_block(BSR *bsr, DEV_BLOCK *block); void position_bsr_block(BSR *bsr, DEV_BLOCK *block); BSR *find_next_bsr(BSR *root_bsr, DEVICE *dev); +bool match_set_eof(BSR *bsr, DEV_RECORD *rec); /* From mount.c */ int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release); diff --git a/bacula/src/stored/read_record.c b/bacula/src/stored/read_record.c index de2b17f204..9528a920db 100644 --- a/bacula/src/stored/read_record.c +++ b/bacula/src/stored/read_record.c @@ -33,8 +33,10 @@ #include "bacula.h" #include "stored.h" +/* Forward referenced functions */ static void handle_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec); static BSR *position_to_first_file(JCR *jcr, DEVICE *dev); +static int try_repositioning(JCR *jcr, DEV_RECORD *rec, DEVICE *dev); #ifdef DEBUG static char *rec_state_to_str(DEV_RECORD *rec); #endif @@ -99,6 +101,8 @@ int read_records(JCR *jcr, DEVICE *dev, Jmsg(jcr, M_INFO, 0, "Got EOF at file %u on device %s, Volume \"%s\"\n", dev->file, dev_name(dev), jcr->VolumeName); } + Dmsg3(100, "Got EOF at file %u on device %s, Volume \"%s\"\n", + dev->file, dev_name(dev), jcr->VolumeName); continue; } else if (dev_state(dev, ST_SHORT)) { Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); @@ -111,12 +115,13 @@ int read_records(JCR *jcr, DEVICE *dev, } } Dmsg2(100, "New block at position=(file:block) %d:%d\n", dev->file, dev->block_num); - Dmsg5(100, "Read block: devblk=%d blk=%d VI=%u VT=%u blen=%d\n", dev->block_num, block->BlockNumber, - block->VolSessionId, block->VolSessionTime, block->block_len); #ifdef FAST_BLOCK_REJECTION /* this does not stop when file/block are too big */ if (!match_bsr_block(jcr->bsr, block)) { - continue; + if (try_repositioning(jcr, rec, dev)) { + break; /* get next volume */ + } + continue; /* skip this record */ } #endif @@ -148,13 +153,15 @@ int read_records(JCR *jcr, DEVICE *dev, Dmsg3(100, "After mount next vol. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), block->BlockNumber, rec->remainder); record = 0; + rec->state = 0; + Dmsg1(100, "Block empty %d\n", is_block_empty(rec)); for (rec->state=0; !is_block_empty(rec); ) { if (!read_record_from_block(block, rec)) { - Dmsg3(10, "!read-break. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec), + Dmsg3(00, "!read-break. state=%s blk=%d rem=%d\n", rec_state_to_str(rec), block->BlockNumber, rec->remainder); break; } - Dmsg5(100, "read-OK. stat=%s blk=%d rem=%d file:block=%d:%d\n", + Dmsg5(100, "read-OK. state=%s blk=%d rem=%d file:block=%d:%d\n", rec_state_to_str(rec), block->BlockNumber, rec->remainder, dev->file, dev->block_num); /* @@ -167,10 +174,6 @@ int read_records(JCR *jcr, DEVICE *dev, Dmsg6(100, "recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record, rec_state_to_str(rec), block->BlockNumber, rec->VolSessionId, rec->VolSessionTime, rec->FileIndex); - Dmsg4(30, "VolSId=%ld FI=%s Strm=%s Size=%ld\n", rec->VolSessionId, - FI_to_ascii(rec->FileIndex), - stream_to_ascii(rec->Stream, rec->FileIndex), - rec->data_len); if (rec->FileIndex == EOM_LABEL) { /* end of tape? */ Dmsg0(40, "Get EOM LABEL\n"); @@ -200,47 +203,37 @@ int read_records(JCR *jcr, DEVICE *dev, Dmsg2(100, "All done=(file:block) %d:%d\n", dev->file, dev->block_num); break; } else if (stat == 0) { /* no match */ - BSR *bsr; - bsr = find_next_bsr(jcr->bsr, dev); - if (bsr == NULL && jcr->bsr->mount_next_volume) { - Dmsg0(100, "Would mount next volume here\n"); - Dmsg2(100, "Current postion (file:block) %d:%d\n", - dev->file, dev->block_num); - jcr->bsr->mount_next_volume = false; - dev->state |= ST_EOT; - rec->Block = 0; + Dmsg4(100, "Clear rem=%d FI=%d before set_eof pos %d:%d\n", + rec->remainder, rec->FileIndex, dev->file, dev->block_num); + rec->remainder = 0; + rec->state &= ~REC_PARTIAL_RECORD; + if (try_repositioning(jcr, rec, dev)) { break; - } - if (bsr) { - Dmsg4(100, "Reposition from (file:block) %d:%d to %d:%d\n", - dev->file, dev->block_num, bsr->volfile->sfile, - bsr->volblock->sblock); - if (verbose) { - Jmsg(jcr, M_INFO, 0, "Reposition from (file:block) %d:%d to %d:%d\n", - dev->file, dev->block_num, bsr->volfile->sfile, - bsr->volblock->sblock); - } - reposition_dev(dev, bsr->volfile->sfile, bsr->volblock->sblock); - rec->Block = 0; - Dmsg2(100, "Now at (file:block) %d:%d\n", - dev->file, dev->block_num); } - Dmsg5(100, "BSR no match rec=%d block=%d SessId=%d SessTime=%d FI=%d\n", - record, block->BlockNumber, rec->VolSessionId, rec->VolSessionTime, - rec->FileIndex); continue; /* we don't want record, read next one */ } } if (is_partial_record(rec)) { - Dmsg6(10, "Partial, break. recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record, + Dmsg6(100, "Partial, break. recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record, rec_state_to_str(rec), block->BlockNumber, rec->VolSessionId, rec->VolSessionTime, rec->FileIndex); break; /* read second part of record */ } ok = record_cb(jcr, dev, block, rec); + if (rec->Stream == STREAM_MD5_SIGNATURE || rec->Stream == STREAM_SHA1_SIGNATURE) { + Dmsg3(100, "Done FI=%d before set_eof pos %d:%d\n", rec->FileIndex, + dev->file, dev->block_num); + if (match_set_eof(jcr->bsr, rec) && try_repositioning(jcr, rec, dev)) { + Dmsg2(100, "Break after match_set_eof pos %d:%d\n", + dev->file, dev->block_num); + break; + } + Dmsg2(100, "After set_eof pos %d:%d\n", dev->file, dev->block_num); + } } /* end for loop over records */ + Dmsg2(100, "After end records position=(file:block) %d:%d\n", dev->file, dev->block_num); } /* end for loop over blocks */ - Dmsg2(100, "Position=(file:block) %d:%d\n", dev->file, dev->block_num); +// Dmsg2(100, "Position=(file:block) %d:%d\n", dev->file, dev->block_num); /* Walk down list and free all remaining allocated recs */ for (rec=(DEV_RECORD *)recs->first(); rec; ) { @@ -255,6 +248,42 @@ int read_records(JCR *jcr, DEVICE *dev, return ok; } +/* + * See if we can reposition. + * Returns: 1 if at end of volume + * 0 otherwise + */ +static int try_repositioning(JCR *jcr, DEV_RECORD *rec, DEVICE *dev) +{ + BSR *bsr; + bsr = find_next_bsr(jcr->bsr, dev); + if (bsr == NULL && jcr->bsr->mount_next_volume) { + Dmsg0(100, "Would mount next volume here\n"); + Dmsg2(100, "Current postion (file:block) %d:%d\n", + dev->file, dev->block_num); + jcr->bsr->mount_next_volume = false; + dev->state |= ST_EOT; + rec->Block = 0; + return 1; + } + if (bsr) { + if (verbose > 1) { + Jmsg(jcr, M_INFO, 0, "Reposition from (file:block) %d:%d to %d:%d\n", + dev->file, dev->block_num, bsr->volfile->sfile, + bsr->volblock->sblock); + } + Dmsg4(100, "Try_Reposition from (file:block) %d:%d to %d:%d\n", + dev->file, dev->block_num, bsr->volfile->sfile, + bsr->volblock->sblock); + reposition_dev(dev, bsr->volfile->sfile, bsr->volblock->sblock); + rec->Block = 0; + } + return 0; +} + +/* + * Position to the first file on this volume + */ static BSR *position_to_first_file(JCR *jcr, DEVICE *dev) { BSR *bsr = NULL; @@ -265,15 +294,12 @@ static BSR *position_to_first_file(JCR *jcr, DEVICE *dev) if (jcr->bsr) { jcr->bsr->reposition = true; /* force repositioning */ bsr = find_next_bsr(jcr->bsr, dev); - if (bsr) { + if (bsr && (bsr->volfile->sfile != 0 || bsr->volblock->sblock != 0)) { Jmsg(jcr, M_INFO, 0, _("Forward spacing to file:block %u:%u.\n"), bsr->volfile->sfile, bsr->volblock->sblock); - Dmsg4(100, "Reposition new from (file:block) %d:%d to %d:%d\n", - dev->file, dev->block_num, bsr->volfile->sfile, - bsr->volblock->sblock); + Dmsg2(100, "Forward spacing to file:block %u:%u.\n", + bsr->volfile->sfile, bsr->volblock->sblock); reposition_dev(dev, bsr->volfile->sfile, bsr->volblock->sblock); - Dmsg2(100, "Now at (file:block) %d:%d\n", - dev->file, dev->block_num); } } return bsr; diff --git a/bacula/src/stored/record.h b/bacula/src/stored/record.h index f00207547e..dd3047d478 100644 --- a/bacula/src/stored/record.h +++ b/bacula/src/stored/record.h @@ -77,6 +77,7 @@ * * This is the memory structure for the record header. */ +struct BSR; /* satisfy forward reference */ struct DEV_RECORD { dlink link; /* link for chaining in read_record.c */ /* File and Block are always returned during reading @@ -91,6 +92,7 @@ struct DEV_RECORD { uint32_t data_len; /* current record length */ uint32_t remainder; /* remaining bytes to read/write */ uint32_t state; /* state bits */ + BSR *bsr; /* pointer to bsr that matched */ uint8_t ser_buf[WRITE_RECHDR_LENGTH]; /* serialized record header goes here */ POOLMEM *data; /* Record data. This MUST be a memory pool item */ }; -- 2.39.5