*/
if (ok && lmr.PoolId == mr->PoolId) {
Dmsg2(050, "Vol=%s MediaId=%d purged.\n", lmr.VolumeName, (int)lmr.MediaId);
- mr = &lmr; /* struct copy */
+ memcpy(mr, &lmr, sizeof(lmr));
break; /* got a volume */
}
/*
STORE *store = jcr->wstore;
bstrncpy(mr->MediaType, store->media_type, sizeof(mr->MediaType));
- Dmsg3(050, "find_next_vol_for_append: JobId=%u PoolId=%d, MediaType=%s\n",
+ Dmsg3(100, "find_next_vol_for_append: JobId=%u PoolId=%d, MediaType=%s\n",
(uint32_t)jcr->JobId, (int)mr->PoolId, mr->MediaType);
/*
* If we are using an Autochanger, restrict Volume
* 2. Try finding a recycled volume
*/
ok = find_recycled_volume(jcr, InChanger, mr);
- Dmsg2(050, "find_recycled_volume ok=%d FW=%d\n", ok, mr->FirstWritten);
+ Dmsg2(150, "find_recycled_volume ok=%d FW=%d\n", ok, mr->FirstWritten);
if (!ok) {
/*
* 3. Try recycling any purged volume
*/
if (prune) {
Dmsg0(150, "Call prune_volumes\n");
- ok = prune_volumes(jcr, InChanger, mr);
+ prune_volumes(jcr, InChanger, mr);
}
- if (!ok) {
- ok = recycle_oldest_purged_volume(jcr, InChanger, mr);
- if (!ok && create) {
- Dmsg4(050, "after prune volumes_vol ok=%d index=%d InChanger=%d Vstat=%s\n",
- ok, index, InChanger, mr->VolStatus);
- /*
- * 5. Try pulling a volume from the Scratch pool
- */
- ok = get_scratch_volume(jcr, InChanger, mr);
- Dmsg4(050, "after get scratch volume ok=%d index=%d InChanger=%d Vstat=%s\n",
- ok, index, InChanger, mr->VolStatus);
- }
- /*
- * If we are using an Autochanger and have not found
- * a volume, retry looking for any volume.
- */
- if (!ok && InChanger) {
- InChanger = false;
- continue; /* retry again accepting any volume */
- }
- }
- }
+ ok = recycle_oldest_purged_volume(jcr, InChanger, mr);
+ if (!ok && create) {
+ Dmsg4(050, "after prune volumes_vol ok=%d index=%d InChanger=%d Vstat=%s\n",
+ ok, index, InChanger, mr->VolStatus);
+ /*
+ * 5. Try pulling a volume from the Scratch pool
+ */
+ ok = get_scratch_volume(jcr, InChanger, mr);
+ }
+ /*
+ * If we are using an Autochanger and have not found
+ * a volume, retry looking for any volume.
+ */
+ if (InChanger) {
+ InChanger = false;
+ if (!ok) {
+ continue; /* retry again accepting any volume */
+ }
+ }
+ }
}
*/
if (!ok && (jcr->pool->purge_oldest_volume ||
jcr->pool->recycle_oldest_volume)) {
- Dmsg2(050, "No next volume found. PurgeOldest=%d\n RecyleOldest=%d",
+ Dmsg2(200, "No next volume found. PurgeOldest=%d\n RecyleOldest=%d",
jcr->pool->purge_oldest_volume, jcr->pool->recycle_oldest_volume);
/* Find oldest volume to recycle */
ok = db_find_next_volume(jcr, jcr->db, -1, InChanger, mr);
- Dmsg1(050, "Find oldest=%d\n", ok);
+ Dmsg1(400, "Find oldest=%d\n", ok);
if (ok && prune) {
UAContext *ua;
- Dmsg0(050, "Try purge.\n");
+ Dmsg0(400, "Try purge.\n");
/*
* 7. Try to purging oldest volume only if not UA calling us.
*/
free_ua_context(ua);
if (ok) {
ok = recycle_volume(jcr, mr);
- Dmsg1(050, "Recycle after purge oldest=%d\n", ok);
+ Dmsg1(400, "Recycle after purge oldest=%d\n", ok);
}
}
}
}
- Dmsg2(050, "VolJobs=%d FirstWritten=%d\n", mr->VolJobs, mr->FirstWritten);
+ Dmsg2(100, "VolJobs=%d FirstWritten=%d\n", mr->VolJobs, mr->FirstWritten);
if (ok) {
/* If we can use the volume, check if it is expired */
if (has_volume_expired(jcr, mr)) {
break;
} /* end for loop */
db_unlock(jcr->db);
- Dmsg1(050, "return ok=%d find_next_vol\n", ok);
+ Dmsg1(150, "return ok=%d find_next_vol\n", ok);
return ok;
}
}
while (dir->recv() >= 0) {
- Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
+ Dmsg1(200, "filed<dird: bootstrap: %s", dir->msg);
fputs(dir->msg, bs);
}
fclose(bs);
jcr->wait_time = time(NULL);
}
}
- Dmsg3(100, "jid=%u leave set_jcr_job_status=%c set=%c\n", (uint32_t)jcr->JobId,
+ Dmsg3(200, "jid=%u leave set_jcr_job_status=%c set=%c\n", (uint32_t)jcr->JobId,
jcr->JobStatus, JobStatus);
}
dev->num_writers, jcr->JobId);
goto get_out;
}
+ dev->clear_unload();
/* Find next Volume, if any */
vol = jcr->VolList;
/* Volume info is always needed because of VolParts */
Dmsg1(150, "dir_get_volume_info vol=%s\n", dcr->VolumeName);
if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
+ Dmsg2(150, "dir_get_vol_info failed for vol=%s: %s\n",
+ dcr->VolumeName, jcr->errmsg);
Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
}
dev->set_load(); /* set to load volume */
switch (vol_label_status) {
case VOL_OK:
ok = true;
- memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
+ dev->VolCatInfo = dcr->VolCatInfo; /* structure assignment */
break; /* got it */
case VOL_IO_ERROR:
/*
}
goto default_path;
case VOL_NAME_ERROR:
- if (tape_initially_mounted) {
- tape_initially_mounted = false;
- goto default_path;
- }
- /* If polling and got a previous bad name, ignore it */
- if (dev->poll && strcmp(dev->BadVolName, dev->VolHdr.VolumeName) == 0) {
+ if (dev->is_volume_to_unload()) {
goto default_path;
- } else {
- bstrncpy(dev->BadVolName, dev->VolHdr.VolumeName, sizeof(dev->BadVolName));
}
+// if (tape_initially_mounted) {
+ tape_initially_mounted = false;
+// goto default_path;
+// }
+ dev->set_unload(); /* force unload of unwanted tape */
if (!unload_autochanger(dcr, -1)) {
/* at least free the device so we can re-open with correct volume */
dev->close();
}
+ dev->set_load();
+ ASSERT(0);
/* Fall through */
default:
Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
}
/* Try closing and re-opening */
dev->close();
- dev->clear_unload();
if (dev->open(dcr, OPEN_READ_ONLY) >= 0) {
continue;
}
} /* end switch */
break;
} /* end for loop */
+
if (!ok) {
Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s for reading.\n"),
dev->print_name());
free_volume(dev); /* Free any volume associated with this drive */
free_pool_memory(changer);
}
- dev->clear_unload();
+ if (ok) {
+ dev->clear_unload();
+ }
return ok;
}
Dmsg2(100, "Slot %d unloaded %s\n", dev->get_slot(), dev->print_name());
dev->set_slot(0); /* nothing loaded */
}
- dev->clear_unload();
+ if (ok) {
+ dev->clear_unload();
+ }
unlock_changer(dcr);
dev->dunlock();
} else {
d_open = ::open;
d_close = ::close;
- d_ioctl = win32_ioctl; /* dummy function */
- d_write = win32_write; /* win32 read/write are not POSIX */
+ d_ioctl = win32_ioctl; /* dummy function */
+ d_write = win32_write; /* win32 read/write are not POSIX */
d_read = win32_read;
}
#else /* POSIX / UNIX Interface */
- if (is_vtape()) { /* test backend */
- d_open = vtape_open; /* vtape isn't available for WIN32 or FreeBSD */
+ if (is_vtape()) { /* test backend */
+ d_open = vtape_open; /* vtape isn't available for WIN32 or FreeBSD */
d_write = vtape_write;
d_close = vtape_close;
d_ioctl = vtape_ioctl;
d_read = vtape_read;
- } else { /* tape and file are using normal io */
+ } else { /* tape and file are using normal io */
d_open = ::open;
d_write = ::write;
d_close = ::close;
{
struct mtop mt_com;
int stat;
- Dmsg0(129, "weof_dev\n");
+ Dmsg1(129, "=== weof_dev=%s\n", print_name());
if (!is_open()) {
dev_errno = EBADF;
}
+/*
+ * Set to unload the current volume in the drive
+ */
+void DEVICE::set_unload()
+{
+ if (!m_unload && VolHdr.VolumeName[0] != 0) {
+ m_unload = true;
+ memcpy(UnloadVolName, VolHdr.VolumeName, sizeof(UnloadVolName));
+ }
+}
+
+
/*
* Clear volume header
*/
dev->rem_wait_sec = dev->wait_sec;
dev->num_wait = 0;
dev->poll = false;
- dev->BadVolName[0] = 0;
jcr->min_wait = 60 * 60;
jcr->max_wait = 24 * 60 * 60;
char pool_name[MAX_NAME_LENGTH]; /* pool name */
char pool_type[MAX_NAME_LENGTH]; /* pool type */
- /* Device wait times ***FIXME*** look at durations */
- char BadVolName[MAX_NAME_LENGTH]; /* Last wrong Volume mounted */
+ char UnloadVolName[MAX_NAME_LENGTH]; /* Last wrong Volume mounted */
bool poll; /* set to poll Volume */
+ /* Device wait times ***FIXME*** look at durations */
int min_wait;
int max_wait;
int max_num_wait;
void set_part_spooled(int val) { if (val) state |= ST_PART_SPOOLED; \
else state &= ~ST_PART_SPOOLED;
};
- void set_unload() { m_unload = true; };
+ bool is_volume_to_unload() const { \
+ return m_unload && strcmp(VolHdr.VolumeName, UnloadVolName) == 0; };
void set_load() { m_load = true; };
void inc_reserved() { m_num_reserved++; }
void set_mounted(int val) { if (val) state |= ST_MOUNTED; \
void clear_media() { state &= ~ST_MEDIA; };
void clear_short_block() { state &= ~ST_SHORT; };
void clear_freespace_ok() { state &= ~ST_FREESPACE_OK; };
- void clear_unload() { m_unload = false; };
+ void clear_unload() { m_unload = false; UnloadVolName[0] = 0; };
void clear_load() { m_load = false; };
char *bstrerror(void) { return errmsg; };
char *print_errmsg() { return errmsg; };
int32_t get_slot() const { return m_slot; };
-
+ void set_unload(); /* in dev.c */
void clear_volhdr(); /* in dev.c */
void close(); /* in dev.c */
void close_part(DCR *dcr); /* in dev.c */
}
free_record(record); /* finished reading Volume record */
+ if (!dev->is_volume_to_unload()) {
+ dev->clear_unload();
+ }
+
if (!ok) {
if (forge_on || jcr->ignore_label_errors) {
dev->set_labeled(); /* set has Bacula label */
}
dev->set_labeled(); /* set has Bacula label */
- Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
- Dmsg2(100, "=== dcr->dev=%p dev=%p\n", dcr->dev, dev);
- if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
- Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
- dev->VolHdr.VolumeName, dev->print_name());
- stat = VOL_NAME_ERROR;
- goto bail_out;
- }
- Dmsg2(100, "=== dcr->dev=%p dev=%p\n", dcr->dev, dev);
/* Compare Volume Names */
Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName);
}
Dmsg0(150, "return VOL_NAME_ERROR\n");
stat = VOL_NAME_ERROR;
- volume_unused(dcr); /* mark volume "released" */
goto bail_out;
}
- Dmsg1(130, "Copy vol_name=%s\n", dev->VolHdr.VolumeName);
+
if (debug_level >= 10) {
dump_volume_label(dev);
stat = read_ansi_ibm_label(dcr);
/* If we want a label and didn't find it, return error */
if (stat != VOL_OK) {
- volume_unused(dcr); /* mark volume "released" */
goto bail_out;
}
}
}
+
+ Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName);
+ if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) {
+ Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"),
+ dev->VolHdr.VolumeName, dev->print_name());
+ stat = VOL_NAME_ERROR;
+ goto bail_out;
+ }
+
empty_block(block);
return VOL_OK;
}
do_swapping(true /*writing*/);
- if (!find_a_volume()) {
+ if (retry < 2 && !find_a_volume()) {
goto no_lock_bail_out;
}
* we will fail, recurse and ask the operator the next time.
*/
if (!dev->must_unload() && dev->is_tape() && dev->has_cap(CAP_AUTOMOUNT)) {
- Dmsg0(150, "(1)Ask=0\n");
+ Dmsg0(250, "(1)Ask=0\n");
ask = false; /* don't ask SYSOP this time */
}
/* Don't ask if not removable */
if (!dev->is_removable()) {
- Dmsg0(150, "(2)Ask=0\n");
+ Dmsg0(250, "(2)Ask=0\n");
ask = false;
}
- Dmsg2(150, "Ask=%d autochanger=%d\n", ask, autochanger);
+ Dmsg2(250, "Ask=%d autochanger=%d\n", ask, autochanger);
if (ask) {
unlock_volumes();
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.
+ */
bool DCR::find_a_volume()
{
DCR *dcr = this;
VOLUME_CAT_INFO dcrVolCatInfo, devVolCatInfo;
char saveVolumeName[MAX_NAME_LENGTH];
+ Dmsg1(150, "Vol NAME Error Name=%s\n", VolumeName);
+ if (dev->is_volume_to_unload()) {
+ ask = true;
+ goto check_next_volume;
+ }
+
/* If not removable, Volume is broken */
if (!dev->is_removable()) {
Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"),
goto check_next_volume;
}
- Dmsg1(150, "Vol NAME Error Name=%s\n", VolumeName);
- /* If polling and got a previous bad name, ignore it */
- if (dev->poll && strcmp(dev->BadVolName, dev->VolHdr.VolumeName) == 0) {
- ask = true;
- Dmsg1(200, "Vol Name error supress due to poll. Name=%s\n", VolumeName);
- goto check_next_volume;
- }
/*
* OK, we got a different volume mounted. First save the
* requested Volume info (dcr) structure, then query if
mark_volume_not_inchanger();
}
dev->VolCatInfo = devVolCatInfo; /* structure assignment */
- bstrncpy(dev->BadVolName, dev->VolHdr.VolumeName, sizeof(dev->BadVolName));
+ dev->set_unload(); /* unload this volume */
Jmsg(jcr, M_WARNING, 0, _("Director wanted Volume \"%s\".\n"
" Current Volume \"%s\" not acceptable because:\n"
" %s"),
*/
Dmsg1(150, "Got new Volume name=%s\n", VolumeName);
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());
+ ask = true;
+ goto check_next_volume;
+ }
break; /* got a Volume */
/*
* At this point, we assume we have a blank tape mounted.
void DCR::do_swapping(bool is_writing)
{
if (dev->must_unload()) {
- Dmsg1(100, "swapping: unloading %s\n", dev->print_name());
+ Dmsg1(100, "must_unload release %s\n", dev->print_name());
release_volume();
- dev->clear_unload();
}
/*
* See if we are asked to swap the Volume from another device
dev->swap_dev = NULL;
}
if (dev->must_load()) {
- Dmsg1(100, "swapping: must load %s\n", dev->print_name());
+ Dmsg1(100, "Must load %s\n", dev->print_name());
if (autoload_device(this, is_writing, NULL) > 0) {
dev->clear_load();
}
if (dev->is_open()) {
dev->offline_or_rewind();
}
- Dmsg0(50, "set_unload\n");
- dev->set_unload();
+// Dmsg0(50, "set_unload\n");
+// dev->set_unload();
Dmsg0(190, "release_volume\n");
}
}
Dmsg2(dbglvl, "reserve_vol free vol=%s at %p\n", vol->vol_name, vol->vol_name);
free_volume(dev);
-// volume_unused(dcr);
Dmsg0(50, "set_unload\n");
dev->set_unload(); /* have to unload current volume */
debug_list_volumes("reserve_vol free");
Dmsg3(dbglvl, "==== Swap vol=%s from dev=%s to %s\n",
VolumeName, vol->dev->print_name(), dev->print_name());
free_volume(dev); /* free any volume attached to our drive */
-// volume_unused(dcr);
Dmsg0(50, "set_unload\n");
dev->set_unload(); /* Unload any volume that is on our drive */
dcr->dev = vol->dev; /* temp point to other dev */
case MTFSF: /* Forward space over mt_count filemarks. */
do {
- result = fsf();
+ result = fsf();
} while (--count > 0 && result == 0);
break;
case MTBSF: /* Backward space over mt_count filemarks. */
do {
- result = bsf();
+ result = bsf();
} while (--count > 0 && result == 0);
break;
case MTWEOF: /* Write mt_count filemarks. */
do {
- result = weof();
+ result = weof();
} while (result == 0 && --count > 0);
break;
case MTEOM:/* Go to the end of the recorded media (for appending files). */
while (next_FM) {
- lseek(fd, next_FM, SEEK_SET);
- if (read_fm(VT_READ_EOF)) {
- current_file++;
- }
+ lseek(fd, next_FM, SEEK_SET);
+ if (read_fm(VT_READ_EOF)) {
+ current_file++;
+ }
}
off_t l;
while (::read(fd, &l, sizeof(l)) > 0) {
- if (l) {
- lseek(fd, l, SEEK_CUR);
- } else {
- ASSERT(0);
- }
- Dmsg0(dbglevel, "skip 1 block\n");
+ if (l) {
+ lseek(fd, l, SEEK_CUR);
+ } else {
+ ASSERT(0);
+ }
+ Dmsg0(dbglevel, "skip 1 block\n");
}
current_block = -1;
atEOF = false;
ssize_t nb;
Dmsg3(dbglevel*2, "write len=%i %i:%i\n",
- count, current_file,current_block);
+ count, current_file,current_block);
if (atEOT) {
Dmsg0(dbglevel, "write nothing, EOT !\n");
atBOT = false;
Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
- if (next_FM > cur_FM) { /* not the last file */
+ if (next_FM > cur_FM) { /* not the last file */
lseek(fd, next_FM, SEEK_SET);
read_fm(VT_READ_EOF);
current_file++;
atEOF = true;
ret = 0;
- } else if (atEOF) { /* last file mark */
+ } else if (atEOF) { /* last file mark */
current_block=-1;
errno = EIO;
atEOF = false;
atEOD = true;
- } else { /* last file, but no at the end */
+ } else { /* last file, but no at the end */
fsr(100000);
Dmsg0(dbglevel, "Try to FSF after EOT\n");
if (read_all == VT_READ_EOF) {
::read(fd, &c, sizeof(c));
if (c != 0) {
- lseek(fd, cur_FM, SEEK_SET);
- return false;
+ lseek(fd, cur_FM, SEEK_SET);
+ return false;
}
}
current_block=0;
Dmsg3(dbglevel, "Read FM cur=%lli last=%lli next=%lli\n",
- cur_FM, last_FM, next_FM);
+ cur_FM, last_FM, next_FM);
return (ret == sizeof(next_FM));
}
off_t where=0;
uint32_t s;
Dmsg4(dbglevel, "fsr %i:%i EOF=%i c=%i\n",
- current_file,current_block,atEOF,count);
+ current_file,current_block,atEOF,count);
check_eof();
current_file, current_block, nb,s);
errno = EIO;
ret = -1;
- if (next_FM) {
+ if (next_FM) {
current_file++;
- read_fm(VT_SKIP_EOF);
- }
+ read_fm(VT_SKIP_EOF);
+ }
atEOF = true; /* stop the loop */
}
}
lseek(fd, cur_FM, SEEK_SET);
atEOF = false;
if (current_file > 0) {
- current_file--;
+ current_file--;
}
current_block=-1;
errno = EIO;
/*
* First, go to cur/last_FM and read all blocks to find the good one
*/
- if (cur_FM == orig) { /* already just before EOF */
+ if (cur_FM == orig) { /* already just before EOF */
lseek(fd, last_FM, SEEK_SET);
} else {
do {
if (!atEOF) {
- last2 = last; /* keep track of the 2 last blocs position */
+ last2 = last; /* keep track of the 2 last blocs position */
last = lseek(fd, 0, SEEK_CUR);
last_f = current_file;
last_b = current_block;
/* reading size of data */
nb = ::read(fd, &s, sizeof(uint32_t));
if (nb <= 0) {
- atEOF = true; /* TODO: check this */
+ atEOF = true; /* TODO: check this */
return 0;
}
if (!s) { /* EOF */
atEOF = true;
if (read_fm(VT_SKIP_EOF)) {
- current_file++;
+ current_file++;
}
return 0;
current_block = -1;
Dmsg0(dbglevel, "EOT during reading\n");
return -1;
- } /* read ok */
+ } /* read ok */
if (current_block >= 0) {
current_block++;
struct stat statp;
if (stat(pathname, &statp) != 0) {
+ fd = -1;
Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
if (uflags & O_NONBLOCK) {
online = false;
/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-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.
#undef VERSION
#define VERSION "2.5.1"
-#define BDATE "22 June 2008"
-#define LSMDATE "22Jun08"
+#define BDATE "27 June 2008"
+#define LSMDATE "27Jun08"
#define PROG_COPYRIGHT "Copyright (C) %d-2008 Free Software Foundation Europe e.V.\n"
#define BYEAR "2008" /* year for copyright messages in progs */
General:
+27Jun08
+kes Generally clean up the manual tape loading code. The main
+ conceptial change is that when a volume is marked to be unloaded,
+ its volume name is retained, and it is only marked as unloaded
+ when either the autoloader says it is unloaded or another tape
+ is read on that drive.
25Jun08
kes Add debug code and refactor subroutine in stored/mount.c
kes Fix format problem in bscan output reported in bug #1105.