Emsg1(M_ERROR, 0, _("Failed ASSERT: %s\n"), #x); \
Pmsg1(000, _("Failed ASSERT: %s\n"), #x); \
jcr[0] = 0; }
+
+#define ASSERT2(x,y) if (!(x)) { \
+ assert_msg = y; \
+ Emsg1(M_ERROR, 0, _("Failed ASSERT: %s\n"), #x); \
+ Pmsg1(000, _("Failed ASSERT: %s\n"), #x); \
+ char *jcr = NULL; \
+ jcr[0] = 0; }
#else
#define ASSERT(x)
+#define ASSERT2(x, y)
#endif
/* Allow printing of NULL pointers */
/** Determine endianes */
static inline bool bigendian() { return htonl(1) == 1L; }
+#ifndef __GNUC__
+#define __PRETTY_FUNCTION__ __func__
+#endif
+#ifdef ENTER_LEAVE
+#define Enter(lvl) Dmsg1(lvl, "Enter: %s\n", __PRETTY_FUNCTION__)
+#define Leave(lvl) Dmsg1(lvl, "Leave: %s\n", __PRETTY_FUNCTION__)
+#else
+#define Enter(lvl)
+#define Leave(lvl)
+#endif
+
#endif /* _BACONFIG_H */
* daemons include this file.
*/
const char *working_directory = NULL; /* working directory path stored here */
+const char *assert_msg = (char *)NULL; /* ASSERT2 error message */
int verbose = 0; /* increase User messages */
int debug_level = 0; /* debug level */
bool dbg_timestamp = false; /* print timestamp in debug output */
extern DLL_IMP_EXP bool prt_kaboom; /* Print kaboom output */
extern DLL_IMP_EXP int verbose;
extern DLL_IMP_EXP char my_name[];
+extern DLL_IMP_EXP const char *assert_msg; /* Assert error message */
extern DLL_IMP_EXP const char * working_directory;
extern DLL_IMP_EXP utime_t daemon_start_time;
/*
Bacula(R) - The Network Backup Solution
- Copyright (C) 2002-2012 Free Software Foundation Europe e.V.
+ Copyright (C) 2002-2013 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.
#include "bacula.h" /* pull in global headers */
#include "stored.h" /* pull in Storage Deamon headers */
+static int const rdbglvl = 100;
+
/* Forward referenced functions */
static void attach_dcr_to_dev(DCR *dcr);
static void detach_dcr_from_dev(DCR *dcr);
*/
bool acquire_device_for_read(DCR *dcr)
{
- DEVICE *dev = dcr->dev;
+ DEVICE *dev;
JCR *jcr = dcr->jcr;
bool ok = false;
bool tape_previously_mounted;
int vol_label_status;
int retry = 0;
- P(dev->read_acquire_mutex);
- Dmsg2(950, "dcr=%p dev=%p\n", dcr, dcr->dev);
- Dmsg2(950, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
+ Enter(rdbglvl);
+ dev = dcr->dev;
+ dev->Lock_read_acquire();
+ Dmsg2(rdbglvl, "dcr=%p dev=%p\n", dcr, dcr->dev);
+ Dmsg2(rdbglvl, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
dev->dblock(BST_DOING_ACQUIRE);
if (dev->num_writers > 0) {
}
set_dcr_from_vol(dcr, vol);
- if (generate_plugin_event(jcr, bsdEventDeviceOpen, dcr) != bRC_OK) {
- Jmsg(jcr, M_FATAL, 0, _("generate_plugin_event(bsdEventDeviceOpen) Failed\n"));
- goto get_out;
- }
-
- Dmsg2(100, "Want Vol=%s Slot=%d\n", vol->VolumeName, vol->Slot);
+ Dmsg2(rdbglvl, "Want Vol=%s Slot=%d\n", vol->VolumeName, vol->Slot);
/*
* If the MediaType requested for this volume is not the
* them such as the block pointer (size may change), but we do
* not release the dcr.
*/
- Dmsg2(50, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
+ Dmsg2(rdbglvl, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
if (dcr->media_type[0] && strcmp(dcr->media_type, dev->device->media_type) != 0) {
RCTX rctx;
DIRSTORE *store;
Jmsg3(jcr, M_INFO, 0, _("Changing read device. Want Media Type=\"%s\" have=\"%s\"\n"
" device=%s\n"),
dcr->media_type, dev->device->media_type, dev->print_name());
- Dmsg3(50, "Changing read device. Want Media Type=\"%s\" have=\"%s\"\n"
+ Dmsg3(rdbglvl, "Changing read device. Want Media Type=\"%s\" have=\"%s\"\n"
" device=%s\n",
dcr->media_type, dev->device->media_type, dev->print_name());
- generate_plugin_event(jcr, bsdEventDeviceClose, dcr);
-
dev->dunblock(DEV_UNLOCKED);
lock_reservations();
* Switching devices, so acquire lock on new device,
* then release the old one.
*/
- P(dcr->dev->read_acquire_mutex);
- V(dev->read_acquire_mutex);
+ dcr->dev->Lock_read_acquire(); /* lock new one */
+ dev->Unlock_read_acquire(); /* release old one */
dev = dcr->dev; /* get new device pointer */
dev->dblock(BST_DOING_ACQUIRE);
Jmsg(jcr, M_INFO, 0, _("Media Type change. New read device %s chosen.\n"),
dev->print_name());
Dmsg1(50, "Media Type change. New read device %s chosen.\n", dev->print_name());
- if (generate_plugin_event(jcr, bsdEventDeviceOpen, dcr) != bRC_OK) {
- Jmsg(jcr, M_FATAL, 0, _("generate_plugin_event(bsdEventDeviceOpen) Failed\n"));
- goto get_out;
- }
bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
dcr->setVolCatName(vol->VolumeName);
bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type));
/* error */
Jmsg1(jcr, M_FATAL, 0, _("No suitable device found to read Volume \"%s\"\n"),
vol->VolumeName);
- Dmsg1(50, "No suitable device found to read Volume \"%s\"\n", vol->VolumeName);
+ Dmsg1(rdbglvl, "No suitable device found to read Volume \"%s\"\n", vol->VolumeName);
goto get_out;
}
}
- Dmsg2(400, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
+ Dmsg2(rdbglvl, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
dev->clear_unload();
if (dev->vol && dev->vol->is_swapping()) {
dev->vol->set_slot(vol->Slot);
- Dmsg3(100, "swapping: slot=%d Vol=%s dev=%s\n", dev->vol->get_slot(),
+ Dmsg3(rdbglvl, "swapping: slot=%d Vol=%s dev=%s\n", dev->vol->get_slot(),
dev->vol->vol_name, dev->print_name());
}
// tape_initially_mounted = tape_previously_mounted;
/* Volume info is always needed because of VolParts */
- Dmsg1(150, "dir_get_volume_info vol=%s\n", dcr->VolumeName);
+ Dmsg1(rdbglvl, "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",
+ Dmsg2(rdbglvl, "dir_get_vol_info failed for vol=%s: %s\n",
dcr->VolumeName, jcr->errmsg);
Jmsg1(jcr, M_WARNING, 0, "Read acquire: %s", jcr->errmsg);
}
* reading. If it is a file, it opens it.
* If it is a tape, it checks the volume name
*/
- Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName);
+ Dmsg1(rdbglvl, "open vol=%s\n", dcr->VolumeName);
if (!dev->open(dcr, OPEN_READ_ONLY)) {
if (!dev->poll) {
Jmsg3(jcr, M_WARNING, 0, _("Read open device %s Volume \"%s\" failed: ERR=%s\n"),
}
goto default_path;
}
- Dmsg1(50, "opened dev %s OK\n", dev->print_name());
+ Dmsg1(rdbglvl, "opened dev %s OK\n", dev->print_name());
/* Read Volume Label */
- Dmsg0(50, "calling read-vol-label\n");
+ Dmsg0(rdbglvl, "calling read-vol-label\n");
vol_label_status = read_dev_volume_label(dcr);
switch (vol_label_status) {
case VOL_OK:
- Dmsg0(50, "Got correct volume.\n");
+ Dmsg0(rdbglvl, "Got correct volume.\n");
ok = true;
dev->VolCatInfo = dcr->VolCatInfo; /* structure assignment */
break; /* got it */
case VOL_IO_ERROR:
- Dmsg0(50, "IO Error\n");
+ Dmsg0(rdbglvl, "IO Error\n");
/*
* Send error message generated by read_dev_volume_label()
* only we really had a tape mounted. This supresses superfluous
}
goto default_path;
case VOL_NAME_ERROR:
- Dmsg3(50, "Vol name=%s want=%s drv=%s.\n", dev->VolHdr.VolumeName,
+ Dmsg3(rdbglvl, "Vol name=%s want=%s drv=%s.\n", dev->VolHdr.VolumeName,
dcr->VolumeName, dev->print_name());
if (dev->is_volume_to_unload()) {
goto default_path;
default:
Jmsg1(jcr, M_WARNING, 0, "Read acquire: %s", jcr->errmsg);
default_path:
- Dmsg0(50, "default path\n");
+ Dmsg0(rdbglvl, "default path\n");
tape_previously_mounted = true;
/*
/* Call autochanger only once unless ask_sysop called */
if (try_autochanger) {
int stat;
- Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
+ Dmsg2(rdbglvl, "calling autoload Vol=%s Slot=%d\n",
dcr->VolumeName, dcr->VolCatInfo.Slot);
stat = autoload_device(dcr, 0, NULL);
if (stat > 0) {
}
/* Mount a specific volume and no other */
- Dmsg0(200, "calling dir_ask_sysop\n");
+ Dmsg0(rdbglvl, "calling dir_ask_sysop\n");
if (!dir_ask_sysop_to_mount_volume(dcr, ST_READ)) {
goto get_out; /* error return */
}
dcr->VolumeName, dev->print_name());
get_out:
- dev->dlock();
+ dev->Lock();
dcr->clear_reserved();
- /* If failed and not writing plugin close device */
- if (!ok && dev->num_writers == 0 && dev->num_reserved() == 0) {
- generate_plugin_event(jcr, bsdEventDeviceClose, dcr);
- }
/*
* Normally we are blocked, but in at least one error case above
* we are not blocked because we unsuccessfully tried changing
if (dev->is_blocked()) {
dev->dunblock(DEV_LOCKED);
} else {
- dev->dunlock(); /* dunblock() unlock the device too */
+ dev->Unlock(); /* dunblock() unlock the device too */
}
- Dmsg2(950, "dcr=%p dev=%p\n", dcr, dcr->dev);
- Dmsg2(950, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
- V(dev->read_acquire_mutex);
+ Dmsg2(rdbglvl, "dcr=%p dev=%p\n", dcr, dcr->dev);
+ Dmsg2(rdbglvl, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
+ dev->Unlock_read_acquire();
+ Leave(rdbglvl);
return ok;
}
bool ok = false;
bool have_vol = false;
+ Enter(200);
init_device_wait_timers(dcr);
- P(dev->acquire_mutex); /* only one job at a time */
- dev->dlock();
+ dev->Lock_acquire(); /* only one job at a time */
+ dev->Lock();
Dmsg1(100, "acquire_append device is %s\n", dev->is_tape()?"tape":
(dev->is_dvd()?"DVD":"disk"));
}
if (!have_vol) {
- dev->r_dlock(true);
+ dev->rLock(true);
block_device(dev, BST_DOING_ACQUIRE);
- dev->dunlock();
+ dev->Unlock();
Dmsg1(190, "jid=%u Do mount_next_write_vol\n", (uint32_t)jcr->JobId);
if (!dcr->mount_next_write_volume()) {
if (!job_canceled(jcr)) {
Dmsg1(200, "Could not ready device %s for append.\n",
dev->print_name());
}
- dev->dlock();
+ dev->Lock();
unblock_device(dev);
goto get_out;
}
Dmsg2(190, "Output pos=%u:%u\n", dcr->dev->file, dcr->dev->block_num);
- dev->dlock();
+ dev->Lock();
unblock_device(dev);
}
- if (generate_plugin_event(jcr, bsdEventDeviceOpen, dcr) != bRC_OK) {
- Jmsg(jcr, M_FATAL, 0, _("generate_plugin_event(bsdEventDeviceOpen) Failed\n"));
- goto get_out;
- }
-
dev->num_writers++; /* we are now a writer */
if (jcr->NumWriteVolumes == 0) {
jcr->NumWriteVolumes = 1;
get_out:
/* Don't plugin close here, we might have multiple writers */
dcr->clear_reserved();
- dev->dunlock();
- V(dev->acquire_mutex);
+ dev->Unlock();
+ dev->Unlock_acquire();
+ Leave(200);
return ok ? dcr : NULL;
}
char tbuf[100];
int was_blocked = BST_NOT_BLOCKED;
- dev->dlock();
+ dev->Lock();
if (!dev->is_blocked()) {
block_device(dev, BST_RELEASING);
} else {
if (dev->can_read()) {
VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
- generate_plugin_event(jcr, bsdEventDeviceClose, dcr);
dev->clear_read(); /* clear read bit */
Dmsg2(150, "dir_update_vol_info. label=%d Vol=%s\n",
dev->is_labeled(), vol->VolCatName);
* there are no writers. It was probably reserved.
*/
volume_unused(dcr);
- generate_plugin_event(jcr, bsdEventDeviceClose, dcr);
}
Dmsg3(100, "%d writers, %d reserve, dev=%s\n", dev->num_writers, dev->num_reserved(),
dev->print_name());
/* If no writers, close if file or !CAP_ALWAYS_OPEN */
if (dev->num_writers == 0 && (!dev->is_tape() || !dev->has_cap(CAP_ALWAYSOPEN))) {
- generate_plugin_event(jcr, bsdEventDeviceClose, dcr);
dvd_remove_empty_part(dcr); /* get rid of any empty spool part */
dev->close();
free_volume(dev);
} else {
/* Otherwise, reset the prior block status and unlock */
dev->set_blocked(was_blocked);
- dev->dunlock();
+ dev->Unlock();
}
if (dcr->keep_dcr) {
} else {
free_dcr(dcr);
}
- Dmsg2(100, "===== Device %s released by JobId=%u\n", dev->print_name(),
+ Dmsg2(100, "Device %s released by JobId=%u\n", dev->print_name(),
(uint32_t)jcr->JobId);
return ok;
}
Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
}
+ if ((errstat = pthread_mutex_init(&dcr->r_mutex, NULL)) != 0) {
+ berrno be;
+ dev->dev_errno = errstat;
+ Mmsg1(dev->errmsg, _("Unable to init r_mutex: ERR=%s\n"), be.bstrerror(errstat));
+ Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
+ }
}
dcr->jcr = jcr; /* point back to jcr */
/* Set device information, possibly change device */
dcr->max_job_spool_size = dev->device->max_job_spool_size;
}
dcr->device = dev->device;
- dcr->dev = dev;
+ dcr->set_dev(dev);
attach_dcr_to_dev(dcr);
}
return dcr;
if (jcr) Dmsg1(500, "JobId=%u enter attach_dcr_to_dev\n", (uint32_t)jcr->JobId);
/* ***FIXME*** return error if dev not initiated */
if (!dcr->attached_to_dev && dev->initiated && jcr && jcr->getJobType() != JT_SYSTEM) {
- dev->dlock();
+ dev->Lock();
+ Dmsg4(200, "Attach Jid=%d dcr=%p size=%d dev=%s\n", (uint32_t)jcr->JobId,
+ dcr, dev->attached_dcrs->size(), dev->print_name());
dev->attached_dcrs->append(dcr); /* attach dcr to device */
- dev->dunlock();
+ dev->Unlock();
dcr->attached_to_dev = true;
- Dmsg1(500, "JobId=%u attach_dcr_to_dev\n", (uint32_t)jcr->JobId);
}
V(dcr->m_mutex);
}
/* Detach this dcr only if attached */
if (dcr->attached_to_dev && dev) {
dcr->unreserve_device();
- dev->dlock();
- dcr->dev->attached_dcrs->remove(dcr); /* detach dcr from device */
+ dev->Lock();
+ Dmsg4(200, "Detach Jid=%d dcr=%p size=%d to dev=%s\n", (uint32_t)dcr->jcr->JobId,
+ dcr, dev->attached_dcrs->size(), dev->print_name());
+ dcr->attached_to_dev = false;
+ if (dev->attached_dcrs->size()) {
+ dev->attached_dcrs->remove(dcr); /* detach dcr from device */
+ }
// remove_dcr_from_dcrs(dcr); /* remove dcr from jcr list */
- dev->dunlock();
+ dev->Unlock();
}
dcr->attached_to_dev = false;
}
}
V(dcr->m_mutex);
pthread_mutex_destroy(&dcr->m_mutex);
+ pthread_mutex_destroy(&dcr->r_mutex);
free(dcr);
}
}
Dmsg0(100, "About to acquire device for writing\n");
/* For we must now acquire the device for writing */
- out_dev->r_dlock();
+ out_dev->rLock(false);
if (!out_dev->open(out_jcr->dcr, OPEN_READ_WRITE)) {
Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
- out_dev->dunlock();
+ out_dev->Unlock();
exit(1);
}
- out_dev->dunlock();
+ out_dev->Unlock();
if (!acquire_device_for_append(out_jcr->dcr)) {
free_jcr(in_jcr);
exit(1);
if (!dcr->is_dev_locked()) { /* device already locked? */
/* note, do not change this to dcr->r_dlock */
- dev->r_dlock(); /* no, lock it */
+ dev->rLock(); /* no, lock it */
}
/*
bail_out:
if (!dcr->is_dev_locked()) { /* did we lock dev above? */
/* note, do not change this to dcr->dunlock */
- dev->dunlock(); /* unlock it now */
+ dev->Unlock(); /* unlock it now */
}
return stat;
}
bool ok;
Dmsg0(250, "Enter read_block_from_device\n");
- dev->r_dlock();
+ dev->rLock();
ok = read_block_from_dev(check_block_numbers);
- dev->dunlock();
+ dev->Unlock();
Dmsg0(250, "Leave read_block_from_device\n");
return ok;
}
bool ok = true;
block = new_block(dev);
- dev->r_dlock();
+ dev->rLock();
Dmsg1(200, "Opening device %s\n", dcr->VolumeName);
if (!dev->open(dcr, OPEN_READ_WRITE)) {
Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg);
dev->set_append(); /* put volume in append mode */
bail_out:
- dev->dunlock();
+ dev->Unlock();
free_block(block);
return ok;
}
DEV_BLOCK *tblock;
uint32_t this_file, this_block_num;
- dev->r_dlock();
+ dev->rLock();
if (!this_block) {
this_block = new_block(dev);
}
if (!fixup_device_block_write_error(jcr->dcr)) {
Pmsg1(000, _("Cannot fixup device error. %s\n"), dev->bstrerror());
ok = false;
- dev->dunlock();
+ dev->Unlock();
return 0;
}
BlockNumber = 0; /* start counting for second tape */
}
- dev->dunlock();
+ dev->Unlock();
return 1; /* end of tape reached */
}
last_file = this_file;
last_block_num = this_block_num;
- dev->dunlock();
+ dev->Unlock();
return 1;
}
* Kern Sibbald, MM
*
* NOTE!!!! None of these routines are reentrant. You must
- * use dev->r_dlock() and dev->unlock() at a higher level,
+ * use dev->rLock() and dev->Unlock() at a higher level,
* or use the xxx_device() equivalents. By moving the
* thread synchronization to a higher level, we permit
* the higher level routines to "seize" the device and
dev->errmsg = get_pool_memory(PM_EMSG);
*dev->errmsg = 0;
- if ((errstat = pthread_mutex_init(&dev->m_mutex, NULL)) != 0) {
+ if ((errstat = dev->init_mutex()) != 0) {
berrno be;
dev->dev_errno = errstat;
Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
if ((errstat = pthread_mutex_init(&dev->spool_mutex, NULL)) != 0) {
berrno be;
dev->dev_errno = errstat;
- Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
+ Mmsg1(dev->errmsg, _("Unable to init spool mutex: ERR=%s\n"), be.bstrerror(errstat));
Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
}
- if ((errstat = pthread_mutex_init(&dev->acquire_mutex, NULL)) != 0) {
+ if ((errstat = dev->init_acquire_mutex()) != 0) {
berrno be;
dev->dev_errno = errstat;
- Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
+ Mmsg1(dev->errmsg, _("Unable to init acquire mutex: ERR=%s\n"), be.bstrerror(errstat));
Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
}
- /* Ensure that we respect this order in P/V operations */
- bthread_mutex_set_priority(&dev->m_mutex, PRIO_SD_DEV_ACCESS);
- bthread_mutex_set_priority(&dev->spool_mutex, PRIO_SD_DEV_SPOOL);
- bthread_mutex_set_priority(&dev->acquire_mutex, PRIO_SD_DEV_ACQUIRE);
- if ((errstat = pthread_mutex_init(&dev->read_acquire_mutex, NULL)) != 0) {
+ if ((errstat = dev->init_read_acquire_mutex()) != 0) {
berrno be;
dev->dev_errno = errstat;
- Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
+ Mmsg1(dev->errmsg, _("Unable to init read acquire mutex: ERR=%s\n"), be.bstrerror(errstat));
Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
}
+
+ dev->set_mutex_priorities();
+
+
#ifdef xxx
if ((errstat = rwl_init(&dev->lock)) != 0) {
berrno be;
* Locking and blocking calls
*/
#ifdef SD_DEBUG_LOCK
- void _r_dlock(const char *, int, bool locked=false); /* 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 */
+ void dbg_rLock(const char *, int, bool locked=false); /* in lock.c */
+ void dbg_rUnlock(const char *, int); /* in lock.c */
+ void dbg_Lock(const char *, int); /* in lock.c */
+ void dbg_Unlock(const char *, int); /* in lock.c */
+ void dbg_Lock_acquire(const char *, int); /* in lock.c */
+ void dbg_Unlock_acquire(const char *, int); /* in lock.c */
+ void dbg_Lock_read_acquire(const char *, int); /* in lock.c */
+ void dbg_Unlock_read_acquire(const char *, int); /* in lock.c */
#else
- void r_dlock(bool locked=false); /* in lock.c */
- void r_dunlock() { dunlock(); }
- void dlock() { P(m_mutex); }
- void dunlock() { V(m_mutex); }
+ void rLock(bool locked=false); /* in lock.c */
+ void rUnlock(); /* in lock.c */
+ void Lock(); /* in lock.c */
+ void Unlock(); /* in lock.c */
+ void Lock_acquire(); /* in lock.c */
+ void Unlock_acquire(); /* in lock.c */
+ void Lock_read_acquire(); /* in lock.c */
+ void Unlock_read_acquire(); /* in lock.c */
+ void Lock_VolCatInfo(); /* in lock.c */
+ void Unlock_VolCatInfo(); /* in lock.c */
#endif
+ int init_mutex(); /* in lock.c */
+ int init_acquire_mutex(); /* in lock.c */
+ int init_read_acquire_mutex(); /* in lock.c */
+ int init_volcat_mutex(); /* in lock.c */
+ int init_adata_mutex(); /* in lock.c */
+ void set_mutex_priorities(); /* in lock.c */
+ int next_vol_timedwait(const struct timespec *timeout); /* in lock.c */
void dblock(int why); /* in lock.c */
void dunblock(bool locked=false); /* in lock.c */
bool is_device_unmounted(); /* in lock.c */
class DCR {
private:
bool m_dev_locked; /* set if dev already locked */
+ int m_dev_lock; /* non-zero if rLock already called */
bool m_reserved; /* set if reserved device */
bool m_found_in_use; /* set if a volume found in use */
dlink dev_link; /* link to attach to dev */
JCR *jcr; /* pointer to JCR */
bthread_mutex_t m_mutex; /* access control */
+ pthread_mutex_t r_mutex; /* rLock pre-mutex */
DEVICE * volatile dev; /* pointer to device */
DEVRES *device; /* pointer to device resource */
DEV_BLOCK *block; /* pointer to block */
/* Methods */
void set_dev(DEVICE *ndev) { dev = ndev; };
+ void inc_dev_lock() { m_dev_lock++; };
+ void dec_dev_lock() { m_dev_lock--; };
bool found_in_use() const { return m_found_in_use; };
void set_found_in_use() { m_found_in_use = true; };
void clear_found_in_use() { m_found_in_use = false; };
/* Methods in lock.c */
void dblock(int why) { dev->dblock(why); }
-#ifdef SD_DEBUG_LOCK
- void _dlock(const char *, int); /* in lock.c */
- void _dunlock(const char *, int); /* in lock.c */
+#ifdef SD_DEBUG_LOCK
+ void dbg_mLock(const char *, int, bool locked); /* in lock.c */
+ void dbg_mUnlock(const char *, int); /* in lock.c */
#else
- void dlock() { dev->dlock(); m_dev_locked = true; }
- void dunlock() { m_dev_locked = false; dev->dunlock(); }
+ void mLock(bool locked);
+ void mUnlock();
#endif
/* Methods in record.c */
block_device(dev, BST_DOING_ACQUIRE);
/* Continue unlocked, but leave BLOCKED */
- dev->dunlock();
+ dev->Unlock();
bstrncpy(PrevVolName, dev->getVolCatName(), sizeof(PrevVolName));
bstrncpy(dev->VolHdr.PrevVolumeName, PrevVolName, sizeof(dev->VolHdr.PrevVolumeName));
if (!dcr->mount_next_write_volume()) {
free_block(label_blk);
dcr->block = block;
- dev->dlock();
+ dev->Lock();
goto bail_out;
}
Dmsg2(050, "must_unload=%d dev=%s\n", dev->must_unload(), dev->print_name());
- dev->dlock(); /* lock again */
+ dev->Lock(); /* lock again */
dev->VolCatInfo.VolCatJobs++; /* increment number of jobs on vol */
dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
return false;
}
- dev->r_dlock();
+ dev->rLock();
/* Defer opening files */
if (!dev->is_tape()) {
Dmsg1(129, "open dev %s OK\n", dev->print_name());
bail_out:
- dev->dunlock();
+ dev->Unlock();
return ok;
}
dcr = find_device(jcr, dev_name, drive);
if (dcr) {
dev = dcr->dev;
- dev->dlock(); /* Use P to avoid indefinite block */
+ dev->Lock(); /* Use P to avoid indefinite block */
if (!dev->is_open() && !dev->is_busy()) {
Dmsg1(400, "Can %slabel. Device is not open\n", relabel?"re":"");
label_volume_if_ok(dcr, oldname, newname, poolname, slot, relabel);
Dmsg0(400, "Can relabel. device not used\n");
label_volume_if_ok(dcr, oldname, newname, poolname, slot, relabel);
}
- dev->dunlock();
+ dev->Unlock();
free_dcr(dcr);
} else {
dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), dev_name.c_str());
dcr = find_device(jcr, devname, drive);
if (dcr) {
dev = dcr->dev;
- dev->dlock(); /* Use P to avoid indefinite block */
+ dev->Lock(); /* Use P to avoid indefinite block */
Dmsg2(100, "mount cmd blocked=%d must_unload=%d\n", dev->blocked(),
dev->must_unload());
switch (dev->blocked()) { /* device blocked? */
dir->fsend(_("3905 Unknown wait state %d\n"), dev->blocked());
break;
}
- dev->dunlock();
+ dev->Unlock();
free_dcr(dcr);
} else {
dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
dcr = find_device(jcr, devname, drive);
if (dcr) {
dev = dcr->dev;
- dev->dlock(); /* Use P to avoid indefinite block */
+ dev->Lock(); /* Use P to avoid indefinite block */
if (!dev->is_open()) {
if (!dev->is_busy()) {
unload_autochanger(dcr, -1);
dev->print_name());
}
}
- dev->dunlock();
+ dev->Unlock();
free_dcr(dcr);
} else {
dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
dcr = find_device(jcr, devname, drive);
if (dcr) {
dev = dcr->dev;
- dev->dlock(); /* Use P to avoid indefinite block */
+ dev->Lock(); /* Use P to avoid indefinite block */
if (!dev->is_open()) {
if (!dev->is_busy()) {
unload_autochanger(dcr, -1);
dir->fsend(_("3022 Device \"%s\" released.\n"),
dev->print_name());
}
- dev->dunlock();
+ dev->Unlock();
free_dcr(dcr);
} else {
dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
dcr = find_device(jcr, devname, -1);
if (dcr) {
dev = dcr->dev;
- dev->dlock(); /* Use P to avoid indefinite block */
+ dev->Lock(); /* Use P to avoid indefinite block */
if (!dev->device->changer_res) {
dir->fsend(_("3998 Device \"%s\" is not an autochanger.\n"),
dev->print_name());
} else { /* device not being used */
autochanger_cmd(dcr, dir, cmd);
}
- dev->dunlock();
+ dev->Unlock();
free_dcr(dcr);
} else {
dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
dcr = find_device(jcr, devname, drive);
if (dcr) {
dev = dcr->dev;
- dev->dlock(); /* Use P to avoid indefinite block */
+ dev->Lock(); /* Use P to avoid indefinite block */
if (!dev->is_open()) {
read_volume_label(jcr, dcr, dev, Slot);
dev->close();
} else { /* device not being used */
read_volume_label(jcr, dcr, dev, Slot);
}
- dev->dunlock();
+ dev->Unlock();
free_dcr(dcr);
} else {
dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-2012 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.
/*
* Collection of Bacula Storage daemon locking software
*
- * Kern Sibbald, 2000-2007. June 2007
+ * Kern Sibbald, June 2007
*
*/
* 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
+ * 2. Lock() simple mutex that locks the device structure. A Lock
* can be acquired while a device is blocked if it is not
* locked.
- * 3. r_dlock(locked) "recursive" dlock, when means that a dlock (mutex)
+ * 3. rLock(locked) "recursive" Lock, when means that a Lock (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.
* Can be called with locked true, which means the
- * dlock is already set
+ * Lock is already set
*
* A lock is normally set when modifying the device structure.
- * A r_lock is normally acquired when you want to block the device
+ * A rLock 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.
* 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.
+ * the block will block if rLock is called.
* A device can be blocked for multiple reasons, labeling, writing,
* acquiring (opening) the device, waiting for the operator, unmounted,
* ...
*
* Functions:
*
- * DEVICE::dlock() does P(m_mutex) (in dev.h)
- * DEVICE::dunlock() does V(m_mutex)
+ * DEVICE::Lock() does P(m_mutex) (in dev.h)
+ * DEVICE::Unlock() does V(m_mutex)
*
- * DEVICE::r_dlock(locked) allows locking the device when this thread
+ * DEVICE::rLock(locked) allows locking the device when this thread
* already has the device blocked.
* if (!locked)
- * dlock()
+ * Lock()
* if blocked and not same thread that locked
* pthread_cond_wait
* leaves device locked
*
- * DEVICE::r_dunlock() unlocks but does not unblock
- * same as dunlock();
+ * DEVICE::rUnlock() unlocks but does not unblock
+ * same as Unlock();
*
* DEVICE::dblock(why) does
- * r_dlock(); (recursive device lock)
+ * rLock(); (recursive device lock)
* block_device(this, why)
- * r_dunlock()
+ * rUnlock()
*
* DEVICE::dunblock does
- * dlock()
+ * Lock()
* unblock_device()
- * dunlock()
+ * Unlock()
*
* block_device() does (must be locked and not blocked at entry)
* set blocked status
* save status
* set new blocked status
* set new pid
- * unlock()
+ * Unlock()
*
* give_back_device_lock() does (must be blocked but not locked)
- * dlock()
+ * Lock()
* reset blocked status
* save previous blocked
* reset pid
*
*/
-
void DEVICE::dblock(int why)
{
- r_dlock(); /* need recursive lock to block */
+ rLock(false); /* need recursive lock to block */
block_device(this, why);
- r_dunlock();
+ rUnlock();
}
void DEVICE::dunblock(bool locked)
{
if (!locked) {
- dlock();
+ Lock();
}
unblock_device(this);
- dunlock();
+ Unlock();
}
#ifdef SD_DEBUG_LOCK
-void DCR::_dlock(const char *file, int line)
+
+/*
+ * Debug DCR locks N.B.
+ *
+ */
+void DCR::dbg_mLock(const char *file, int line, bool locked)
{
- dev->_dlock(file, line);
- m_dev_locked = true;
+ real_P(r_mutex);
+ if (is_dev_locked()) {
+ real_V(r_mutex);
+ return;
+ }
+ Dmsg3(sd_dbglvl, "mLock %d from %s:%d\n", locked, file, line);
+ dev->dbg_rLock(file,line,locked);
+ inc_dev_lock();
+ real_V(r_mutex);
+ return;
}
-void DCR::_dunlock(const char *file, int line)
-{
- m_dev_locked = false;
- dev->_dunlock(file, line);
+void DCR::dbg_mUnlock(const char *file, int line)
+{
+ Dmsg2(sd_dbglvl, "mUnlock from %s:%d\n", file, line);
+ real_P(r_mutex);
+ if (!is_dev_locked()) {
+ real_P(r_mutex);
+ ASSERT2(0, "Call on dcr mUnlock when not locked");
+ return;
+ }
+ dec_dev_lock();
+ /* When the count goes to zero, unlock it */
+ if (!is_dev_locked()) {
+ dev->dbg_rUnlock(file,line);
+ }
+ real_V(r_mutex);
+ return;
}
-void DEVICE::_dlock(const char *file, int line)
+/*
+ * Debug DEVICE locks N.B.
+ *
+ */
+void DEVICE::dbg_Lock(const char *file, int line)
{
- Dmsg3(sd_dbglvl, "dlock from %s:%d precnt=%d\n", file, line, m_count);
+ Dmsg3(sd_dbglvl, "Lock from %s:%d precnt=%d\n", file, line, m_count);
/* Note, this *really* should be protected by a mutex, but
* since it is only debug code we don't worry too much.
*/
get_jobid_from_tid(m_pid),
file, line, m_count);
}
- P(m_mutex);
+ bthread_mutex_lock_p(&m_mutex, file, line);
m_pid = pthread_self();
m_count++;
}
-void DEVICE::_dunlock(const char *file, int line)
+void DEVICE::dbg_Unlock(const char *file, int line)
{
m_count--;
- Dmsg3(sd_dbglvl+1, "dunlock from %s:%d postcnt=%d\n", file, line, m_count);
- V(m_mutex);
+ Dmsg3(sd_dbglvl, "Unlock from %s:%d postcnt=%d\n", file, line, m_count);
+ bthread_mutex_unlock_p(&m_mutex, file, line);
+}
+
+void DEVICE::dbg_rUnlock(const char *file, int line)
+{
+ Dmsg2(sd_dbglvl, "rUnlock from %s:%d\n", file, line);
+ dbg_Unlock(file, line);
+}
+
+void DEVICE::dbg_Lock_acquire(const char *file, int line)
+{
+ Dmsg2(sd_dbglvl, "Lock_acquire from %s:%d\n", file, line);
+ bthread_mutex_lock_p(&acquire_mutex, file, line);
+}
+
+void DEVICE::dbg_Unlock_acquire(const char *file, int line)
+{
+ Dmsg2(sd_dbglvl, "Unlock_acquire from %s:%d\n", file, line);
+ bthread_mutex_unlock_p(&acquire_mutex, file, line);
}
-void DEVICE::_r_dunlock(const char *file, int line)
+void DEVICE::dbg_Lock_read_acquire(const char *file, int line)
{
- this->_dunlock(file, line);
+ Dmsg2(sd_dbglvl, "Lock_read_acquire from %s:%d\n", file, line);
+ bthread_mutex_lock_p(&read_acquire_mutex, file, line);
+}
+
+void DEVICE::dbg_Unlock_read_acquire(const char *file, int line)
+{
+ Dmsg2(sd_dbglvl, "Unlock_read_acquire from %s:%d\n", file, line);
+ bthread_mutex_unlock_p(&read_acquire_mutex, file, line);
+}
+
+
+#else
+
+/*
+ * DCR locks N.B.
+ *
+ */
+/* Multiple rLock implementation */
+void DCR::mLock(bool locked)
+{
+ P(r_mutex);
+ if (is_dev_locked()) {
+ V(r_mutex);
+ return;
+ }
+ dev->rLock(locked);
+ inc_dev_lock();
+ V(r_mutex);
+ return;
+}
+
+/* Multiple rUnlock implementation */
+void DCR::mUnlock()
+{
+ P(r_mutex);
+ if (!is_dev_locked()) {
+ V(r_mutex);
+ ASSERT2(0, "Call on dcr mUnlock when not locked");
+ return;
+ }
+ dec_dev_lock();
+ /* When the count goes to zero, unlock it */
+ if (!is_dev_locked()) {
+ dev->rUnlock();
+ }
+ V(r_mutex);
+ return;
+}
+
+/*
+ * DEVICE locks N.B.
+ *
+ */
+
+void DEVICE::rUnlock()
+{
+ Unlock();
+}
+
+void DEVICE::Lock()
+{
+ P(m_mutex);
+}
+
+void DEVICE::Unlock()
+{
+ V(m_mutex);
+}
+
+void DEVICE::Lock_acquire()
+{
+ P(acquire_mutex);
+}
+
+void DEVICE::Unlock_acquire()
+{
+ V(acquire_mutex);
+}
+
+void DEVICE::Lock_read_acquire()
+{
+ P(read_acquire_mutex);
+}
+
+void DEVICE::Unlock_read_acquire()
+{
+ V(read_acquire_mutex);
}
#endif
+/* Main device access control */
+int DEVICE::init_mutex()
+{
+ return pthread_mutex_init(&m_mutex, NULL);
+}
+
+/* Write device acquire mutex */
+int DEVICE::init_acquire_mutex()
+{
+ return pthread_mutex_init(&acquire_mutex, NULL);
+}
+
+/* Read device acquire mutex */
+int DEVICE::init_read_acquire_mutex()
+{
+ return pthread_mutex_init(&read_acquire_mutex, NULL);
+}
+
+/* Set order in which device locks must be acquired */
+void DEVICE::set_mutex_priorities()
+{
+ /* Ensure that we respect this order in P/V operations */
+ bthread_mutex_set_priority(&m_mutex, PRIO_SD_DEV_ACCESS);
+ bthread_mutex_set_priority(&spool_mutex, PRIO_SD_DEV_SPOOL);
+ bthread_mutex_set_priority(&acquire_mutex, PRIO_SD_DEV_ACQUIRE);
+}
+
+int DEVICE::next_vol_timedwait(const struct timespec *timeout)
+{
+ return pthread_cond_timedwait(&wait_next_vol, &m_mutex, timeout);
+}
+
/*
* This is a recursive lock that checks if the device is blocked.
* and preparing the label.
*/
#ifdef SD_DEBUG_LOCK
-void DEVICE::_r_dlock(const char *file, int line, bool locked)
+void DEVICE::dbg_rLock(const char *file, int line, bool locked)
{
- Dmsg3(sd_dbglvl+1, "r_dlock blked=%s from %s:%d\n", this->print_blocked(),
+ Dmsg3(sd_dbglvl, "rLock blked=%s from %s:%d\n", print_blocked(),
file, line);
+ if (!locked) {
+ /* lockmgr version of P(m_mutex) */
+ bthread_mutex_lock_p(&m_mutex, file, line);
+ m_count++;
+ }
#else
-void DEVICE::r_dlock(bool locked)
+void DEVICE::rLock(bool locked)
{
-#endif
- int stat;
if (!locked) {
- P(m_mutex); /* this->dlock(); */
- m_count++; /* this->dlock() */
+ Lock();
+ m_count++;
}
- if (this->blocked() && !pthread_equal(this->no_wait_id, pthread_self())) {
- this->num_waiting++; /* indicate that I am waiting */
- while (this->blocked()) {
+#endif
+
+ if (blocked() && !pthread_equal(no_wait_id, pthread_self())) {
+ num_waiting++; /* indicate that I am waiting */
+ while (blocked()) {
+ int stat;
#ifndef HAVE_WIN32
/* thread id on Win32 may be a struct */
- Dmsg3(sd_dbglvl, "r_dlock blked=%s no_wait=%p me=%p\n", this->print_blocked(),
- this->no_wait_id, pthread_self());
+ Dmsg3(sd_dbglvl, "rLock blked=%s no_wait=%p me=%p\n", print_blocked(),
+ no_wait_id, pthread_self());
#endif
if ((stat = pthread_cond_wait(&this->wait, &m_mutex)) != 0) {
berrno be;
- this->dunlock();
+ this->Unlock();
Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
be.bstrerror(stat));
}
}
- this->num_waiting--; /* no longer waiting */
+ num_waiting--; /* no longer waiting */
}
}
/*
* Block all other threads from using the device
* Device must already be locked. After this call,
- * the device is blocked to any thread calling dev->r_lock(),
+ * the device is blocked to any thread calling dev->rLock(),
* but the device is not locked (i.e. no P on device). Also,
- * the current thread can do slip through the dev->r_lock()
+ * the current thread can do slip through the dev->rLock()
* calls without blocking.
*/
void _block_device(const char *file, int line, DEVICE *dev, int state)
*/
void _steal_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state)
{
-
Dmsg3(sd_dbglvl, "steal lock. old=%s from %s:%d\n", dev->print_blocked(),
file, line);
hold->dev_blocked = dev->blocked();
dev->set_blocked(state);
Dmsg1(sd_dbglvl, "steal lock. new=%s\n", dev->print_blocked());
dev->no_wait_id = pthread_self();
- dev->dunlock();
+ dev->Unlock();
}
/*
{
Dmsg3(sd_dbglvl, "return lock. old=%s from %s:%d\n",
dev->print_blocked(), file, line);
- dev->dlock();
+ dev->Lock();
dev->set_blocked(hold->dev_blocked);
dev->dev_prev_blocked = hold->dev_prev_blocked;
dev->no_wait_id = hold->no_wait_id;
bool DEVICE::is_device_unmounted()
{
bool stat;
+
int blk = blocked();
stat = (blk == BST_UNMOUNTED) ||
(blk == BST_UNMOUNTED_WAITING_FOR_SYSOP);
* End Of Tape -- mount next Volume (if another specified)
*/
if (jcr->NumReadVolumes > 1 && jcr->CurReadVolume < jcr->NumReadVolumes) {
- dev->dlock();
+ dev->Lock();
dev->close();
dev->set_read();
dcr->set_reserved();
- dev->dunlock();
+ 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);
*/
void DCR::unreserve_device()
{
- dev->dlock();
+ dev->Lock();
lock_volumes();
if (is_reserved()) {
clear_reserved();
}
}
unlock_volumes();
- dev->dunlock();
+ dev->Unlock();
}
/*
return false;
}
- dev->dlock();
+ dev->Lock();
if (dev->is_device_unmounted()) {
Dmsg1(dbglvl, "Device %s is BLOCKED due to user unmount.\n", dev->print_name());
ok = true;
bail_out:
- dev->dunlock();
+ dev->Unlock();
return ok;
}
return false;
}
- dev->dlock();
+ dev->Lock();
/* If device is being read, we cannot write it */
if (dev->can_read()) {
ok = true;
bail_out:
- dev->dunlock();
+ dev->Unlock();
return ok;
}
{
DCR *dcr;
bool found_jcr = false;
- dev->dlock();
+ dev->Lock();
foreach_dlist(dcr, dev->attached_dcrs) {
if (dcr->jcr->JobStatus == JS_WaitMount) {
len = Mmsg(msg, _(" Device is BLOCKED waiting for mount of volume \"%s\",\n"
found_jcr = true;
}
}
- dev->dunlock();
+ dev->Unlock();
if (!found_jcr) {
len = Mmsg(msg, _(" Device is BLOCKED waiting for media.\n"));
sendit(msg, len, sp);
sendit(msg, len, sp);
DCR *dcr = NULL;
bool found = false;
- dev->dlock();
+ dev->Lock();
foreach_dlist(dcr, dev->attached_dcrs) {
if (dcr->jcr) {
if (found) {
found = true;
}
}
- dev->dunlock();
+ dev->Unlock();
sendit("\n", 1, sp);
len = Mmsg(msg, _("Device parameters:\n"));
DEVICE *dev = dcr->dev;
JCR *jcr = dcr->jcr;
- dev->dlock();
+ dev->Lock();
Dmsg1(dbglvl, "Enter blocked=%s\n", dev->print_blocked());
/*
Dmsg1(dbglvl, "set %s\n", dev->print_blocked());
}
Dmsg1(dbglvl, "Exit blocked=%s\n", dev->print_blocked());
- dev->dunlock();
+ dev->Unlock();
return stat;
}