From b3e8c5aea0913b61f73b1c0b02d8d6d755e337d7 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Thu, 18 Sep 2003 12:20:21 +0000 Subject: [PATCH] Massive cleanup of recycling code git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@706 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/ReleaseNotes | 2 + bacula/kernstodo | 8 +- bacula/src/dird/catreq.c | 133 ++++++++------------------------ bacula/src/dird/job.c | 1 + bacula/src/dird/next_vol.c | 149 +++++++++++++++++++++++++++++++++--- bacula/src/dird/protos.h | 2 + bacula/src/dird/recycle.c | 2 +- bacula/src/dird/ua_cmds.c | 6 +- bacula/src/lib/watchdog.c | 2 - bacula/src/stored/acquire.c | 33 +++++--- bacula/src/stored/dircmd.c | 8 +- bacula/src/stored/job.c | 2 +- bacula/src/stored/mount.c | 41 ++++++---- bacula/src/version.h | 4 +- 14 files changed, 239 insertions(+), 154 deletions(-) diff --git a/bacula/ReleaseNotes b/bacula/ReleaseNotes index c12647cb8c..06950566b7 100644 --- a/bacula/ReleaseNotes +++ b/bacula/ReleaseNotes @@ -15,6 +15,8 @@ Major Changes this Release: - Implemented Include | and < in File daemon. - Implemented a new Include/Exclude syntax. - Lots of fixes with variable expansion and counter variables +- Automatic labeling of tape Volumes is fixed. +- Recycling has been completely restructured and should work. Other Changes this Release: diff --git a/bacula/kernstodo b/bacula/kernstodo index 47d11af8bf..e7acbe60c1 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -1,5 +1,5 @@ Kern's ToDo List - 16 September 2003 + 18 September 2003 Documentation to do: (any release a little bit at a time) - Document running a test version. @@ -32,15 +32,16 @@ For 1.32 Testing/Documentation: - Add test of exclusion, test multiple Include {} statements. For 1.32: +- Add multiple character duration qualifiers. - Enhance "update slots" to include a "scan" feature scan 1; scan 1-5; scan 1,2,4 ... to update the catalog - Allow a slot or range of slots on the label barcodes command. - Don't print "Warning: Wrong Volume mounted ..." if mounting second volume. - - For 1.33 +- Do a complete audit of all pthreads_mutex, cond, ... to ensure that + any that are dynamically initialized are destroyed when no longer used. - Write a mini-readline with history and editing. - Look at how fuser works and /proc/PID/fd that is how Nic found the file descriptor leak in Bacula. @@ -919,4 +920,5 @@ Done: (see kernsdone for more) a block and a record. - LabelFormat on tape volume apparently creates the db record but never actually labels the volume. +- Recycling a volume when two jobs are using it is going to break. Fixed. diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c index 4fd0e049a8..05f7f1e884 100644 --- a/bacula/src/dird/catreq.c +++ b/bacula/src/dird/catreq.c @@ -82,7 +82,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) */ Dmsg1(200, "catreq %s", bs->msg); if (sscanf(bs->msg, Find_media, &Job, &index) == 2) { - ok = find_next_volume_for_append(jcr, &mr, TRUE /*create*/); + ok = find_next_volume_for_append(jcr, &mr, TRUE /*permit create new vol*/); /* * Send Find Media response to Storage daemon */ @@ -112,14 +112,16 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) */ unbash_spaces(mr.VolumeName); if (db_get_media_record(jcr, jcr->db, &mr)) { - bool VolSuitable = false; - char *reason = ""; /* detailed reason for rejection */ + char *reason = NULL; /* detailed reason for rejection */ jcr->MediaId = mr.MediaId; Dmsg1(120, "VolumeInfo MediaId=%d\n", jcr->MediaId); pm_strcpy(&jcr->VolumeName, mr.VolumeName); - if (!writing) { - VolSuitable = true; /* accept anything for read */ - } else { + /* + * If we are reading, accept any volume (reason == NULL) + * If we are writing, check if the Volume is valid + * for this job, and do a recycle if necessary + */ + if (writing) { /* * SD wants to write this Volume, so make * sure it is suitable for this job, i.e. @@ -128,63 +130,26 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) */ if (mr.PoolId != jcr->PoolId) { reason = "not in Pool"; - } else if (strcmp(mr.VolStatus, "Append") != 0 && - strcmp(mr.VolStatus, "Recycle") != 0 && - strcmp(mr.VolStatus, "Purged") != 0) { - reason = "not Append, Purged or Recycle"; - /* What we're trying to do here is see if the current volume is - * "recycleable" - ie. if we prune all expired jobs off it, is - * it now possible to reuse it for the job that it is currently - * needed for? - */ - if ((mr.LastWritten + mr.VolRetention) < (utime_t)time(NULL) - && mr.Recycle && jcr->pool->recycle_current_volume - && (strcmp(mr.VolStatus, "Full") == 0 || - strcmp(mr.VolStatus, "Used") == 0)) { - /* - * Attempt prune of current volume to see if we can - * recycle it for use. - */ - UAContext *ua; - - ua = new_ua_context(jcr); - ok = prune_volume(ua, &mr); - free_ua_context(ua); - - if (ok) { - /* If fully purged, recycle current volume */ - if (recycle_volume(jcr, &mr)) { - Jmsg(jcr, M_INFO, 0, "Recycled current " - "volume \"%s\"\n", mr.VolumeName); - VolSuitable = true; - } else { - reason = "not Append, Purged or Recycle (recycling of the " - "current volume failed)"; - } - } else { - reason = "not Append, Purged or Recycle (cannot automatically " - "recycle current volume, as it still contains " - "unpruned data)"; - } - } } else if (strcmp(mr.MediaType, jcr->store->media_type) != 0) { reason = "not correct MediaType"; - } else if (!jcr->pool->accept_any_volume) { - reason = "Volume not in sequence"; - } else if (strcmp(mr.VolStatus, "Purged") == 0) { - if (recycle_volume(jcr, &mr)) { - Jmsg(jcr, M_INFO, 0, "Recycled current " - "volume \"%s\"\n", mr.VolumeName); - VolSuitable = true; - } else { - /* In principle this shouldn't happen */ - reason = "recycling of current volume failed"; - } } else { - VolSuitable = true; + /* + * ****FIXME*** + * This test (accept_any_volume) is turned off + * because it doesn't properly check if the volume + * really is out of sequence! + * + * } else if (!jcr->pool->accept_any_volume) { + * reason = "Volume not in sequence"; + */ + + /* + * Now try recycling if necessary + */ + is_volume_valid_or_recyclable(jcr, &mr, &reason); } } - if (VolSuitable) { + if (reason == NULL) { char ed1[50], ed2[50], ed3[50]; /* * Send Find Media response to Storage daemon @@ -199,8 +164,7 @@ 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\" %s.\n", mr.VolumeName, reason); } } else { @@ -210,7 +174,8 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) /* * Request to update Media record. Comes typically at the end - * of a Storage daemon Job Session + * of a Storage daemon Job Session or when labeling/relabeling a + * Volume. */ } else if (sscanf(bs->msg, Update_media, &Job, &sdmr.VolumeName, &sdmr.VolJobs, &sdmr.VolFiles, &sdmr.VolBlocks, &sdmr.VolBytes, &sdmr.VolMounts, &sdmr.VolErrors, @@ -252,47 +217,17 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) mr.Slot = sdmr.Slot; /* - * Update Media Record + * Apply expiration periods and limits, if not a label request, + * and ignore status because if !label we won't use it. */ - - /* Check limits and expirations if "Append" and not a lable request */ - if (strcmp(mr.VolStatus, "Append") == 0 && !label) { - /* First handle Max Volume Bytes */ - if ((mr.MaxVolBytes > 0 && mr.VolBytes >= mr.MaxVolBytes)) { - Jmsg(jcr, M_INFO, 0, _("Max Volume bytes exceeded. " - "Marking Volume \"%s\" as Full.\n"), mr.VolumeName); - strcpy(mr.VolStatus, "Full"); - - /* Now see if Volume should only be used once */ - } else if (mr.VolBytes > 0 && jcr->pool->use_volume_once) { - Jmsg(jcr, M_INFO, 0, _("Volume used once. " - "Marking Volume \"%s\" as Used.\n"), mr.VolumeName); - strcpy(mr.VolStatus, "Used"); - - /* Now see if Max Jobs written to volume */ - } else if (mr.MaxVolJobs > 0 && mr.MaxVolJobs <= mr.VolJobs) { - Jmsg(jcr, M_INFO, 0, _("Max Volume jobs exceeded. " - "Marking Volume \"%s\" as Used.\n"), mr.VolumeName); - strcpy(mr.VolStatus, "Used"); - - /* Now see if Max Files written to volume */ - } else if (mr.MaxVolFiles > 0 && mr.MaxVolFiles <= mr.VolFiles) { - Jmsg(jcr, M_INFO, 0, _("Max Volume files exceeded. " - "Marking Volume \"%s\" as Used.\n"), mr.VolumeName); - strcpy(mr.VolStatus, "Used"); - - /* Finally, check Use duration expiration */ - } else if (mr.VolUseDuration > 0) { - utime_t now = time(NULL); - /* See if Vol Use has expired */ - if (mr.VolUseDuration <= (now - mr.FirstWritten)) { - Jmsg(jcr, M_INFO, 0, _("Max configured use duration exceeded. " - "Marking Volume \"%s\"as Used.\n"), mr.VolumeName); - strcpy(mr.VolStatus, "Used"); /* yes, mark as used */ - } - } + if (!label) { + has_volume_expired(jcr, &mr); } + Dmsg2(200, "db_update_media_record. Stat=%s Vol=%s\n", mr.VolStatus, mr.VolumeName); + /* + * Write the modified record to the DB + */ if (db_update_media_record(jcr, jcr->db, &mr)) { bnet_fsend(bs, OK_update); Dmsg0(190, "send OK\n"); diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index 2878a9e634..1827194306 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -381,6 +381,7 @@ void dird_free_jcr(JCR *jcr) free_pool_memory(jcr->client_uname); jcr->client_uname = NULL; } + pthread_cond_destroy(&jcr->term_wait); Dmsg0(200, "End dird free_jcr\n"); } diff --git a/bacula/src/dird/next_vol.c b/bacula/src/dird/next_vol.c index d16f042fb4..043fd1ac93 100644 --- a/bacula/src/dird/next_vol.c +++ b/bacula/src/dird/next_vol.c @@ -96,19 +96,11 @@ int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int create) } } } - /* Check if use duration applies, then if it has expired */ Dmsg2(100, "VolJobs=%d FirstWritten=%d\n", mr->VolJobs, mr->FirstWritten); - if (ok && mr->VolJobs > 0 && mr->VolUseDuration > 0 && - strcmp(mr->VolStatus, "Append") == 0) { - utime_t now = time(NULL); - if (mr->VolUseDuration <= (now - mr->FirstWritten)) { - ok = FALSE; - Dmsg4(100, "Duration=%d now=%d start=%d now-start=%d\n", - (int)mr->VolUseDuration, (int)now, (int)mr->FirstWritten, - (int)(now-mr->FirstWritten)); - Jmsg(jcr, M_INFO, 0, _("Max configured use duration exceeded. " - "Marking Volume \"%s\" as Used.\n"), mr->VolumeName); - strcpy(mr->VolStatus, "Used"); /* yes, mark as used */ + if (ok) { + /* If we can use the volume, check if it is expired */ + if (has_volume_expired(jcr, mr)) { + /* Need to update media */ if (!db_update_media_record(jcr, jcr->db, mr)) { Jmsg(jcr, M_ERROR, 0, _("Catalog error updating volume \"%s\". ERR=%s"), mr->VolumeName, db_strerror(jcr->db)); @@ -126,3 +118,136 @@ int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int create) db_unlock(jcr->db); return ok; } + +/* + * Check if any time limits or use limits have expired + * if so, set the VolStatus appropriately. + */ +bool has_volume_expired(JCR *jcr, MEDIA_DBR *mr) +{ + bool expired = false; + /* + * Check limits and expirations if "Append" and it has been used + * i.e. mr->VolJobs > 0 + * + */ + if (strcmp(mr->VolStatus, "Append") == 0 && mr->VolJobs > 0) { + /* First handle Max Volume Bytes */ + if ((mr->MaxVolBytes > 0 && mr->VolBytes >= mr->MaxVolBytes)) { + Jmsg(jcr, M_INFO, 0, _("Max Volume bytes exceeded. " + "Marking Volume \"%s\" as Full.\n"), mr->VolumeName); + bstrncpy(mr->VolStatus, "Full", sizeof(mr->VolStatus)); + expired = true; + + /* Now see if Volume should only be used once */ + } else if (mr->VolBytes > 0 && jcr->pool->use_volume_once) { + Jmsg(jcr, M_INFO, 0, _("Volume used once. " + "Marking Volume \"%s\" as Used.\n"), mr->VolumeName); + bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus)); + expired = true; + + /* Now see if Max Jobs written to volume */ + } else if (mr->MaxVolJobs > 0 && mr->MaxVolJobs <= mr->VolJobs) { + Jmsg(jcr, M_INFO, 0, _("Max Volume jobs exceeded. " + "Marking Volume \"%s\" as Used.\n"), mr->VolumeName); + bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus)); + expired = true; + + /* Now see if Max Files written to volume */ + } else if (mr->MaxVolFiles > 0 && mr->MaxVolFiles <= mr->VolFiles) { + Jmsg(jcr, M_INFO, 0, _("Max Volume files exceeded. " + "Marking Volume \"%s\" as Used.\n"), mr->VolumeName); + bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus)); + expired = true; + + /* Finally, check Use duration expiration */ + } else if (mr->VolUseDuration > 0) { + utime_t now = time(NULL); + /* See if Vol Use has expired */ + if (mr->VolUseDuration <= (now - mr->FirstWritten)) { + Jmsg(jcr, M_INFO, 0, _("Max configured use duration exceeded. " + "Marking Volume \"%s\" as Used.\n"), mr->VolumeName); + bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus)); + expired = true; + } + } + } + return expired; +} + +/* + * Try hard to recycle the current volume + * + * Returns: on failure - reason = NULL + * on success - reason - pointer to reason + */ +bool is_volume_valid_or_recyclable(JCR *jcr, MEDIA_DBR *mr, char **reason) +{ + int ok; + + *reason = NULL; + + /* Check if a duration or limit has expired */ + has_volume_expired(jcr, mr); + + /* + * Now see if we can use the volume as is + */ + if (strcmp(mr->VolStatus, "Append") == 0 || + strcmp(mr->VolStatus, "Recycle") == 0) { + return true; + } + + /* + * Check if the Volume is alreay marked for recycling + */ + if (strcmp(mr->VolStatus, "Purged") == 0) { + if (recycle_volume(jcr, mr)) { + Jmsg(jcr, M_INFO, 0, "Recycled current volume \"%s\"\n", mr->VolumeName); + return true; + } else { + /* In principle this shouldn't happen */ + *reason = "recycling of current volume failed"; + return false; + } + } + + /* At this point, the volume is not valid for writing */ + *reason = "not Append, Purged or Recycle"; + + /* + * What we're trying to do here is see if the current volume is + * "recyclable" - ie. if we prune all expired jobs off it, is + * it now possible to reuse it for the job that it is currently + * needed for? + */ + if ((mr->LastWritten + mr->VolRetention) < (utime_t)time(NULL) + && mr->Recycle && jcr->pool->recycle_current_volume + && (strcmp(mr->VolStatus, "Full") == 0 || + strcmp(mr->VolStatus, "Used") == 0)) { + /* + * Attempt prune of current volume to see if we can + * recycle it for use. + */ + UAContext *ua; + + ua = new_ua_context(jcr); + ok = prune_volume(ua, mr); + free_ua_context(ua); + + if (ok) { + /* If fully purged, recycle current volume */ + if (recycle_volume(jcr, mr)) { + 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 " + "current volume failed)"; + } + } else { + *reason = "not Append, Purged or Recycle (cannot automatically " + "recycle current volume, as it still contains unpruned data)"; + } + } + return *reason ? false : true; +} diff --git a/bacula/src/dird/protos.h b/bacula/src/dird/protos.h index e54713823d..a4b48609de 100644 --- a/bacula/src/dird/protos.h +++ b/bacula/src/dird/protos.h @@ -101,6 +101,8 @@ extern void wait_for_storage_daemon_termination(JCR *jcr); /* next_vol.c */ int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int create); +bool has_volume_expired(JCR *jcr, MEDIA_DBR *mr); +bool is_volume_valid_or_recyclable(JCR *jcr, MEDIA_DBR *mr, char **reason); /* newvol.c */ int newVolume(JCR *jcr, MEDIA_DBR *mr); diff --git a/bacula/src/dird/recycle.c b/bacula/src/dird/recycle.c index 591888121a..9e5b4fce0e 100644 --- a/bacula/src/dird/recycle.c +++ b/bacula/src/dird/recycle.c @@ -114,7 +114,7 @@ int recycle_volume(JCR *jcr, MEDIA_DBR *mr) { bstrncpy(mr->VolStatus, "Recycle", sizeof(mr->VolStatus)); mr->VolJobs = mr->VolFiles = mr->VolBlocks = mr->VolErrors = 0; - mr->VolBytes = 0; + mr->VolBytes = 1; mr->FirstWritten = mr->LastWritten = 0; return db_update_media_record(jcr, jcr->db, mr); } diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 1be9924233..7acb0d1216 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -821,12 +821,12 @@ static int update_volume(UAContext *ua) N_("Recycle"), /* 6 */ NULL }; - if (!select_media_dbr(ua, &mr)) { - return 0; - } for (int i=0; kw[i]; i++) { int j; if ((j=find_arg_with_value(ua, kw[i])) > 0) { + if (!select_media_dbr(ua, &mr)) { + return 0; + } switch (i) { case 0: update_volstatus(ua, ua->argv[j], &mr); diff --git a/bacula/src/lib/watchdog.c b/bacula/src/lib/watchdog.c index 002207641f..93ba92cee1 100755 --- a/bacula/src/lib/watchdog.c +++ b/bacula/src/lib/watchdog.c @@ -75,8 +75,6 @@ int start_watchdog(void) watchdog_time = time(NULL); quit = FALSE; if ((stat = pthread_create(&wdid, NULL, btimer_thread, (void *)NULL)) != 0) { - pthread_mutex_destroy(&mutex); - pthread_cond_destroy(&timer); return stat; } return 0; diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index 48fe3ecaa8..940b0171f2 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -161,10 +161,11 @@ get_out: * multiple devices (for files), thus we have our own mutex * on top of the device mutex. */ -DEVICE * acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) +DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) { int release = 0; - int do_mount = 0; + bool recycle = false; + bool do_mount = false; DEVICE *rtn_dev = NULL; if (device_is_unmounted(dev)) { @@ -218,8 +219,20 @@ DEVICE * acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) } /* Wrong tape mounted, release it, then fall through to get correct one */ release = 1; - do_mount = 1; - } + do_mount = true; + } else { + /* + * At this point, the correct tape is already mounted, so + * we do not need to do mount_next_write_volume(), unless + * we need to recycle the tape. + */ + recycle = strcmp(jcr->VolCatInfo.VolCatStatus, "Recycle") == 0; + if (recycle && dev->num_writers != 0) { + Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\"" + " because it is in use by another job.")); + goto get_out; + } + } } else { /* Not already in append mode, so mount the device */ if (dev->state & ST_READ) { @@ -227,10 +240,10 @@ DEVICE * acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) goto get_out; } ASSERT(dev->num_writers == 0); - do_mount = 1; + do_mount = true; } - if (do_mount) { + if (do_mount || recycle) { if (!mount_next_write_volume(jcr, dev, block, release)) { Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"), dev_name(dev)); @@ -239,16 +252,16 @@ DEVICE * acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) } dev->num_writers++; - if (dev->num_writers > 1) { - Dmsg2(100, "Hey!!!! There are %d writers on device %s\n", dev->num_writers, - dev_name(dev)); - } if (jcr->NumVolumes == 0) { jcr->NumVolumes = 1; } attach_jcr_to_device(dev, jcr); /* attach jcr to device */ rtn_dev = dev; /* return device */ +/* + * If we jump here, it is an error return because + * rtn_dev will still be NULL + */ get_out: P(dev->mutex); unblock_device(dev); diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index ec67d19976..91a6ac3c17 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -387,7 +387,7 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname, case VOL_OK: if (!relabel) { bnet_fsend(dir, _( - "3911 Cannot label Volume because it is already labeled: %s\n"), + "3911 Cannot label Volume because it is already labeled: \"%s\"\n"), dev->VolHdr.VolName); break; } @@ -520,7 +520,7 @@ static int mount_cmd(JCR *jcr) dev->dev_name, dev->VolHdr.VolName); } else { bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n" - "Try unmounting and remounting the Volume.\n"), + "If this is not a blank tape, try unmounting and remounting the Volume.\n"), dev->dev_name); } break; @@ -541,7 +541,7 @@ static int mount_cmd(JCR *jcr) dev->dev_name, dev->VolHdr.VolName); } else { bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n" - "Try unmounting and remounting the Volume.\n"), + "If this is not a blank tape, try unmounting and remounting the Volume.\n"), dev->dev_name); } } else { @@ -560,7 +560,7 @@ static int mount_cmd(JCR *jcr) dev->dev_name, dev->VolHdr.VolName); } else { bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n" - "Try unmounting and remounting the Volume.\n"), + "If this is not a blank tape, try unmounting and remounting the Volume.\n"), dev->dev_name); } } diff --git a/bacula/src/stored/job.c b/bacula/src/stored/job.c index 3a8d3a2112..37f732732b 100644 --- a/bacula/src/stored/job.c +++ b/bacula/src/stored/job.c @@ -376,6 +376,6 @@ void stored_free_jcr(JCR *jcr) if (jcr->next_dev && jcr->prev_dev) { Emsg0(M_FATAL, 0, _("In free_jcr(), but still attached to device!!!!\n")); } - + pthread_cond_destroy(&jcr->job_start_wait); return; } diff --git a/bacula/src/stored/mount.c b/bacula/src/stored/mount.c index 0e2bcb6a9a..4d45f4e384 100644 --- a/bacula/src/stored/mount.c +++ b/bacula/src/stored/mount.c @@ -43,10 +43,13 @@ * * This routine returns a 0 only if it is REALLY * impossible to get the requested Volume. + * + * *****FIXME****** handle "Recycle" volume ****** */ int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release) { - int recycle, ask, retry = 0, autochanger; + int retry = 0, autochanger; + bool ask, recycle; Dmsg0(100, "Enter mount_next_volume()\n"); @@ -60,11 +63,12 @@ mount_next_vol: Jmsg(jcr, M_FATAL, 0, _("Job canceled.\n")); return 0; } - recycle = ask = autochanger = 0; + autochanger = 0; + recycle = ask = false; if (release) { Dmsg0(100, "mount_next_volume release=1\n"); release_volume(jcr, dev); - ask = 1; /* ask operator to mount tape */ + ask = true; /* ask operator to mount tape */ } /* @@ -107,7 +111,7 @@ mount_next_vol: * we will err, recurse and ask the operator the next time. */ if (autochanger || (!release && dev_is_tape(dev) && dev_cap(dev, CAP_AUTOMOUNT))) { - ask = 0; /* don't ask SYSOP this time */ + ask = false; /* don't ask SYSOP this time */ } release = 1; /* release next time if we "recurse" */ @@ -149,6 +153,8 @@ read_volume: } else { vol_label_status = read_dev_volume_label(jcr, dev, block); } + Dmsg2(100, "dirVol=%s dirStat=%s\n", jcr->VolumeName, + jcr->VolCatInfo.VolCatStatus); /* * At this point, dev->VolCatInfo has what is in the drive, if anything, * and jcr->VolCatInfo has what the Director wants. @@ -157,9 +163,7 @@ read_volume: case VOL_OK: Dmsg1(100, "Vol OK name=%s\n", jcr->VolumeName); memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(jcr->VolCatInfo)); - if (strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0) { - recycle = 1; - } + recycle = strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0; break; /* got a Volume */ case VOL_NAME_ERROR: VOLUME_CAT_INFO VolCatInfo; @@ -171,7 +175,7 @@ read_volume: * this volume is really OK. If not, put back the desired * volume name and continue. */ - memcpy(&VolCatInfo, &jcr->VolCatInfo, sizeof(jcr->VolCatInfo)); + memcpy(&VolCatInfo, &jcr->VolCatInfo, sizeof(VolCatInfo)); /* Check if this is a valid Volume in the pool */ pm_strcpy(&jcr->VolumeName, dev->VolHdr.VolName); if (!dir_get_volume_info(jcr, GET_VOL_INFO_FOR_WRITE)) { @@ -186,9 +190,7 @@ read_volume: } Dmsg1(100, "want new name=%s\n", jcr->VolumeName); memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(dev->VolCatInfo)); - if (strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0) { - recycle = 1; - } + recycle = strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0; break; /* got a Volume */ /* * At this point, we assume we have a blank tape mounted. @@ -198,8 +200,11 @@ read_volume: /* * If permitted, we label the device, make sure we can do * it by checking that the VolCatBytes is zero => not labeled. + * As noted above, at this point jcr->VolCatInfo has what + * the Director wants and dev->VolCatInfo has info on the + * previous tape (or nothing). */ - if (dev_cap(dev, CAP_LABEL) && dev->VolCatInfo.VolCatBytes == 0) { + if (dev_cap(dev, CAP_LABEL) && jcr->VolCatInfo.VolCatBytes == 0) { Dmsg0(100, "Create volume label\n"); if (!write_volume_label_to_dev(jcr, (DEVRES *)dev->device, jcr->VolumeName, jcr->pool_name)) { @@ -207,6 +212,7 @@ read_volume: goto mount_next_vol; } Dmsg0(200, "dir_update_vol_info. Set Append\n"); + /* Copy Director's info into the device info */ memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(dev->VolCatInfo)); dir_update_volume_info(jcr, &dev->VolCatInfo, 1); /* indicate tape labeled */ Jmsg(jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"), @@ -220,14 +226,14 @@ mount_error: /* Send error message */ Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg); Dmsg0(100, "Default\n"); - ask = 1; + ask = true; goto ask_again; } break; } /* - * See if we have a fresh tape or tape with data. + * See if we have a fresh tape or a tape with data. * * Note, if the LabelType is PRE_LABEL, it was labeled * but never written. If so, rewrite the label but set as @@ -277,7 +283,7 @@ mount_error: /* Set or reset Volume statistics */ dev->VolCatInfo.VolCatJobs = 0; dev->VolCatInfo.VolCatFiles = 0; - dev->VolCatInfo.VolCatBytes = 0; + dev->VolCatInfo.VolCatBytes = 1; dev->VolCatInfo.VolCatErrors = 0; dev->VolCatInfo.VolCatBlocks = 0; dev->VolCatInfo.VolCatRBytes = 0; @@ -291,6 +297,7 @@ mount_error: dev->VolCatInfo.VolCatReads = 1; } Dmsg0(200, "dir_update_vol_info. Set Append\n"); + bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus)); dir_update_volume_info(jcr, &dev->VolCatInfo, 1); /* indicate doing relabel */ if (recycle) { Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"), @@ -314,7 +321,7 @@ mount_error: dev_name(dev), strerror_dev(dev)); Jmsg(jcr, M_INFO, 0, _("Marking Volume \"%s\" in Error in Catalog.\n"), jcr->VolumeName); - strcpy(dev->VolCatInfo.VolCatStatus, "Error"); + bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus)); Dmsg0(200, "dir_update_vol_info. Set Error.\n"); dir_update_volume_info(jcr, &dev->VolCatInfo, 0); goto mount_next_vol; @@ -332,7 +339,7 @@ mount_error: Jmsg(jcr, M_ERROR, 0, _("I canot write on this volume because:\n\ The number of files mismatch! Volume=%u Catalog=%u\n"), dev_file(dev), dev->VolCatInfo.VolCatFiles); - strcpy(dev->VolCatInfo.VolCatStatus, "Error"); + bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus)); Dmsg0(200, "dir_update_vol_info. Set Error.\n"); dir_update_volume_info(jcr, &dev->VolCatInfo, 0); goto mount_next_vol; diff --git a/bacula/src/version.h b/bacula/src/version.h index f3d1854935..4c1c968022 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -2,8 +2,8 @@ #undef VERSION #define VERSION "1.32" #define VSTRING "1" -#define BDATE "16 Sep 2003" -#define LSMDATE "16Sep03" +#define BDATE "18 Sep 2003" +#define LSMDATE "18Sep03" /* Debug flags */ #undef DEBUG -- 2.39.5