From 9d6de3a8a8b317490f1d6c44926078e63c85ec0b Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Wed, 3 Aug 2005 19:01:43 +0000 Subject: [PATCH] - Modify open() for tape so nonblocking really works. - Use fcntl() to reset blocking status rather than close() and reopen the drive. - Make sure dev->open() is always called so that any change in read/write permissions will occur. - Open drives initially in daemon in read-only mode. - Ensure that each time the VolHdr.VolumeName is zapped or changed that free_volume() is called on the old name. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2289 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/kes-1.37 | 15 ++++++++++- bacula/src/stored/acquire.c | 42 ++++++++++++++--------------- bacula/src/stored/ansi_label.c | 6 ++++- bacula/src/stored/dev.c | 48 +++++++++++++++++++++++++--------- bacula/src/stored/dev.h | 4 +-- bacula/src/stored/device.c | 2 +- bacula/src/stored/dircmd.c | 10 +++---- bacula/src/stored/label.c | 3 +++ bacula/src/version.h | 2 +- 9 files changed, 86 insertions(+), 46 deletions(-) diff --git a/bacula/kes-1.37 b/bacula/kes-1.37 index e8a4053796..ba38515cca 100644 --- a/bacula/kes-1.37 +++ b/bacula/kes-1.37 @@ -3,7 +3,18 @@ General: -Changes to 1.37.32: +Changes to 1.37.34: +03Aug03 +- Modify open() for tape so nonblocking really works. +- Use fcntl() to reset blocking status rather than close() + and reopen the drive. +- Make sure dev->open() is always called so that any change + in read/write permissions will occur. +- Open drives initially in daemon in read-only mode. +- Ensure that each time the VolHdr.VolumeName is zapped + or changed that free_volume() is called on the old name. + +Changes to 1.37.33: 03Aug03 - Require 5 arguments to mtx-changer except list and slots - Turn -EPIPE status returns from bpipe to ETIME @@ -11,6 +22,8 @@ Changes to 1.37.32: - Do not term_dev() during initialization in SD if the device could not be opened. In the case of a tape drive, there may be no tape in the drive. + +Changes to 1.32.32: 02Aug05 - Correct PostgreSQL database scripts as suggested by a user. - Add additional info to FATAL message generated when a device diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index e9daa80c1d..6e82b61dbf 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -187,31 +187,29 @@ DCR *acquire_device_for_read(DCR *dcr) * reading. If it is a file, it opens it. * If it is a tape, it checks the volume name */ - for ( ; !dev->is_open(); ) { - Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName); - if (dev->open(dcr, OPEN_READ_ONLY) < 0) { - if (dev->dev_errno == EIO) { /* no tape loaded */ - Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed (EIO): ERR=%s\n"), - dev->print_name(), dcr->VolumeName, strerror_dev(dev)); - goto default_path; - } - + Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName); + if (dev->open(dcr, OPEN_READ_ONLY) < 0) { + if (dev->dev_errno == EIO) { /* no tape loaded */ + Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed (EIO): ERR=%s\n"), + dev->print_name(), dcr->VolumeName, strerror_dev(dev)); + goto default_path; + } + #ifdef xxx_needed - /* If we have a dvd that requires mount, - * we need to try to open the label, so the info can be reported - * if a wrong volume has been mounted. - */ - if (dev->is_dvd() && (dcr->VolCatInfo.VolCatParts > 0)) { - break; - } + /* If we have a dvd that requires mount, + * we need to try to open the label, so the info can be reported + * if a wrong volume has been mounted. + */ + if (dev->is_dvd() && (dcr->VolCatInfo.VolCatParts > 0)) { + break; + } #endif - - Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"), - dev->print_name(), dcr->VolumeName, strerror_dev(dev)); - goto get_out; - } - Dmsg1(100, "opened dev %s OK\n", dev->print_name()); + + Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"), + dev->print_name(), dcr->VolumeName, strerror_dev(dev)); + goto get_out; } + Dmsg1(100, "opened dev %s OK\n", dev->print_name()); /* Read Volume Label */ diff --git a/bacula/src/stored/ansi_label.c b/bacula/src/stored/ansi_label.c index fa643b9c5f..ef2e6561a9 100644 --- a/bacula/src/stored/ansi_label.c +++ b/bacula/src/stored/ansi_label.c @@ -123,7 +123,11 @@ int read_ansi_ibm_label(DCR *dcr) if (VolName && *VolName && *VolName != '*') { if (!same_label_names(VolName, &label[4])) { char *p = &label[4]; - char *q = dev->VolHdr.VolumeName; + char *q; + + free_volume(dev); + /* Store new Volume name */ + q = dev->VolHdr.VolumeName; for (int i=0; *p != ' ' && i < 6; i++) { *q++ = *p++; } diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index f0321a15f3..a8ea31197b 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -276,7 +276,7 @@ DEVICE::open(DCR *dcr, int omode) state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF); label_type = B_BACULA_LABEL; if (is_tape() || is_fifo()) { - open_tape_device(omode); + open_tape_device(dcr, omode); } else if (is_dvd()) { Dmsg1(100, "call open_dvd_device mode=%s\n", mode_to_str(omode)); open_dvd_device(dcr, omode); @@ -311,7 +311,20 @@ void DEVICE::set_mode(int new_mode) } } -void DEVICE::open_tape_device(int omode) +/* + * If the flage open_nowait is set, which is the case + * when the daemon is initially trying to open the device, + * we open it with O_NONBLOCK set and O_RONLY, which will + * allow us to open normal Linux tape drives with no tape + * in the drive without blocking. We then immediately + * set blocking status so that if we read from the device they + * will be normal blocking reads. + * + * If later, we want to write on the device, it will be freed and + * reopened, but hopefully there will be a tape in the drive so + * we will not block. + */ +void DEVICE::open_tape_device(DCR *dcr, int omode) { int nonblocking = 0;; file_size = 0; @@ -333,14 +346,14 @@ void DEVICE::open_tape_device(int omode) tid = start_thread_timer(pthread_self(), timeout); } /* If busy retry each second for max_open_wait seconds */ -open_again: - Dmsg1(500, "Try open %s\n", print_name()); + Dmsg3(100, "Try open %s mode=%s nonblocking=%d\n", print_name(), + mode_to_str(omode), nonblocking); /* Use system open() */ - while ((fd = ::open(dev_name, mode, MODE_RW+nonblocking)) < 0) { + while ((fd = ::open(dev_name, mode+nonblocking, MODE_RW)) < 0) { berrno be; - Dmsg2(500, "Open error errno=%d ERR=%s\n", errno, be.strerror()); + Dmsg2(100, "Open error errno=%d ERR=%s\n", errno, be.strerror()); if (errno == EINTR || errno == EAGAIN) { - Dmsg0(500, "Continue open\n"); + Dmsg0(100, "Continue open\n"); continue; } /* Busy wait for specified time (default = 5 mins) */ @@ -352,7 +365,7 @@ open_again: /* IO error (no volume) try 10 times every 6 seconds */ if (errno == EIO && ioerrcnt-- > 0) { bmicrosleep(5, 0); - Dmsg0(500, "Continue open\n"); + Dmsg0(100, "Continue open\n"); continue; } dev_errno = errno; @@ -366,12 +379,21 @@ open_again: Emsg0(M_FATAL, 0, errmsg); break; } - if (fd >= 0) { - /* If opened in non-block mode, close it an open it normally */ + /* Really an if, but we use a break for an error exit */ + while (fd >= 0) { + /* If opened in non-block mode, make it block now */ if (nonblocking) { + int oflags; nonblocking = 0; - ::close(fd); /* use system close() */ - goto open_again; + /* Try to reset blocking */ + if ((oflags = fcntl(fd, F_GETFL, 0)) < 0 || + fcntl(fd, F_SETFL, oflags & ~O_NONBLOCK) < 0) { + berrno be; + Jmsg1(dcr->jcr, M_ERROR, 0, "fcntl error. ERR=%s\n", be.strerror()); + ::close(fd); /* use system close() */ + fd = -1; + break; + } } openmode = omode; /* save open mode */ Dmsg2(100, "openmode=%d %s\n", openmode, mode_to_str(openmode)); @@ -381,6 +403,7 @@ open_again: update_pos_dev(this); /* update position */ set_os_device_parameters(this); /* do system dependent stuff */ Dmsg0(500, "Open OK\n"); + break; } /* Stop any open() timer we started */ if (tid) { @@ -1706,6 +1729,7 @@ static void do_close(DEVICE *dev) dev->part_start = 0; dev->EndFile = dev->EndBlock = 0; memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo)); + free_volume(dev); memset(&dev->VolHdr, 0, sizeof(dev->VolHdr)); if (dev->tid) { stop_thread_timer(dev->tid); diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 57c4bb5b77..f96a8291bb 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -196,7 +196,7 @@ public: int mode; /* read/write modes */ int openmode; /* parameter passed to open_dev (useful to reopen the device) */ bool autoselect; /* Autoselect in autochanger */ - bool open_nowait; /* If set, don t wait on open */ + bool open_nowait; /* If set, don't wait on open */ int label_type; /* Bacula/ANSI/IBM label types */ uint32_t drive_index; /* Autochanger drive index (base 0) */ int32_t Slot; /* Slot currently in drive (base 1) */ @@ -335,7 +335,7 @@ public: private: void set_mode(int omode); /* in dev.c */ - void open_tape_device(int omode); /* in dev.c */ + void open_tape_device(DCR *dcr, int omode); /* in dev.c */ void open_file_device(int omode); /* in dev.c */ void open_dvd_device(DCR *dcr, int omode); /* in dev.c */ diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index 3cd95bf32d..5b98bc8de7 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -265,7 +265,7 @@ bool first_open_device(DCR *dcr) if (dev_cap(dev, CAP_STREAM)) { mode = OPEN_WRITE_ONLY; } else { - mode = OPEN_READ_WRITE; + mode = OPEN_READ_ONLY; } Dmsg0(129, "Opening device.\n"); dev->open_nowait = true; diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index a7b1102f5a..993c3d10e6 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -917,12 +917,10 @@ static bool try_autoload_device(JCR *jcr, int slot, const char *VolName) } /* Ensure that the device is open -- autoload_device() closes it */ - for ( ; !dev->is_open(); ) { - if (dev->open(dcr, OPEN_READ_WRITE) < 0) { - bnet_fsend(dir, _("3910 Unable to open device %s: ERR=%s\n"), - dev->print_name(), dev->strerror()); - return false; - } + if (dev->open(dcr, OPEN_READ_WRITE) < 0) { + bnet_fsend(dir, _("3910 Unable to open device %s: ERR=%s\n"), + dev->print_name(), dev->strerror()); + return false; } return true; } diff --git a/bacula/src/stored/label.c b/bacula/src/stored/label.c index 5b39ff7fda..d5319dffb5 100644 --- a/bacula/src/stored/label.c +++ b/bacula/src/stored/label.c @@ -301,6 +301,7 @@ bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *Po Dmsg1(100, "Label type=%d\n", dev->label_type); if (!rewind_dev(dev)) { + free_volume(dev); memset(&dev->VolHdr, 0, sizeof(dev->VolHdr)); Dmsg2(30, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), strerror_dev(dev)); if (!forge_on) { @@ -356,6 +357,7 @@ bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *Po return true; bail_out: + free_volume(dev); memset(&dev->VolHdr, 0, sizeof(dev->VolHdr)); dev->clear_append(); /* remove append since this is PRE_LABEL */ return false; @@ -529,6 +531,7 @@ void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName) ASSERT(dev != NULL); + free_volume(dev); /* release any old volume */ memset(&dev->VolHdr, 0, sizeof(dev->VolHdr)); bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id)); diff --git a/bacula/src/version.h b/bacula/src/version.h index f6a1bb755e..b5d36d79ec 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,6 +1,6 @@ /* */ #undef VERSION -#define VERSION "1.37.33" +#define VERSION "1.37.34" #define BDATE "03 August 2005" #define LSMDATE "03Aug05" -- 2.39.5