int retry = 0;
Dmsg1(50, "jcr->dcr=%p\n", jcr->dcr);
- dev->block(BST_DOING_ACQUIRE);
+ dev->dblock(BST_DOING_ACQUIRE);
if (dev->num_writers > 0) {
Jmsg2(jcr, M_FATAL, 0, _("Acquire read: num_writers=%d not zero. Job %d canceled.\n"),
* which we do not use except for the dev info.
*/
stat = search_res_for_device(rctx);
- release_msgs(jcr); /* release queued messages */
+ release_reserve_messages(jcr); /* release queued messages */
unlock_reservations();
if (stat == 1) {
DCR *ndcr = jcr->read_dcr;
- dev->unblock(dev_unlocked);
+ dev->dunblock(dev_unlocked);
detach_dcr_from_dev(dcr); /* release old device */
/* Copy important info from the new dcr */
dev = dcr->dev = ndcr->dev;
attach_dcr_to_dev(dcr);
ndcr->VolumeName[0] = 0;
free_dcr(ndcr);
- dev->block(BST_DOING_ACQUIRE);
+ dev->dblock(BST_DOING_ACQUIRE);
Jmsg(jcr, M_INFO, 0, _("Media Type change. New device %s chosen.\n"),
dev->print_name());
bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
dcr->reserved_device = false;
}
- dev->unblock(dev_locked);
+ dev->dunblock(dev_locked);
Dmsg1(50, "jcr->dcr=%p\n", jcr->dcr);
return ok;
}
init_device_wait_timers(dcr);
- dev->block(BST_DOING_ACQUIRE);
+ dev->dblock(BST_DOING_ACQUIRE);
Dmsg1(190, "acquire_append device is %s\n", dev->is_tape()?"tape":
(dev->is_dvd()?"DVD":"disk"));
Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
dcr->reserved_device = false;
}
- dev->unblock(dev_locked);
+ dev->dunblock(dev_locked);
return dcr;
/*
Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
dcr->reserved_device = false;
}
- dev->unblock(dev_locked);
+ dev->dunblock(dev_locked);
return NULL;
}
pthread_cond_broadcast(&dev->wait_next_vol);
Dmsg1(100, "JobId=%u broadcast wait_device_release\n", (uint32_t)jcr->JobId);
pthread_cond_broadcast(&wait_device_release);
- dcr->dev_locked = false; /* set no longer locked */
dev->dunlock();
if (jcr->read_dcr == dcr) {
jcr->read_dcr = NULL;
-/*
- * Append code for Storage daemon
- * Kern Sibbald, May MM
- *
- * Version $Id$
- */
/*
Bacula® - The Network Backup Solution
(FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
Switzerland, email:ftf@fsfeurope.org.
*/
+/*
+ * Append code for Storage daemon
+ * Kern Sibbald, May MM
+ *
+ * Version $Id$
+ */
#include "bacula.h"
#include "stored.h"
ds = fd_sock;
- if (!bnet_set_buffer_size(ds, dcr->device->max_network_buffer_size, BNET_SETBUF_WRITE)) {
+ if (!ds->set_buffer_size(dcr->device->max_network_buffer_size, BNET_SETBUF_WRITE)) {
set_jcr_job_status(jcr, JS_ErrorTerminated);
Jmsg0(jcr, M_FATAL, 0, _("Unable to set network buffer size.\n"));
return false;
}
/* Tell File daemon to send data */
- if (!bnet_fsend(fd_sock, OK_data)) {
+ if (!fd_sock->fsend(OK_data)) {
berrno be;
Jmsg1(jcr, M_FATAL, 0, _("Network send error to FD. ERR=%s\n"),
be.bstrerror(fd_sock->b_errno));
break; /* end of data */
}
Jmsg1(jcr, M_FATAL, 0, _("Error reading data header from FD. ERR=%s\n"),
- bnet_strerror(ds));
+ ds->bstrerror());
ok = false;
break;
}
if (!dir_update_file_attributes(dcr, &rec)) {
jcr->dir_bsock->clear_spooling();
Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"),
- bnet_strerror(jcr->dir_bsock));
+ jcr->dir_bsock->bstrerror());
ok = false;
break;
}
Dmsg1(650, "End read loop with FD. Stat=%d\n", n);
if (is_bnet_error(ds)) {
- Dmsg1(350, "Network read error from FD. ERR=%s\n", bnet_strerror(ds));
+ Dmsg1(350, "Network read error from FD. ERR=%s\n", ds->bstrerror());
Jmsg1(jcr, M_FATAL, 0, _("Network error on data channel. ERR=%s\n"),
- bnet_strerror(ds));
+ ds->bstrerror());
ok = false;
break;
}
set_jcr_job_status(jcr, ok?JS_Terminated:JS_ErrorTerminated);
/* Terminate connection with FD */
- bnet_fsend(ds, OK_append);
+ ds->fsend(OK_append);
do_fd_commands(jcr); /* finish dialog with FD */
-/*
- *
- * block.c -- tape block handling functions
- *
- * Kern Sibbald, March MMI
- * added BB02 format October MMII
- *
- * Version $Id$
- *
- */
/*
Bacula® - The Network Backup Solution
(FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
Switzerland, email:ftf@fsfeurope.org.
*/
+/*
+ *
+ * block.c -- tape block handling functions
+ *
+ * Kern Sibbald, March MMI
+ * added BB02 format October MMII
+ *
+ * Version $Id$
+ *
+ */
#include "bacula.h"
* daemon. More complicated coding (double buffering, writer
* thread, ...) is left for a later version.
*
- * Unfortunately, I have had to add more and more complication
- * to this code. This was not foreseen as noted above, and as
- * a consequence has lead to something more contorted than is
- * really necessary -- KES. Note, this contortion has been
- * corrected to a large extent by a rewrite (Apr MMI).
- *
* Version $Id$
*/
#ifndef __DEV_H
#define __DEV_H 1
-#ifdef SD_DEBUG_LOCK
-#define r_dlock() _r_dlock(__FILE__, __LINE__); /* in device.c */
-#define r_dunlock() _r_dunlock(__FILE__, __LINE__); /* in device.c */
-#define dlock() _dlock(__FILE__, __LINE__); /* in device.c */
-#define dunlock() _dunlock(__FILE__, __LINE__); /* in device.c */
-#endif
-
#undef DCR /* used by Bacula */
-#define block_device(d, s) _block_device(__FILE__, __LINE__, (d), s)
-#define unblock_device(d) _unblock_device(__FILE__, __LINE__, (d))
-#define steal_device_lock(d, p, s) _steal_device_lock(__FILE__, __LINE__, (d), (p), s)
-#define give_back_device_lock(d, p) _give_back_device_lock(__FILE__, __LINE__, (d), (p))
-
/* Return values from wait_for_sysop() */
enum {
W_ERROR = 1,
#define ST_PART_SPOOLED (1<<18) /* spooling part */
#define ST_FREESPACE_OK (1<<19) /* Have valid freespace for DVD */
-/* m_blocked states (mutually exclusive) */
-enum {
- BST_NOT_BLOCKED = 0, /* not blocked */
- BST_UNMOUNTED, /* User unmounted device */
- BST_WAITING_FOR_SYSOP, /* Waiting for operator to mount tape */
- BST_DOING_ACQUIRE, /* Opening/validating/moving tape */
- BST_WRITING_LABEL, /* Labeling a tape */
- BST_UNMOUNTED_WAITING_FOR_SYSOP, /* User unmounted during wait for op */
- BST_MOUNT /* Mount request */
-};
/* Volume Catalog Information structure definition */
struct VOLUME_CAT_INFO {
};
-typedef struct s_steal_lock {
- pthread_t no_wait_id; /* id of no wait thread */
- int dev_blocked; /* state */
- int dev_prev_blocked; /* previous blocked state */
-} bsteal_lock_t;
-
class DEVRES; /* Device resource defined in stored_conf.h */
class DCR; /* forward reference */
class VOLRES; /* forward reference */
-/*
- * Used in unblock() call
- */
-enum {
- dev_locked = true,
- dev_unlocked = false
-};
/*
* Device structure definition. There is one of these for
int num_waiting; /* number of threads waiting */
int num_writers; /* number of writing threads */
int reserved_device; /* number of device reservations */
-
- /* New access control in process of being implemented */
-// brwlock_t xlock; /* New mutual exclusion lock */
-
int capabilities; /* capabilities mask */
int state; /* state mask */
int dev_errno; /* Our own errno */
char *bstrerror(void) { return errmsg; };
char *print_errmsg() { return errmsg; };
-#ifdef SD_DEBUG_LOCK
- void _r_dlock(const char *, int); /* in device.c */
- void _r_dunlock(const char *, int); /* in device.c */
- void _dlock(const char *, int); /* in device.c */
- void _dunlock(const char *, int); /* in device.c */
-#else
- void r_dlock(); /* in device.c */
- void r_dunlock() { dunlock(); }
- void dlock() { P(m_mutex); }
- void dunlock() { V(m_mutex); }
-#endif
void clear_volhdr(); /* in dev.c */
- void block(int why); /* in locks.c */
- void unblock(bool locked=false); /* in locks.c */
void close(); /* in dev.c */
void close_part(DCR *dcr); /* in dev.c */
bool truncate(DCR *dcr); /* in dev.c */
bool update_pos(DCR *dcr); /* in dev.c */
bool update_freespace(); /* in dvd.c */
- void set_blocked(int block) { m_blocked = block; };
- int blocked() const { return m_blocked; };
uint32_t get_file() const { return file; };
- uint32_t get_block() const { return block_num; };
- const char *print_blocked() const; /* in dev.c */
- bool is_blocked() const { return m_blocked != BST_NOT_BLOCKED; };
+ uint32_t get_block_num() const { return block_num; };
int fd() const { return m_fd; };
+ /*
+ * Locking and blocking calls
+ */
+#ifdef SD_DEBUG_LOCK
+ void _r_dlock(const char *, int); /* in lock.c */
+ void _r_dunlock(const char *, int); /* in lock.c */
+ void _dlock(const char *, int); /* in lock.c */
+ void _dunlock(const char *, int); /* in lock.c */
+#else
+ void r_dlock(); /* in lock.c */
+ void r_dunlock() { dunlock(); }
+ void dlock() { P(m_mutex); }
+ void dunlock() { V(m_mutex); }
+#endif
+ void dblock(int why); /* in lock.c */
+ void dunblock(bool locked=false); /* in lock.c */
+ void set_blocked(int block) { m_blocked = block; };
+ int blocked() const { return m_blocked; };
+ bool is_blocked() const { return m_blocked != BST_NOT_BLOCKED; };
+ const char *print_blocked() const; /* in dev.c */
+
private:
bool do_mount(int mount, int timeout); /* in dev.c */
void set_mode(int omode); /* in dev.c */
free_record(rec);
Dmsg2(150, "Leave write_session_label Block=%ud File=%ud\n",
- dev->get_block(), dev->get_file());
+ dev->get_block_num(), dev->get_file());
return true;
}
#endif
-void DEVICE::block(int why)
+/*
+ *
+ * The Storage daemon has three locking concepts that must be
+ * understood:
+ *
+ * 1. dblock blocking the device, which means that the device
+ * is "marked" in use. When setting and removing the
+ block, the device is locked, but after dblock is
+ called the device is unlocked.
+ * 2. dlock() simple mutex that locks the device structure. A dlock
+ * can be acquired while a device is blocked if it is not
+ * locked.
+ * 3. r_dlock "recursive" dlock, when means that a dlock (mutex)
+ * will be acquired on the device if it is not blocked
+ * by some other thread. If the device was blocked by
+ * the current thread, it will acquire the lock.
+ * If some other thread has set a block on the device,
+ * this call will wait until the device is unblocked.
+ *
+ * A lock is normally set when modifying the device structure.
+ * A r_lock is normally acquired when you want to block the device
+ * i.e. it will wait until the device is not blocked.
+ * A block is normally set during long operations like writing to
+ * the device.
+ * If you are writing the device, you will normally block and
+ * lock it.
+ * A lock cannot be violated. No other thread can touch the
+ * device while a lock is set.
+ * When a block is set, every thread accept the thread that set
+ * the block will block if r_dlock is called.
+ * A device can be blocked for multiple reasons, labeling, writing,
+ * acquiring (opening) the device, waiting for the operator, unmounted,
+ * ...
+ * Under certain conditions the block that is set on a device can be
+ * stolen and the device can be used by another thread. For example,
+ * a device is blocked because it is waiting for the operator to
+ * mount a tape. The operator can then unmount the device, and label
+ * a tape, re-mount it, give back the block, and the job will continue.
+ *
+ *
+ * Functions:
+ *
+ * DEVICE::dlock() does P(m_mutex) (in dev.h)
+ * DEVICE::dunlock() does V(m_mutex)
+ *
+ * DEVICE::dblock(why) does
+ * r_dlock(); (recursive device lock)
+ * block_device(this, why)
+ * r_dunlock()
+ *
+ * DEVICE::dunblock does
+ * dlock()
+ * unblock_device()
+ * dunlock()
+ *
+ * DEVICE::r_dlock() does recursive locking
+ * dlock()
+ * if blocked and not same thread that locked
+ * pthread_cond_wait
+ * leaves device locked
+ *
+ * DEVICE::r_dunlock()
+ * same as dunlock();
+ *
+ * block_device() does (must be locked and not blocked at entry)
+ * set blocked status
+ * set our pid
+ *
+ * unblock_device() does (must be blocked at entry)
+ * (locked on entry)
+ * (locked on exit)
+ * set unblocked status
+ * clear pid
+ * if waiting threads
+ * pthread_cond_broadcast
+ *
+ * steal_device_lock() does (must be locked and blocked at entry)
+ * save status
+ * set new blocked status
+ * set new pid
+ * unlock()
+ *
+ * give_back_device_lock() does (must be blocked but not locked)
+ * dlock()
+ * reset blocked status
+ * save previous blocked
+ * reset pid
+ * if waiting threads
+ * pthread_cond_broadcast
+ *
+ */
+
+
+void DEVICE::dblock(int why)
{
r_dlock(); /* need recursive lock to block */
block_device(this, why);
r_dunlock();
}
-void DEVICE::unblock(bool locked)
+void DEVICE::dunblock(bool locked)
{
if (!locked) {
dlock();
*/
#ifdef SD_DEBUG_LOCK
void DEVICE::_r_dlock(const char *file, int line)
-#else
-void DEVICE::r_dlock()
-#endif
{
- int stat;
-#ifdef SD_DEBUG_LOCK
Dmsg4(sd_dbglvl+1, "r_dlock blked=%s from %s:%d JobId=%u\n", this->print_blocked(),
file, line, get_jobid_from_tid());
#else
- Dmsg1(sd_dbglvl, "reclock blked=%s\n", this->print_blocked());
+void DEVICE::r_dlock()
+{
#endif
+ int stat;
this->dlock();
if (this->blocked() && !pthread_equal(this->no_wait_id, pthread_self())) {
this->num_waiting++; /* indicate that I am waiting */
return "BST_UNMOUNTED_WAITING_FOR_SYSOP";
case BST_MOUNT:
return "BST_MOUNT";
+ case BST_DESPOOLING:
+ return "BST_DESPOOLING";
default:
return _("unknown blocked code");
}
(blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
return stat;
}
-
--- /dev/null
+/*
+ Bacula® - The Network Backup Solution
+
+ Copyright (C) 2000-2007 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 John Walker.
+ The licensor of Bacula is the Free Software Foundation Europe
+ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+ Switzerland, email:ftf@fsfeurope.org.
+*/
+/*
+ * Definitions for locking and blocking functions in the SD
+ *
+ * Kern Sibbald, pulled out of dev.h June 2007
+ *
+ * Version $Id$
+ *
+ */
+
+
+#ifndef __LOCK_H
+#define __LOCK_H 1
+
+#ifdef SD_DEBUG_LOCK
+#define r_dlock() _r_dlock(__FILE__, __LINE__); /* in lock.c */
+#define r_dunlock() _r_dunlock(__FILE__, __LINE__); /* in lock.c */
+#define dlock() _dlock(__FILE__, __LINE__); /* in lock.c */
+#define dunlock() _dunlock(__FILE__, __LINE__); /* in lock.c */
+#endif
+
+#define block_device(d, s) _block_device(__FILE__, __LINE__, (d), s)
+#define unblock_device(d) _unblock_device(__FILE__, __LINE__, (d))
+#define steal_device_lock(d, p, s) _steal_device_lock(__FILE__, __LINE__, (d), (p), s)
+#define give_back_device_lock(d, p) _give_back_device_lock(__FILE__, __LINE__, (d), (p))
+
+/* m_blocked states (mutually exclusive) */
+enum {
+ BST_NOT_BLOCKED = 0, /* not blocked */
+ BST_UNMOUNTED, /* User unmounted device */
+ BST_WAITING_FOR_SYSOP, /* Waiting for operator to mount tape */
+ BST_DOING_ACQUIRE, /* Opening/validating/moving tape */
+ BST_WRITING_LABEL, /* Labeling a tape */
+ BST_UNMOUNTED_WAITING_FOR_SYSOP, /* User unmounted during wait for op */
+ BST_MOUNT, /* Mount request */
+ BST_DESPOOLING /* Despooling -- i.e. multiple writes */
+};
+
+typedef struct s_steal_lock {
+ pthread_t no_wait_id; /* id of no wait thread */
+ int dev_blocked; /* state */
+ int dev_prev_blocked; /* previous blocked state */
+} bsteal_lock_t;
+
+/*
+ * Used in unblock() call
+ */
+enum {
+ dev_locked = true,
+ dev_unlocked = false
+};
+
+#endif
void send_drive_reserve_messages(JCR *jcr, void sendit(const char *msg, int len, void *sarg), void *arg);
bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx);
int search_res_for_device(RCTX &rctx);
-void release_msgs(JCR *jcr);
+void release_reserve_messages(JCR *jcr);
extern int reservations_lock_count;
extern int vol_list_lock_count;
static bool reserve_device_for_append(DCR *dcr, RCTX &rctx);
static bool use_storage_cmd(JCR *jcr);
static void queue_reserve_message(JCR *jcr);
+static void pop_reserve_messages(JCR *jcr);
/* Requests from the Director daemon */
static char use_storage[] = "use storage=%127s media_type=%127s "
int Copy, Stripe;
DIRSTORE *store;
RCTX rctx;
- char *msg;
- alist *msgs;
alist *dirstore;
memset(&rctx, 0, sizeof(RCTX));
* use_device for each device that it wants to use.
*/
dirstore = New(alist(10, not_owned_by_alist));
- msgs = jcr->reserve_msgs = New(alist(10, not_owned_by_alist));
+ jcr->reserve_msgs = New(alist(10, not_owned_by_alist));
do {
Dmsg2(dbglvl, "jid=%u <dird: %s", jid(), dir->msg);
ok = sscanf(dir->msg, use_storage, store_name.c_str(),
lock_reservations();
for ( ; !fail && !job_canceled(jcr); ) {
- while ((msg = (char *)msgs->pop())) {
- free(msg);
- }
+ pop_reserve_messages(jcr);
rctx.suitable_device = false;
rctx.have_volume = false;
rctx.VolumeName[0] = 0;
Dmsg2(dbglvl, "jid=%u >dird: %s", jid(), dir->msg);
}
- release_msgs(jcr);
+ release_reserve_messages(jcr);
return ok;
}
jcr->unlock();
}
-void release_msgs(JCR *jcr)
+/*
+ * Pop and release any reservations messages
+ */
+static void pop_reserve_messages(JCR *jcr)
{
alist *msgs;
char *msg;
while ((msg = (char *)msgs->pop())) {
free(msg);
}
- delete msgs;
+bail_out:
+ jcr->unlock();
+}
+
+/*
+ * Also called from acquire.c
+ */
+void release_reserve_messages(JCR *jcr)
+{
+ pop_reserve_messages(jcr);
+ jcr->lock();
+ if (!jcr->reserve_msgs) {
+ goto bail_out;
+ }
+ delete jcr->reserve_msgs;
jcr->reserve_msgs = NULL;
bail_out:
# endif
# endif
#endif
+#include "lock.h"
#include "block.h"
#include "record.h"
#include "dev.h"
#undef VERSION
#define VERSION "2.1.23"
-#define BDATE "26 June 2007"
-#define LSMDATE "26Jun07"
+#define BDATE "28 June 2007"
+#define LSMDATE "28Jun07"
#define PROG_COPYRIGHT "Copyright (C) %d-2007 Free Software Foundation Europe e.V.\n"
#define BYEAR "2007" /* year for copyright messages in progs */