/*
Bacula® - The Network Backup Solution
- Copyright (C) 2002-2009 Free Software Foundation Europe e.V.
+ Copyright (C) 2002-2012 Free Software Foundation Europe e.V.
The main author of Bacula is Kern Sibbald, with contributions from
many others, a complete list can be found in the file AUTHORS.
This program is Free Software; you can redistribute it and/or
- modify it under the terms of version two of the GNU General Public
+ modify it under the terms of version three of the GNU Affero General Public
License as published by the Free Software Foundation and included
in the file LICENSE.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
- You should have received a copy of the GNU General Public License
+ You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*
* Kern Sibbald, August MMII
*
- * Version $Id$
*/
#include "bacula.h" /* pull in global headers */
#include "stored.h" /* pull in Storage Deamon headers */
-
enum {
try_next_vol = 1,
try_read_vol,
{
int retry = 0;
bool ask = false, recycle, autochanger;
- bool do_find = true;
int mode;
DCR *dcr = this;
dev->print_name());
init_device_wait_timers(dcr);
- lock_volumes();
/*
* Attempt to mount the next volume. If something non-fatal goes
* wrong, we come back here to re-try (new op messages, re-read
* Volume, ...)
*/
+ lock_volumes();
+
mount_next_vol:
Dmsg1(150, "mount_next_vol retry=%d\n", retry);
/* Ignore retry if this is poll request */
- if (!dev->poll && retry++ > 4) {
+ if (retry++ > 4) {
/* Last ditch effort before giving up, force operator to respond */
VolCatInfo.Slot = 0;
unlock_volumes();
}
recycle = false;
- if (retry >= 2) {
- do_find = false;
- }
-
if (dev->must_unload()) {
ask = true; /* ask operator to mount tape */
- do_find = true; /* re-find a volume after unload */
}
- unlock_volumes();
do_unload();
do_swapping(true /*is_writing*/);
do_load(true /*is_writing*/);
- lock_volumes();
- if (do_find && !find_a_volume()) {
- goto no_lock_bail_out;
+ if (!find_a_volume()) {
+ goto bail_out;
}
if (job_canceled(jcr)) {
goto bail_out;
}
Dmsg3(150, "After find_next_append. Vol=%s Slot=%d Parts=%d\n",
- VolCatInfo.VolCatName, VolCatInfo.Slot, VolCatInfo.VolCatParts);
+ getVolCatName(), VolCatInfo.Slot, VolCatInfo.VolCatParts);
/*
* Get next volume and ready it for append
* and move the tape to the end of data.
*
*/
- unlock_volumes();
+ dcr->setVolCatInfo(false); /* out of date when Vols unlocked */
if (autoload_device(dcr, true/*writing*/, NULL) > 0) {
autochanger = true;
ask = false;
autochanger = false;
VolCatInfo.Slot = 0;
ask = retry >= 2;
- do_find = true; /* do find_a_volume if we retry */
}
- lock_volumes();
Dmsg1(150, "autoload_dev returns %d\n", autochanger);
/*
* If we autochanged to correct Volume or (we have not just
if (ask) {
unlock_volumes();
+ dcr->setVolCatInfo(false); /* out of date when Vols unlocked */
if (!dir_ask_sysop_to_mount_volume(dcr, ST_APPEND)) {
Dmsg0(150, "Error return ask_sysop ...\n");
goto no_lock_bail_out;
mode = OPEN_READ_WRITE;
}
/* Try autolabel if enabled */
- if (dev->open(dcr, mode) < 0) {
+ if (!dev->open(dcr, mode)) {
try_autolabel(false); /* try to create a new volume label */
}
- while (dev->open(dcr, mode) < 0) {
+ while (!dev->open(dcr, mode)) {
Dmsg1(150, "open_device failed: ERR=%s\n", dev->bstrerror());
if ((dev->is_file() && dev->is_removable()) || dev->is_dvd()) {
bool ok = true;
}
}
if (ok && dev->scan_dir_for_volume(dcr)) {
- if (dev->open(dcr, mode) >= 0) {
+ if (dev->open(dcr, mode)) {
break; /* got a valid volume */
}
}
case check_ok:
break;
}
+ /*
+ * Check that volcatinfo is good
+ */
+ if (!dev->haveVolCatInfo()) {
+ Dmsg0(210, "Do not have volcatinfo\n");
+ if (!find_a_volume()) {
+ goto mount_next_vol;
+ }
+ dev->VolCatInfo = VolCatInfo; /* structure assignment */
+ }
/*
* See if we have a fresh tape or a tape with data.
*/
recycle = strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0;
if (dev->VolHdr.LabelType == PRE_LABEL || recycle) {
- if (!rewrite_volume_label(dcr, recycle)) {
+ if (!dcr->rewrite_volume_label(recycle)) {
mark_volume_in_error();
goto mount_next_vol;
}
* This routine is meant to be called once the first pass
* to ensure that we have a candidate volume to mount.
* Otherwise, we ask the sysop to created one.
- * Note, the the Volumes are locked on entry.
- * They are unlocked on failure and remain locked on
- * success. The caller must know this!!!
+ * Note, the the Volumes are locked on entry and exit.
*/
-bool DCR::find_a_volume()
+bool DCR::find_a_volume()
{
DCR *dcr = this;
+
if (!is_suitable_volume_mounted()) {
bool have_vol = false;
/* Do we have a candidate volume? */
while (!dir_find_next_appendable_volume(dcr)) {
Dmsg0(200, "not dir_find_next\n");
if (job_canceled(jcr)) {
- unlock_volumes();
return false;
}
unlock_volumes();
if (!dir_ask_sysop_to_create_appendable_volume(dcr)) {
+ lock_volumes();
return false;
}
lock_volumes();
+ if (job_canceled(jcr)) {
+ return false;
+ }
Dmsg0(150, "Again dir_find_next_append...\n");
}
}
}
- return true;
+ if (dcr->haveVolCatInfo()) {
+ return true;
+ }
+ return dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE);
}
int DCR::check_volume_label(bool &ask, bool &autochanger)
Dmsg2(150, "Want dirVol=%s dirStat=%s\n", VolumeName,
VolCatInfo.VolCatStatus);
+
/*
* At this point, dev->VolCatInfo has what is in the drive, if anything,
* and dcr->VolCatInfo has what the Director wants.
Jmsg2(jcr, M_WARNING, 0, _("Could not reserve volume %s on %s\n"),
dev->VolHdr.VolumeName, dev->print_name());
ask = true;
+ dev->setVolCatInfo(false);
+ setVolCatInfo(false);
goto check_next_volume;
}
break; /* got a Volume */
return check_ok;
check_next_volume:
+ dev->setVolCatInfo(false);
+ setVolCatInfo(false);
return check_next_vol;
check_bail_out:
Dmsg2(100, "Vol=%s on dev=%s\n", dev->swap_dev->vol->vol_name,
dev->swap_dev->print_name());
}
+ Dmsg2(100, "Set swap_dev=NULL for dev=%s swap_dev=%s\n",
+ dev->print_name(), dev->swap_dev->print_name());
dev->swap_dev = NULL;
+ } else {
+ Dmsg0(100, "No swap_dev set\n");
}
}
if (dev->VolCatInfo.VolCatFiles == dev->get_file()) {
Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\" at file=%d.\n"),
VolumeName, dev->get_file());
+ } else if (dev->get_file() > dev->VolCatInfo.VolCatFiles) {
+ Jmsg(jcr, M_WARNING, 0, _("For Volume \"%s\":\n"
+ "The number of files mismatch! Volume=%u Catalog=%u\n"
+ "Correcting Catalog\n"),
+ VolumeName, dev->get_file(), dev->VolCatInfo.VolCatFiles);
+ dev->VolCatInfo.VolCatFiles = dev->get_file();
+ dev->VolCatInfo.VolCatBlocks = dev->get_block_num();
+ if (!dir_update_volume_info(this, false, true)) {
+ Jmsg(jcr, M_WARNING, 0, _("Error updating Catalog\n"));
+ mark_volume_in_error();
+ return false;
+ }
} else {
Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on tape Volume \"%s\" because:\n"
"The number of files mismatch! Volume=%u Catalog=%u\n"),
Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\""
" size=%s\n"), VolumeName,
edit_uint64(dev->VolCatInfo.VolCatBytes, ed1));
+ } else if ((uint64_t)pos > dev->VolCatInfo.VolCatBytes) {
+ Jmsg(jcr, M_WARNING, 0, _("For Volume \"%s\":\n"
+ "The sizes do not match! Volume=%s Catalog=%s\n"
+ "Correcting Catalog\n"),
+ VolumeName, edit_uint64(pos, ed1),
+ edit_uint64(dev->VolCatInfo.VolCatBytes, ed2));
+ dev->VolCatInfo.VolCatBytes = (uint64_t)pos;
+ dev->VolCatInfo.VolCatFiles = (uint32_t)(pos >> 32);
+ if (!dir_update_volume_info(this, false, true)) {
+ Jmsg(jcr, M_WARNING, 0, _("Error updating Catalog\n"));
+ mark_volume_in_error();
+ return false;
+ }
} else {
Mmsg(jcr->errmsg, _("Bacula cannot write on disk Volume \"%s\" because: "
"The sizes do not match! Volume=%s Catalog=%s\n"),
{
Jmsg(jcr, M_ERROR, 0, _("Autochanger Volume \"%s\" not found in slot %d.\n"
" Setting InChanger to zero in catalog.\n"),
- VolCatInfo.VolCatName, VolCatInfo.Slot);
+ getVolCatName(), VolCatInfo.Slot);
dev->VolCatInfo = VolCatInfo; /* structure assignment */
VolCatInfo.InChanger = false;
dev->VolCatInfo.InChanger = false;
if (dev->is_open()) {
dev->offline_or_rewind();
}
-// Dmsg0(50, "set_unload\n");
-// dev->set_unload();
Dmsg0(190, "release_volume\n");
}
* End Of Tape -- mount next Volume (if another specified)
*/
if (jcr->NumReadVolumes > 1 && jcr->CurReadVolume < jcr->NumReadVolumes) {
+ dev->Lock();
dev->close();
+ dev->set_read();
+ dcr->set_reserved();
+ dev->Unlock();
if (!acquire_device_for_read(dcr)) {
Jmsg2(jcr, M_FATAL, 0, _("Cannot open Dev=%s, Vol=%s\n"), dev->print_name(),
dcr->VolumeName);