/*
- Bacula® - The Network Backup Solution
-
- Copyright (C) 2002-2008 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
- License as published by the Free Software Foundation and included
- in the file LICENSE.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- 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
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
- Bacula® is a registered trademark of Kern Sibbald.
- The licensor of Bacula is the Free Software Foundation Europe
- (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
- Switzerland, email:ftf@fsfeurope.org.
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2017 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
*/
/*
*
*
* Kern Sibbald, August MMII
*
- * Version $Id$
*/
#include "bacula.h" /* pull in global headers */
#include "stored.h" /* pull in Storage Deamon headers */
+static pthread_mutex_t mount_mutex = PTHREAD_MUTEX_INITIALIZER;
enum {
try_next_vol = 1,
* This routine returns a 0 only if it is REALLY
* impossible to get the requested Volume.
*
+ * This routine is entered with the device blocked, but not
+ * locked.
+ *
*/
bool DCR::mount_next_write_volume()
{
int retry = 0;
bool ask = false, recycle, autochanger;
- bool do_find = true;
- int mode;
DCR *dcr = this;
- Dmsg2(150, "Enter mount_next_volume(release=%d) dev=%s\n", dev->must_unload(),
+ Enter(200);
+ set_ameta();
+ Dmsg2(100, "Enter mount_next_volume(release=%d) dev=%s\n", dev->must_unload(),
dev->print_name());
init_device_wait_timers(dcr);
- lock_volumes();
-
+
+ P(mount_mutex);
+
/*
* 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, ...)
*/
mount_next_vol:
- Dmsg1(150, "mount_next_vol retry=%d\n", retry);
+ Dmsg1(100, "mount_next_vol retry=%d\n", retry);
/* Ignore retry if this is poll request */
- if (!dev->poll && retry++ > 4) {
+ if (dev->is_nospace() || retry++ > 4) {
/* Last ditch effort before giving up, force operator to respond */
VolCatInfo.Slot = 0;
- unlock_volumes();
- if (!dir_ask_sysop_to_mount_volume(dcr, ST_APPEND)) {
- Jmsg(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"),
- dev->print_name());
+ V(mount_mutex);
+ if (!dir_ask_sysop_to_mount_volume(dcr, SD_APPEND)) {
+ Jmsg(jcr, M_FATAL, 0, _("Too many errors trying to mount %s device %s.\n"),
+ dev->print_type(), dev->print_name());
goto no_lock_bail_out;
}
- lock_volumes();
- Dmsg1(150, "Continue after dir_ask_sysop_to_mount. must_load=%d\n", dev->must_load());
+ P(mount_mutex);
+ Dmsg1(90, "Continue after dir_ask_sysop_to_mount. must_load=%d\n", dev->must_load());
}
if (job_canceled(jcr)) {
Jmsg(jcr, M_FATAL, 0, _("Job %d canceled.\n"), jcr->JobId);
}
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 */
}
do_unload();
- do_swapping(true /*is_writing*/);
- do_load(true /*is_writing*/);
+ do_swapping(SD_APPEND);
+ do_load(SD_APPEND);
- 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);
-
+ Dmsg3(100, "After find_a_volume. Vol=%s Slot=%d VolType=%d\n",
+ getVolCatName(), VolCatInfo.Slot, VolCatInfo.VolCatType);
+
+ dev->notify_newvol_in_attached_dcrs(getVolCatName());
+
/*
* Get next volume and ready it for append
* This code ensures that the device is ready for
* and move the tape to the end of data.
*
*/
- if (autoload_device(dcr, true/*writing*/, NULL) > 0) {
+ dcr->setVolCatInfo(false); /* out of date when Vols unlocked */
+ if (autoload_device(dcr, SD_APPEND, NULL) > 0) {
autochanger = true;
ask = false;
} else {
autochanger = false;
VolCatInfo.Slot = 0;
- ask = retry >= 2;
+ if (dev->is_autochanger() && !VolCatInfo.InChanger) {
+ ask = true; /* not in changer, do not retry */
+ } else {
+ ask = retry >= 2;
+ }
}
- Dmsg1(150, "autoload_dev returns %d\n", autochanger);
+ Dmsg1(100, "autoload_dev returns %d\n", autochanger);
/*
* If we autochanged to correct Volume or (we have not just
* released the Volume AND we can automount) we go ahead
Dmsg0(250, "(2)Ask=0\n");
ask = false;
}
- Dmsg2(250, "Ask=%d autochanger=%d\n", ask, autochanger);
+ Dmsg2(100, "Ask=%d autochanger=%d\n", ask, autochanger);
if (ask) {
- unlock_volumes();
- if (!dir_ask_sysop_to_mount_volume(dcr, ST_APPEND)) {
+ V(mount_mutex);
+ dcr->setVolCatInfo(false); /* out of date when Vols unlocked */
+ if (!dir_ask_sysop_to_mount_volume(dcr, SD_APPEND)) {
Dmsg0(150, "Error return ask_sysop ...\n");
goto no_lock_bail_out;
}
- lock_volumes();
+ P(mount_mutex);
}
if (job_canceled(jcr)) {
goto bail_out;
}
- Dmsg3(150, "want vol=%s devvol=%s dev=%s\n", VolumeName,
+ Dmsg3(100, "want vol=%s devvol=%s dev=%s\n", VolumeName,
dev->VolHdr.VolumeName, dev->print_name());
if (dev->poll && dev->has_cap(CAP_CLOSEONPOLL)) {
- dev->close();
+ dev->close(this);
+ free_volume(dev);
}
- /* Ensure the device is open */
- if (dev->has_cap(CAP_STREAM)) {
- mode = OPEN_WRITE_ONLY;
- } else {
- mode = OPEN_READ_WRITE;
- }
/* Try autolabel if enabled */
- if (dev->open(dcr, mode) < 0) {
- try_autolabel(false); /* try to create a new volume label */
+ Dmsg1(100, "Try open Vol=%s\n", getVolCatName());
+ if (!dev->open_device(dcr, OPEN_READ_WRITE)) {
+ Dmsg1(100, "Try autolabel Vol=%s\n", getVolCatName());
+ if (!dev->poll) {
+ try_autolabel(false); /* try to create a new volume label */
+ }
}
- while (dev->open(dcr, mode) < 0) {
- Dmsg1(150, "open_device failed: ERR=%s\n", dev->bstrerror());
- if ((dev->is_file() && dev->is_removable()) || dev->is_dvd()) {
+ while (!dev->open_device(dcr, OPEN_READ_WRITE)) {
+ Dmsg1(100, "open_device failed: ERR=%s", dev->bstrerror());
+ if (dev->is_file() && dev->is_removable()) {
bool ok = true;
Dmsg0(150, "call scan_dir_for_vol\n");
- if (dev->is_dvd()) {
- if (!dev->mount(0)) {
- ok = false;
- }
- }
if (ok && dev->scan_dir_for_volume(dcr)) {
- if (dev->open(dcr, mode) >= 0) {
+ if (dev->open_device(dcr, OPEN_READ_WRITE)) {
break; /* got a valid volume */
}
}
- if (ok && dev->is_dvd()) {
- dev->unmount(0);
- }
}
if (try_autolabel(false) == try_read_vol) {
break; /* created a new volume label */
}
- Dmsg0(50, "set_unload\n");
- dev->set_unload(); /* force ask sysop */
- ask = true;
- Dmsg0(150, "goto mount_next_vol\n");
+
+ /* ***FIXME*** if autochanger, before giving up try unload and load */
+
+ Jmsg4(jcr, M_WARNING, 0, _("Open of %s device %s Volume \"%s\" failed: ERR=%s\n"),
+ dev->print_type(), dev->print_name(), dcr->VolumeName, dev->bstrerror());
+
+ /* If not removable, Volume is broken. This is a serious issue here. */
+ if(dev->is_file() && !dev->is_removable()) {
+ Dmsg3(40, "Volume \"%s\" not loaded on %s device %s.\n",
+ dcr->VolumeName, dev->print_type(), dev->print_name());
+ mark_volume_in_error();
+
+ } else {
+ Dmsg0(100, "set_unload\n");
+ dev->set_unload(); /* force ask sysop */
+ ask = true;
+ }
+
+ Dmsg0(100, "goto mount_next_vol\n");
goto mount_next_vol;
}
case check_next_vol:
Dmsg0(50, "set_unload\n");
dev->set_unload(); /* want a different Volume */
- Dmsg0(150, "goto mount_next_vol\n");
+ Dmsg0(100, "goto mount_next_vol\n");
goto mount_next_vol;
case check_read_vol:
goto read_volume;
case check_ok:
break;
}
+ /*
+ * Check that volcatinfo is good
+ */
+ if (!dev->haveVolCatInfo()) {
+ Dmsg0(100, "Do not have volcatinfo\n");
+ if (!find_a_volume()) {
+ goto mount_next_vol;
+ }
+ dev->set_volcatinfo_from_dcr(this);
+ }
/*
* 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)) {
+ dcr->WroteVol = false;
+ if (!dev->rewrite_volume_label(dcr, recycle)) {
mark_volume_in_error();
goto mount_next_vol;
}
* we need to position to the end of the volume, since we are
* just now putting it into append mode.
*/
- Dmsg0(200, "Device previously written, moving to end of data\n");
+ Dmsg1(100, "Device previously written, moving to end of data. Expect %lld bytes\n",
+ dev->VolCatInfo.VolCatBytes);
Jmsg(jcr, M_INFO, 0, _("Volume \"%s\" previously written, moving to end of data.\n"),
VolumeName);
if (!dev->eod(dcr)) {
- Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data on device %s: ERR=%s\n"),
- dev->print_name(), dev->bstrerror());
+ Dmsg3(050, "Unable to position to end of data on %s device %s: ERR=%s\n",
+ dev->print_type(), dev->print_name(), dev->bstrerror());
+ Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data on %s device %s: ERR=%s\n"),
+ dev->print_type(), dev->print_name(), dev->bstrerror());
mark_volume_in_error();
goto mount_next_vol;
}
- if (!is_eod_valid()) {
- Dmsg0(150, "goto mount_next_vol\n");
+
+ if (!dev->is_eod_valid(dcr)) {
+ Dmsg0(100, "goto mount_next_vol\n");
goto mount_next_vol;
}
if (!dir_update_volume_info(dcr, false, false)) {
goto bail_out;
}
-
+
/* Return an empty block */
empty_block(block); /* we used it for reading so set for write */
}
Dmsg1(150, "set APPEND, normal return from mount_next_write_volume. dev=%s\n",
dev->print_name());
- unlock_volumes();
+ V(mount_mutex);
return true;
bail_out:
- unlock_volumes();
+ V(mount_mutex);
no_lock_bail_out:
+ Leave(200);
return false;
}
* 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, mount_mutex is already locked on entry and thus
+ * must remain locked on exit from this function.
*/
-bool DCR::find_a_volume()
+bool DCR::find_a_volume()
{
DCR *dcr = this;
+ bool ok;
+
if (!is_suitable_volume_mounted()) {
bool have_vol = false;
/* Do we have a candidate volume? */
if (dev->vol) {
bstrncpy(VolumeName, dev->vol->vol_name, sizeof(VolumeName));
- have_vol = dir_get_volume_info(this, GET_VOL_INFO_FOR_WRITE);
+ have_vol = dir_get_volume_info(this, VolumeName, GET_VOL_INFO_FOR_WRITE);
}
/*
* Get Director's idea of what tape we should have mounted.
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)) {
+ /*
+ * Unlock the mount mutex while waiting or
+ * the Director for a new volume
+ */
+ V(mount_mutex);
+ if (dev->must_wait()) {
+ int retries = 5;
+ Dmsg0(40, "No appendable volume. Calling wait_for_device\n");
+ wait_for_device(dcr, retries);
+ ok = true;
+ } else {
+ ok = dir_ask_sysop_to_create_appendable_volume(dcr);
+ }
+ P(mount_mutex);
+ if (!ok || job_canceled(jcr)) {
return false;
- }
- lock_volumes();
- Dmsg0(150, "Again dir_find_next_append...\n");
+ }
+ Dmsg0(150, "Again dir_find_next_append...\n");
}
+ dev->clear_wait();
}
}
- return true;
+ if (dcr->haveVolCatInfo()) {
+ return true;
+ }
+ return dir_get_volume_info(dcr, VolumeName, GET_VOL_INFO_FOR_WRITE);
}
int DCR::check_volume_label(bool &ask, bool &autochanger)
{
int vol_label_status;
+
+ Enter(200);
+
+ set_ameta();
/*
* If we are writing to a stream device, ASSUME the volume label
* is correct.
*/
if (dev->has_cap(CAP_STREAM)) {
vol_label_status = VOL_OK;
- create_volume_label(dev, VolumeName, "Default", false /* not DVD */);
+ create_volume_header(dev, VolumeName, "Default", false);
dev->VolHdr.LabelType = PRE_LABEL;
} else {
- vol_label_status = read_dev_volume_label(this);
+ vol_label_status = dev->read_dev_volume_label(this);
}
if (job_canceled(jcr)) {
goto check_bail_out;
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.
VOLUME_CAT_INFO dcrVolCatInfo, devVolCatInfo;
char saveVolumeName[MAX_NAME_LENGTH];
- Dmsg2(150, "Vol NAME Error Have=%s, want=%s\n", dev->VolHdr.VolumeName, VolumeName);
+ Dmsg2(40, "Vol NAME Error Have=%s, want=%s\n", dev->VolHdr.VolumeName, VolumeName);
if (dev->is_volume_to_unload()) {
ask = true;
goto check_next_volume;
}
+#ifdef xxx
/* If not removable, Volume is broken */
if (!dev->is_removable()) {
- Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"),
- VolumeName, dev->print_name());
+ Jmsg3(jcr, M_WARNING, 0, _("Volume \"%s\" not loaded on %s device %s.\n"),
+ VolumeName, dev->print_type(), dev->print_name());
+ Dmsg3(40, "Volume \"%s\" not loaded on %s device %s.\n",
+ VolumeName, dev->print_type(), dev->print_name());
mark_volume_in_error();
goto check_next_volume;
}
+#endif
/*
* OK, we got a different volume mounted. First save the
/* Check if this is a valid Volume in the pool */
bstrncpy(saveVolumeName, VolumeName, sizeof(saveVolumeName));
bstrncpy(VolumeName, dev->VolHdr.VolumeName, sizeof(VolumeName));
- if (!dir_get_volume_info(this, GET_VOL_INFO_FOR_WRITE)) {
+ if (!dir_get_volume_info(this, VolumeName, GET_VOL_INFO_FOR_WRITE)) {
POOL_MEM vol_info_msg;
pm_strcpy(vol_info_msg, jcr->dir_bsock->msg); /* save error message */
/* Restore desired volume name, note device info out of sync */
/* This gets the info regardless of the Pool */
bstrncpy(VolumeName, dev->VolHdr.VolumeName, sizeof(VolumeName));
- if (autochanger && !dir_get_volume_info(this, GET_VOL_INFO_FOR_READ)) {
+ if (autochanger && !dir_get_volume_info(this, VolumeName, GET_VOL_INFO_FOR_READ)) {
/*
* If we get here, we know we cannot write on the Volume,
- * and we know that we cannot read it either, so it
+ * and we know that we cannot read it either, so it
* is not in the autochanger.
*/
mark_volume_not_inchanger();
dev->VolCatInfo = VolCatInfo; /* structure assignment */
Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
if (reserve_volume(this, dev->VolHdr.VolumeName) == NULL) {
- Jmsg2(jcr, M_WARNING, 0, _("Could not reserve volume %s on %s\n"),
- dev->VolHdr.VolumeName, dev->print_name());
+ if (!jcr->errmsg[0]) {
+ Jmsg3(jcr, M_WARNING, 0, _("Could not reserve volume %s on %s device %s\n"),
+ dev->VolHdr.VolumeName, dev->print_type(), dev->print_name());
+ } else {
+ Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+ }
ask = true;
+ dev->setVolCatInfo(false);
+ setVolCatInfo(false);
goto check_next_volume;
}
break; /* got a Volume */
* At this point, we assume we have a blank tape mounted.
*/
case VOL_IO_ERROR:
- if (dev->is_dvd()) {
- Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
- mark_volume_in_error();
- goto check_bail_out; /* we could not write on DVD */
- }
/* Fall through wanted */
case VOL_NO_LABEL:
switch (try_autolabel(true)) {
case try_default:
break;
}
-
/* NOTE! Fall-through wanted. */
case VOL_NO_MEDIA:
default:
ask = true;
/* Needed, so the medium can be changed */
if (dev->requires_mount()) {
- dev->close();
+ dev->close(this);
+ free_volume(dev);
}
goto check_next_volume;
}
+ Leave(200);
return check_ok;
check_next_volume:
+ dev->setVolCatInfo(false);
+ setVolCatInfo(false);
+ Leave(200);
return check_next_vol;
check_bail_out:
+ Leave(200);
return check_error;
check_read_volume:
+ Leave(200);
return check_read_vol;
}
bool DCR::is_suitable_volume_mounted()
{
+ bool ok;
+
/* Volume mounted? */
if (dev->VolHdr.VolumeName[0] == 0 || dev->swap_dev || dev->must_unload()) {
return false; /* no */
}
bstrncpy(VolumeName, dev->VolHdr.VolumeName, sizeof(VolumeName));
- return dir_get_volume_info(this, GET_VOL_INFO_FOR_WRITE);
+ ok = dir_get_volume_info(this, VolumeName, GET_VOL_INFO_FOR_WRITE);
+ if (!ok) {
+ Dmsg1(40, "dir_get_volume_info failed: %s", jcr->errmsg);
+ dev->set_wait();
+ }
+ return ok;
}
bool DCR::do_unload()
bool DCR::do_load(bool is_writing)
{
if (dev->must_load()) {
- Dmsg1(100, "Must load %s\n", dev->print_name());
+ Dmsg1(100, "Must load dev=%s\n", dev->print_name());
if (autoload_device(this, is_writing, NULL) > 0) {
dev->clear_load();
return true;
if (dev->vol) {
dev->vol->clear_swapping();
Dmsg1(100, "=== set in_use vol=%s\n", dev->vol->vol_name);
- dev->vol->set_in_use();
+ dev->vol->clear_in_use();
dev->VolHdr.VolumeName[0] = 0; /* don't yet have right Volume */
- }
- dev->swap_dev = NULL;
- }
-}
-
-
-/*
- * Check if the current position on the volume corresponds to
- * what is in the catalog.
- */
-bool DCR::is_eod_valid()
-{
- if (dev->is_dvd()) {
- char ed1[50], ed2[50];
- if (dev->VolCatInfo.VolCatBytes == dev->part_start + dev->part_size) {
- Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\""
- " part=%d size=%s\n"), VolumeName,
- dev->part, edit_uint64(dev->VolCatInfo.VolCatBytes,ed1));
} else {
- Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on DVD Volume \"%s\" because: "
- "The sizes do not match! Volume=%s Catalog=%s\n"),
- VolumeName,
- edit_uint64(dev->part_start + dev->part_size, ed1),
- edit_uint64(dev->VolCatInfo.VolCatBytes, ed2));
- mark_volume_in_error();
- return false;
+ Dmsg1(100, "No vol on dev=%s\n", dev->print_name());
}
- } else if (dev->is_tape()) {
- /*
- * Check if we are positioned on the tape at the same place
- * that the database says we should be.
- */
- 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 {
- Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on tape Volume \"%s\" because:\n"
- "The number of files mismatch! Volume=%u Catalog=%u\n"),
- VolumeName, dev->get_file(), dev->VolCatInfo.VolCatFiles);
- mark_volume_in_error();
- return false;
+ if (dev->swap_dev->vol) {
+ Dmsg2(100, "Vol=%s on dev=%s\n", dev->swap_dev->vol->vol_name,
+ dev->swap_dev->print_name());
}
- } else if (dev->is_file()) {
- char ed1[50], ed2[50];
- boffset_t pos;
- pos = dev->lseek(this, (boffset_t)0, SEEK_END);
- if (dev->VolCatInfo.VolCatBytes == (uint64_t)pos) {
- Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\""
- " size=%s\n"), VolumeName,
- edit_uint64(dev->VolCatInfo.VolCatBytes, ed1));
+ 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 {
+ if (dev->vol) {
+ Dmsg1(100, "No swap_dev set. dev->vol=%p\n", dev->vol);
} else {
- Jmsg(jcr, M_ERROR, 0, _("Bacula cannot write on disk Volume \"%s\" because: "
- "The sizes do not match! Volume=%s Catalog=%s\n"),
- VolumeName,
- edit_uint64(pos, ed1),
- edit_uint64(dev->VolCatInfo.VolCatBytes, ed2));
- mark_volume_in_error();
- return false;
+ Dmsg1(100, "No swap_dev set. dev->vol=%p\n", dev->vol);
}
}
- return true;
}
-
/*
* If permitted, we label the device, make sure we can do
* it by checking that the VolCatBytes is zero => not labeled,
DCR *dcr = this;
if (dev->poll && !dev->is_tape()) {
+ Dmsg0(100, "No autolabel because polling.\n");
return try_default; /* if polling, don't try to create new labels */
}
/* For a tape require it to be opened and read before labeling */
- if (!opened && dev->is_tape()) {
+ if (!opened && (dev->is_tape() || dev->is_null())) {
return try_default;
}
if (dev->has_cap(CAP_LABEL) && (VolCatInfo.VolCatBytes == 0 ||
(!dev->is_tape() && strcmp(VolCatInfo.VolCatStatus,
"Recycle") == 0))) {
- Dmsg0(150, "Create volume label\n");
+ Dmsg1(40, "Create new volume label vol=%s\n", VolumeName);
/* Create a new Volume label and write it to the device */
- if (!write_new_volume_label_to_dev(dcr, VolumeName,
- pool_name, false, /* no relabel */ false /* defer DVD label */)) {
- Dmsg2(150, "write_vol_label failed. vol=%s, pool=%s\n",
+ if (!dev->write_volume_label(dcr, VolumeName,
+ pool_name, false, /* no relabel */ false /* defer label */)) {
+ Dmsg2(100, "write_vol_label failed. vol=%s, pool=%s\n",
VolumeName, pool_name);
- if (opened) {
+ if (opened) {
mark_volume_in_error();
}
return try_next_vol;
/* Copy Director's info into the device info */
dev->VolCatInfo = VolCatInfo; /* structure assignment */
if (!dir_update_volume_info(dcr, true, true)) { /* indicate tape labeled */
+ Dmsg3(100, "Update_vol_info failed no autolabel Volume \"%s\" on %s device %s.\n",
+ VolumeName, dev->print_type(), dev->print_name());
return try_error;
}
- Jmsg(dcr->jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"),
- VolumeName, dev->print_name());
+ Jmsg(dcr->jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on %s device %s.\n"),
+ VolumeName, dev->print_type(), dev->print_name());
+ Dmsg3(100, "Labeled new Volume \"%s\" on %s device %s.\n",
+ VolumeName, dev->print_type(), dev->print_name());
return try_read_vol; /* read label we just wrote */
+ } else {
+ Dmsg4(40, "=== Cannot autolabel: cap_label=%d VolCatBytes=%lld is_tape=%d VolCatStatus=%s\n",
+ dev->has_cap(CAP_LABEL), VolCatInfo.VolCatBytes, dev->is_tape(),
+ VolCatInfo.VolCatStatus);
}
if (!dev->has_cap(CAP_LABEL) && VolCatInfo.VolCatBytes == 0) {
- Jmsg(jcr, M_WARNING, 0, _("Device %s not configured to autolabel Volumes.\n"),
- dev->print_name());
+ Jmsg(jcr, M_WARNING, 0, _("%s device %s not configured to autolabel Volumes.\n"),
+ dev->print_type(), dev->print_name());
}
+#ifdef xxx
/* If not removable, Volume is broken */
if (!dev->is_removable()) {
- Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"),
- VolumeName, dev->print_name());
+ Jmsg3(jcr, M_WARNING, 0, _("Volume \"%s\" not loaded on %s device %s.\n"),
+ VolumeName, dev->print_type(), dev->print_name());
+ Dmsg3(40, "Volume \"%s\" not loaded on %s device %s.\n",
+ VolumeName, dev->print_type(), dev->print_name());
+
mark_volume_in_error();
return try_next_vol;
}
+#endif
return try_default;
}
Jmsg(jcr, M_INFO, 0, _("Marking Volume \"%s\" in Error in Catalog.\n"),
VolumeName);
dev->VolCatInfo = VolCatInfo; /* structure assignment */
- bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus));
+ dev->setVolCatStatus("Error");
Dmsg0(150, "dir_update_vol_info. Set Error.\n");
dir_update_volume_info(this, false, false);
volume_unused(this);
{
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;
Jmsg0(jcr, M_ERROR, 0, _("Hey!!!!! WroteVol non-zero !!!!!\n"));
Pmsg0(190, "Hey!!!!! WroteVol non-zero !!!!!\n");
}
+
+ if (dev->is_open() && (!dev->is_tape() || !dev->has_cap(CAP_ALWAYSOPEN))) {
+ generate_plugin_event(jcr, bsdEventDeviceClose, this);
+ dev->close(this);
+ }
+
+ /* If we have not closed the device, then at least rewind the tape */
+ if (dev->is_open()) {
+ dev->offline_or_rewind(this);
+ }
+
/*
- * First erase all memory of the current volume
+ * Erase all memory of the current volume
*/
free_volume(dev);
dev->block_num = dev->file = 0;
dev->label_type = B_BACULA_LABEL;
VolumeName[0] = 0;
- if (dev->is_open() && (!dev->is_tape() || !dev->has_cap(CAP_ALWAYSOPEN))) {
- dev->close();
- }
-
- /* If we have not closed the device, then at least rewind the tape */
- if (dev->is_open()) {
- dev->offline_or_rewind();
- }
-// Dmsg0(50, "set_unload\n");
-// dev->set_unload();
Dmsg0(190, "release_volume\n");
}
/*
- * Insanity check
+ * Insanity check
*
* Check to see if the tape position as defined by the OS is
- * the same as our concept. If it is not,
+ * the same as our concept. If it is not,
* it means the user has probably manually rewound the tape.
* Note, we check only if num_writers == 0, but this code will
* also work fine for any number of writers. If num_writers > 0,
- * we probably should cancel all jobs using this device, or
+ * we probably should cancel all jobs using this device, or
* perhaps even abort the SD, or at a minimum, mark the tape
* in error. Another strategy with num_writers == 0, would be
* to rewind the tape and do a new eod() request.
if (dev->is_tape() && dev->num_writers == 0) {
int32_t file = dev->get_os_tape_file();
if (file >= 0 && file != (int32_t)dev->get_file()) {
- Jmsg(jcr, M_ERROR, 0, _("Invalid tape position on volume \"%s\""
- " on device %s. Expected %d, got %d\n"),
+ Jmsg(jcr, M_ERROR, 0, _("Invalid tape position on volume \"%s\""
+ " on device %s. Expected %d, got %d\n"),
dev->VolHdr.VolumeName, dev->print_name(), dev->get_file(), file);
- /*
+ /*
* If the current file is greater than zero, it means we probably
* have some bad count of EOF marks, so mark tape in error. Otherwise
* the operator might have moved the tape, so we just release it
* End Of Tape -- mount next Volume (if another specified)
*/
if (jcr->NumReadVolumes > 1 && jcr->CurReadVolume < jcr->NumReadVolumes) {
- dev->close();
+ dev->Lock();
+ dev->close(dcr);
+ dev->set_read();
+ dcr->set_reserved_for_read();
+ 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);
+ Jmsg3(jcr, M_FATAL, 0, _("Cannot open %s Dev=%s, Vol=%s for reading.\n"),
+ dev->print_type(), dev->print_name(), dcr->VolumeName);
+ jcr->setJobStatus(JS_FatalError); /* Jmsg is not working for *SystemJob* */
return false;
}
return true; /* next volume mounted */