" VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%" lld " VolMounts=%u"
" VolErrors=%u VolWrites=%u MaxVolBytes=%" lld " EndTime=%d VolStatus=%10s"
" Slot=%d relabel=%d InChanger=%d VolReadTime=%" lld " VolWriteTime=%" lld
- " VolParts=%u\n";
+ " VolFirstWritten=%" lld " VolParts=%u\n";
static char Create_job_media[] = "CatReq Job=%127s CreateJobMedia "
" FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u "
POOLMEM *omsg;
POOL_DBR pr;
uint32_t Stripe;
+ utime_t VolFirstWritten;
memset(&mr, 0, sizeof(mr));
memset(&sdmr, 0, sizeof(sdmr));
&sdmr.VolJobs, &sdmr.VolFiles, &sdmr.VolBlocks, &sdmr.VolBytes,
&sdmr.VolMounts, &sdmr.VolErrors, &sdmr.VolWrites, &sdmr.MaxVolBytes,
&sdmr.LastWritten, &sdmr.VolStatus, &sdmr.Slot, &label, &sdmr.InChanger,
- &sdmr.VolReadTime, &sdmr.VolWriteTime, &sdmr.VolParts) == 18) {
+ &sdmr.VolReadTime, &sdmr.VolWriteTime, &VolFirstWritten,
+ &sdmr.VolParts) == 19) {
db_lock(jcr->db);
Dmsg3(400, "Update media %s oldStat=%s newStat=%s\n", sdmr.VolumeName,
}
/* Set first written time if this is first job */
if (mr.FirstWritten == 0) {
- mr.FirstWritten = jcr->start_time; /* use Job start time as first write */
+ if (VolFirstWritten == 0) {
+ mr.FirstWritten = jcr->start_time; /* use Job start time as first write */
+ } else {
+ mr.FirstWritten = VolFirstWritten;
+ }
mr.set_first_written = true;
}
/* If we just labeled the tape set time */
" VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolMounts=%u"
" VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%d VolStatus=%s"
" Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
- " VolParts=%u\n";
+ " VolFirstWritten=%s VolParts=%u\n";
static char Create_job_media[] = "CatReq Job=%s CreateJobMedia"
" FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u"
" StartBlock=%u EndBlock=%u Copy=%d Strip=%d\n";
BSOCK *dir = jcr->dir_bsock;
DEVICE *dev = dcr->dev;
time_t LastWritten = time(NULL);
- char ed1[50], ed2[50], ed3[50], ed4[50];
+ char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
int InChanger;
POOL_MEM VolumeName;
InChanger, /* bool in structure */
edit_uint64(vol->VolReadTime, ed3),
edit_uint64(vol->VolWriteTime, ed4),
+ edit_uint64(vol->VolFirstWritten, ed5),
vol->VolCatParts);
Dmsg1(100, ">dird: %s", dir->msg);
POOLMEM *changer;
if (!dev->is_autochanger()) {
- Dmsg0(200, "== NOT AUTOCHANGER ==\n");
+ Dmsg1(200, "Device %s is not an autochanger\n", dev->print_name());
return 0;
}
slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
errno = 0;
stat = 0;
do {
- if ((retry > 0 && stat == -1 && errno == EBUSY) || retry > 10) {
+ if (retry > 0 && stat == -1 && errno == EBUSY) {
berrno be;
- Dmsg4(100, "===== read retry=%d stat=%d errno=%d: ERR=%s\n",
+ Dmsg4(100, "===== write retry=%d stat=%d errno=%d: ERR=%s\n",
retry, stat, errno, be.strerror());
- bmicrosleep(0, 100000); /* pause a bit if busy or lots of errors */
+ bmicrosleep(5, 0); /* pause a bit if busy or lots of errors */
dev->clrerror(-1);
}
if (dev->is_tape()) {
} else {
stat = write(dev->fd, block->buf, (size_t)wlen);
}
- } while (stat == -1 && (errno == EBUSY || errno == EIO) && retry++ < 30);
+ } while (stat == -1 && (errno == EBUSY || errno == EIO) && retry++ < 3);
#ifdef DEBUG_BLOCK_ZEROING
if (bp[0] == 0 && bp[1] == 0 && bp[2] == 0 && block->buf[12] == 0) {
errno = 0;
stat = 0;
do {
- if ((retry > 0 && stat == -1 && errno == EBUSY) || retry > 10) {
+ if ((retry > 0 && stat == -1 && errno == EBUSY)) {
berrno be;
- Dmsg4(100, "===== write retry=%d stat=%d errno=%d: ERR=%s\n",
+ Dmsg4(100, "===== read retry=%d stat=%d errno=%d: ERR=%s\n",
retry, stat, errno, be.strerror());
- bmicrosleep(0, 100000); /* pause a bit if busy or lots of errors */
+ bmicrosleep(10, 0); /* pause a bit if busy or lots of errors */
dev->clrerror(-1);
}
if (dev->is_tape()) {
} else {
stat = read(dev->fd, block->buf, (size_t)block->buf_len);
}
- } while (stat == -1 && (errno == EBUSY || errno == EINTR || errno == EIO) && retry++ < 30);
+ } while (stat == -1 && (errno == EBUSY || errno == EINTR || errno == EIO) && retry++ < 3);
if (stat < 0) {
berrno be;
dev->clrerror(-1);
Dmsg1(200, "Read device got: ERR=%s\n", be.strerror());
block->read_len = 0;
- Mmsg4(dev->errmsg, _("Read error at file:blk %u:%u on device %s. ERR=%s.\n"),
- dev->file, dev->block_num, dev->print_name(), be.strerror());
+ Mmsg5(dev->errmsg, _("Read error on fd=%d at file:blk %u:%u on device %s. ERR=%s.\n"),
+ dev->fd, dev->file, dev->block_num, dev->print_name(), be.strerror());
Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
if (dev->at_eof()) { /* EOF just seen? */
dev->set_eot(); /* yes, error => EOT */
}
}
dev->rewind(dcr);
- write_new_volume_label_to_dev(dcr, cmd, "Default", true /* label dvd now */);
+ write_new_volume_label_to_dev(dcr, cmd, "Default", false,/*no relabel*/ true /* label dvd now */);
Pmsg1(-1, _("Wrote Volume label for volume \"%s\".\n"), cmd);
}
void DEVICE::open_tape_device(DCR *dcr, int omode)
{
file_size = 0;
- int timeout;
- int nonblocking = O_NONBLOCK;
- Dmsg0(29, "open dev: device is tape\n");
+ int timeout = max_open_wait;
+ struct mtop mt_com;
+ utime_t start_time = time(NULL);
+ Dmsg0(29, "Open dev: device is tape\n");
get_autochanger_loaded_slot(dcr);
set_mode(omode);
- timeout = max_open_wait;
+ if (timeout < 1) {
+ timeout = 1;
+ }
errno = 0;
if (is_fifo() && timeout) {
/* Set open timer */
tid = start_thread_timer(pthread_self(), timeout);
}
/* If busy retry each second for max_open_wait seconds */
- Dmsg3(100, "Try open %s mode=%s nonblocking=%d\n", print_name(),
- mode_to_str(omode), nonblocking);
+ Dmsg2(100, "Try open %s mode=%s\n", print_name(), mode_to_str(omode));
/* Use system open() */
-
#if defined(HAVE_WIN32)
if ((fd = tape_open(dev_name, mode)) < 0) {
- berrno be;
dev_errno = errno;
-
- Mmsg2(errmsg, _("Unable to open device %s: ERR=%s\n"),
- print_name(), be.strerror(dev_errno));
- Jmsg0(dcr->jcr, M_FATAL, 0, errmsg);
}
#else
- while ((fd = ::open(dev_name, mode+nonblocking)) < 0) {
- berrno be;
- dev_errno = errno;
- Dmsg5(050, "Open omode=%d mode=%x nonblock=%d error errno=%d ERR=%s\n",
- omode, mode, nonblocking, errno, be.strerror());
- if (dev_errno == EINTR || dev_errno == EAGAIN) {
- Dmsg0(100, "Continue open\n");
- continue;
- }
- /* Busy wait for specified time (default = 5 mins) */
- if (dev_errno == EBUSY && timeout-- > 0) {
- Dmsg2(100, "Device %s busy. ERR=%s\n", print_name(), be.strerror());
- bmicrosleep(1, 0);
- continue;
+ for ( ;; ) {
+ fd = ::open(dev_name, mode);
+ if (fd < 0) {
+ berrno be;
+ dev_errno = errno;
+ Dmsg5(050, "Open error on %s omode=%d mode=%x errno=%d: ERR=%s\n",
+ print_name(), omode, mode, errno, be.strerror());
+ } else {
+ /* Tape open, now rewind it */
+ mt_com.mt_op = MTREW;
+ mt_com.mt_count = 1;
+ if (tape_ioctl(fd, MTIOCTOP, (char *)&mt_com) < 0) {
+ berrno be;
+ dev_errno = errno; /* set error status from rewind */
+ ::close(fd);
+ clear_opened();
+ Dmsg2(100, "Rewind error on %s close: ERR=%s\n", print_name(),
+ be.strerror(dev_errno));
+ } else {
+ dev_errno = 0;
+ set_os_device_parameters(this); /* do system dependent stuff */
+ break; /* Successfully opened and rewound */
+ }
}
- Mmsg2(errmsg, _("Unable to open device %s: ERR=%s\n"),
- print_name(), be.strerror(dev_errno));
- /* Stop any open timer we set */
- if (tid) {
- stop_thread_timer(tid);
- tid = 0;
+ bmicrosleep(5, 0);
+ /* Exceed wait time ? */
+ if (time(NULL) - start_time >= max_open_wait) {
+ break; /* yes, get out */
}
- Jmsg0(dcr->jcr, M_FATAL, 0, errmsg);
- break;
}
#endif
- if (this->is_open()) {
- openmode = omode; /* save open mode */
- set_blocking();
- Dmsg2(100, "openmode=%d %s\n", openmode, mode_to_str(openmode));
- dev_errno = 0;
- set_os_device_parameters(this); /* do system dependent stuff */
- } else {
- clear_opened();
+ if (!is_open()) {
+ berrno be;
+ Mmsg2(errmsg, _("Unable to open device %s: ERR=%s\n"),
+ print_name(), be.strerror(dev_errno));
+ Dmsg1(100, "%s", errmsg);
}
/* Stop any open() timer we started */
Dmsg1(29, "open dev: tape %d opened\n", fd);
}
-void DEVICE::set_blocking()
-{
- int oflags;
- /* Try to reset blocking */
-#ifdef xxx
- if ((oflags = fcntl(fd, F_GETFL, 0)) < 0 ||
- fcntl(fd, F_SETFL, oflags & ~O_NONBLOCK) < 0) {
- berrno be;
- ::close(fd); /* use system close() */
- fd = ::open(dev_name, mode);
- Dmsg2(100, "fcntl error. ERR=%s. Close-reopen fd=%d\n", be.strerror(), fd);
- }
-#endif
- oflags = fcntl(fd, F_GETFL, 0);
- if (oflags > 0 && (oflags & O_NONBLOCK)) {
- fcntl(fd, F_SETFL, oflags & ~O_NONBLOCK);
- }
-}
/*
* Open a file device
msg = "MTSETBLK";
break;
#endif
+#ifdef MTSETDRVBUFFER
+ case MTSETDRVBUFFER:
+ msg = "MTSETDRVBUFFER";
+ break;
+#endif
+#ifdef MTRESET
+ case MTRESET:
+ msg = "MTRESET";
+ break;
+#endif
+
#ifdef MTSETBSIZ
case MTSETBSIZ:
msg = "MTSETBSIZ";
edit_mount_codes(ocmd, icmd);
- Dmsg2(000, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted());
+ Dmsg2(100, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted());
if (dotimeout) {
/* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
{
#if defined(HAVE_LINUX_OS) || defined(HAVE_WIN32)
struct mtop mt_com;
+
+#if defined(MTRESET)
+ mt_com.mt_op = MTRESET;
+ mt_com.mt_count = 0;
+ if (tape_ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
+ dev->clrerror(MTRESET);
+ }
+#endif
+#if defined(MTSETBLK)
if (dev->min_block_size == dev->max_block_size &&
dev->min_block_size == 0) { /* variable block mode */
mt_com.mt_op = MTSETBLK;
if (tape_ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
dev->clrerror(MTSETBLK);
}
+ Dmsg0(100, "Set block size to 0\n");
+ }
+#endif
+#if defined(MTSETDRVBUFFER)
+ if (getpid() == 0) { /* Only root can do this */
mt_com.mt_op = MTSETDRVBUFFER;
mt_com.mt_count = MT_ST_CLEARBOOLEANS;
if (!dev->has_cap(CAP_TWOEOF)) {
mt_com.mt_count |= MT_ST_FAST_MTEOM;
}
if (tape_ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
- dev->clrerror(MTSETBLK);
+ dev->clrerror(MTSETDRVBUFFER);
}
}
+#endif
return;
#endif
void clear_short_block() { state &= ~ST_SHORT; };
void clear_freespace_ok() { state &= ~ST_FREESPACE_OK; };
char *bstrerror(void) { return errmsg; };
+ char *print_errmsg() { return errmsg; };
void block(int why); /* in dev.c */
void unblock(); /* in dev.c */
void open_tape_device(DCR *dcr, int omode); /* in dev.c */
void open_file_device(DCR *dcr, int omode); /* in dev.c */
void open_dvd_device(DCR *dcr, int omode); /* in dev.c */
- void set_blocking(); /* in dev.c */
-
};
/* Note, these return int not bool! */
DEVICE *dev = dcr->dev;
int label_status;
int mode;
- const char *volname = (relabel == 0) ? newname : oldname;
+ const char *volname = (relabel == 1) ? oldname : newname;
char ed1[50];
steal_device_lock(dev, &hold, BST_WRITING_LABEL);
Dmsg1(100, "Stole device %s lock, writing label.\n", dev->print_name());
- Dmsg0(90, "try_autoload_device - looking for volume_info\n");
- if (relabel && dev->is_dvd()) {
- /* Fake at least one partition to ensure that we look for the old volume */
- dcr->VolCatInfo.VolCatParts = 1;
- }
+ Dmsg0(90, "try_autoload_device - looking for volume_info\n");
if (!try_autoload_device(dcr->jcr, slot, volname)) {
goto bail_out; /* error */
}
} else {
mode = CREATE_READ_WRITE;
}
- if (dev->is_dvd()) {
- bstrncpy(dcr->VolCatInfo.VolCatName, volname, sizeof(dcr->VolCatInfo.VolCatName));
- }
+ if (relabel) {
+ dev->truncating = true; /* let open() know we will truncate it */
+ }
+ /* Set old volume name for open if relabeling */
+ bstrncpy(dcr->VolCatInfo.VolCatName, volname, sizeof(dcr->VolCatInfo.VolCatName));
if (dev->open(dcr, mode) < 0) {
bnet_fsend(dir, _("3910 Unable to open device %s: ERR=%s\n"),
dev->print_name(), dev->strerror());
/* See what we have for a Volume */
label_status = read_dev_volume_label(dcr);
+ /* Set new volume name */
+ bstrncpy(dcr->VolCatInfo.VolCatName, newname, sizeof(dcr->VolCatInfo.VolCatName));
switch(label_status) {
case VOL_NAME_ERROR:
case VOL_VERSION_ERROR:
bnet_fsend(dir, _("3922 Cannot relabel an ANSI/IBM labeled Volume.\n"));
break;
}
- if (relabel && dev->is_dvd()) {
- /* Save dev VolumeName */
- bstrncpy(dcr->VolumeName, dev->VolCatInfo.VolCatName, sizeof(dcr->VolumeName));
- /* Use new name for DVD truncation */
- bstrncpy(dev->VolCatInfo.VolCatName, newname, sizeof(dev->VolCatInfo.VolCatName));
- if (!dev->truncate(dcr)) {
- bnet_fsend(dir, _("3912 Failed to truncate previous DVD volume.\n"));
- /* Restore device VolName */
- bstrncpy(dev->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dev->VolCatInfo.VolCatName));
- break;
- }
- /* Restore device VolName */
- bstrncpy(dev->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dev->VolCatInfo.VolCatName));
- }
- free_volume(dev); /* release old volume name */
/* Fall through wanted! */
case VOL_IO_ERROR:
case VOL_NO_LABEL:
- if (!write_new_volume_label_to_dev(dcr, newname, poolname, true /* write dvd now */)) {
+ if (!write_new_volume_label_to_dev(dcr, newname, poolname,
+ relabel, true /* write dvd now */)) {
bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), dev->bstrerror());
break;
}
* This routine should be used only when labeling a blank tape.
*/
bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
- const char *PoolName, bool dvdnow)
+ const char *PoolName, bool relabel, bool dvdnow)
{
DEVICE *dev = dcr->dev;
Dmsg0(99, "write_volume_label()\n");
empty_block(dcr->block);
+ /* If relabeling, truncate the device */
+ if (relabel && !dev->truncate(dcr)) {
+ goto bail_out;
+ }
+
+ if (relabel) {
+ dev->close_part(dcr); /* make sure closed for rename */
+ }
+
+ /* Set the new filename for open, ... */
+ bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
+ bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
+ Dmsg1(150, "New VolName=%s\n", VolName);
if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
/* If device is not tape, attempt to create it */
if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
/* Now commit block to DVD if we should write now */
if (dev->is_dvd() && dvdnow) {
+ Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
if (!dvd_write_part(dcr)) {
Dmsg2(30, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->bstrerror());
goto bail_out;
if (dev->poll || dev->is_dvd() || dev->is_removable()) {
goto mount_next_vol;
} else {
+ Jmsg(jcr, M_ERROR, 0, _("Could not open device %s: ERR=%s\n"),
+ dev->print_name(), dev->print_errmsg());
return false;
}
}
Dmsg0(150, "Create volume label\n");
/* Create a new Volume label and write it to the device */
if (!write_new_volume_label_to_dev(dcr, dcr->VolumeName,
- dcr->pool_name, false /* defer DVD label */)) {
+ dcr->pool_name, false, /* no relabel */ false /* defer DVD label */)) {
Dmsg0(150, "!write_vol_label\n");
mark_volume_in_error(dcr);
return try_next_vol;
int read_dvd_volume_label(DCR *dcr, bool write);
void create_session_label(DCR *dcr, DEV_RECORD *rec, int label);
void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName, bool dvdnow);
-bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName, bool dvdnow);
+bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
+ const char *PoolName, bool relabel, bool dvdnow);
#define ANSI_VOL_LABEL 0
#define ANSI_EOF_LABEL 1
#define ANSI_EOV_LABEL 2
#undef VERSION
#define VERSION "1.39.23"
-#define BDATE "20 September 2006"
-#define LSMDATE "20Sep06"
+#define BDATE "23 September 2006"
+#define LSMDATE "23Sep06"
#define BYEAR "2006" /* year for copyright messages in progs */
/* Debug flags */
-This file documents building Bacula for Microsoft Windows using the
-cross-compiler tools on a Linux or FreeBSD system (other Unix systems
-remain to be tested).
+
+This file documents the tools (scripts) we use for building
+Bacula for Microsoft Windows using the cross-compiler tools on a
+Linux system.
+
+We don't officially support this script, but it is what we use, and it should
+build on any Linux machine if you carefully follow the instructions and have
+all the prerequisite programs loaded on your machine. We expect that there
+will be problems on other distributions (FreeBSD, Mac OS X, ...), where you
+are pretty much on your own. However, we will try to provide responses to
+your questions on the bacula-devel list, but that we don't guarantee
+anything.
The basic directory structure you need to have is:
$(CMD_ECHO)-rm -f $(INSTALL_EXE) $(BACULA_BINARIES) $(DEPKGS_BINARIES) $(NONGCC_BINARIES) $(NONGCC_LIBRARIES)
$(CMD_ECHO)-rm -f $(BACULA_BINARIES) $(addsuffix .dbg,$(basename $(BACULA_BINARIES)))
$(CMD_ECHO)-rm -f $(DEPKGS_BINARIES) $(addsuffix .dbg,$(basename $(DEPKGS_BINARIES)))
+ $(CMD_ECHO)-rm -f *.exe
#
# Rules
Technical notes on version 1.39
General:
+23Sep06
+kes All code added back. Fixed block.c read/write to loop only 3
+ times. This apparently keeps the OS from crashing (at least
+ most of the time).
+kes The kernel bug still persists. Backup something then immediately
+ do a bscan on the same tape, and the kernel will crash.
+kes Simplifed tape open(). It no longer uses nonblocking mode, which
+ means that opening with no tape loaded will probably take at least
+ 6 minutes before an error is reported.
+kes Do not use MTSETDRVBUFFER if not running as root. Do a MTRESET
+ when doing set_os_device_parameters.
+kes Report open error in mount.c
+kes Remove all .exe files from the installer directory on make clean.
20Sep06
kes Start adding back removed code.
kes Back out a number of changes because backups to tape crash my