From: Kern Sibbald Date: Tue, 26 Jun 2007 14:41:57 +0000 (+0000) Subject: New file X-Git-Tag: Release-7.0.0~6069 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=2edc13e0e548987cdedcd0d4205e6e6c753c5a88;p=bacula%2Fbacula New file git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@5099 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/src/stored/Makefile.in b/bacula/src/stored/Makefile.in index 6e9456ae3b..490cb26483 100644 --- a/bacula/src/stored/Makefile.in +++ b/bacula/src/stored/Makefile.in @@ -25,40 +25,40 @@ SDOBJS = stored.o ansi_label.o \ askdir.o authenticate.o \ block.o butil.o dev.o \ device.o dircmd.o dvd.o ebcdic.o fd_cmds.o job.o \ - label.o mac.o match_bsr.o mount.o parse_bsr.o \ + label.o locks.o mac.o match_bsr.o mount.o parse_bsr.o \ pythonsd.o read.o read_record.o record.o \ reserve.o scan.o \ spool.o status.o stored_conf.o wait.o # btape TAPEOBJS = btape.o block.o butil.o dev.o device.o label.o \ - ansi_label.o dvd.o ebcdic.o \ + locks.o ansi_label.o dvd.o ebcdic.o \ autochanger.o acquire.o mount.o record.o read_record.o \ reserve.o \ stored_conf.o match_bsr.o parse_bsr.o scan.o spool.o wait.o # bls BLSOBJS = bls.o block.o butil.o device.o dev.o label.o match_bsr.o \ - ansi_label.o dvd.o ebcdic.o \ + ansi_label.o dvd.o ebcdic.o locks.o \ autochanger.o acquire.o mount.o parse_bsr.o record.o \ read_record.o reserve.o scan.o stored_conf.o spool.o wait.o # bextract BEXTOBJS = bextract.o block.o device.o dev.o label.o record.o \ - ansi_label.o dvd.o ebcdic.o \ + ansi_label.o dvd.o ebcdic.o locks.o \ autochanger.o acquire.o mount.o match_bsr.o parse_bsr.o butil.o \ pythonsd.o read_record.o reserve.o \ scan.o stored_conf.o spool.o wait.o # bscan SCNOBJS = bscan.o block.o device.o dev.o label.o \ - ansi_label.o dvd.o ebcdic.o \ + ansi_label.o dvd.o ebcdic.o locks.o \ autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \ butil.o read_record.o scan.o reserve.o stored_conf.o spool.o wait.o # bcopy COPYOBJS = bcopy.o block.o device.o dev.o label.o \ - ansi_label.o dvd.o ebcdic.o \ + ansi_label.o dvd.o ebcdic.o locks.o \ autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \ butil.o read_record.o reserve.o \ scan.o stored_conf.o spool.o wait.o diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index 77f6cfd62d..08dc97f67a 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -781,44 +781,6 @@ bool DEVICE::rewind(DCR *dcr) return true; } -void DEVICE::block(int why) -{ - r_dlock(); /* need recursive lock to block */ - block_device(this, why); - r_dunlock(); -} - -void DEVICE::unblock(bool locked) -{ - if (!locked) { - dlock(); - } - unblock_device(this); - dunlock(); -} - - -const char *DEVICE::print_blocked() const -{ - switch (m_blocked) { - case BST_NOT_BLOCKED: - return "BST_NOT_BLOCKED"; - case BST_UNMOUNTED: - return "BST_UNMOUNTED"; - case BST_WAITING_FOR_SYSOP: - return "BST_WAITING_FOR_SYSOP"; - case BST_DOING_ACQUIRE: - return "BST_DOING_ACQUIRE"; - case BST_WRITING_LABEL: - return "BST_WRITING_LABEL"; - case BST_UNMOUNTED_WAITING_FOR_SYSOP: - return "BST_UNMOUNTED_WAITING_FOR_SYSOP"; - case BST_MOUNT: - return "BST_MOUNT"; - default: - return _("unknown blocked code"); - } -} /* * Called to indicate that we have just read an diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 91c421d818..bb8d33ed7d 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -393,8 +393,8 @@ public: #endif void clear_volhdr(); /* in dev.c */ - void block(int why); /* in dev.c */ - void unblock(bool locked=false); /* 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 */ diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index c57b9151dc..e864226b36 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -59,13 +59,6 @@ #include "bacula.h" /* pull in global headers */ #include "stored.h" /* pull in Storage Deamon headers */ -#ifdef SD_DEBUG_LOCK -const int dbglvl = 0; -#else -const int dbglvl = 500; -#endif - - /* Forward referenced functions */ /* @@ -322,155 +315,3 @@ bool open_device(DCR *dcr) } return true; } - - -/* - * Check if the device is blocked or not - */ -bool is_device_unmounted(DEVICE *dev) -{ - bool stat; - int blocked = dev->blocked(); - stat = (blocked == BST_UNMOUNTED) || - (blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP); - return stat; -} - -#ifdef SD_DEBUG_LOCK -void DEVICE::_dlock(const char *file, int line) -{ - Dmsg4(sd_dbglvl, "dlock from %s:%d precnt=%d JobId=%u\n", file, line, - m_count, get_jobid_from_tid()); - /* Note, this *really* should be protected by a mutex, but - * since it is only debug code we don't worry too much. - */ - if (m_count > 0 && pthread_equal(m_pid, pthread_self())) { - Dmsg5(sd_dbglvl, "Possible DEADLOCK!! lock held by JobId=%u from %s:%d m_count=%d JobId=%u\n", - get_jobid_from_tid(m_pid), - file, line, m_count, get_jobid_from_tid()); - } - P(m_mutex); - m_pid = pthread_self(); - m_count++; -} - -void DEVICE::_dunlock(const char *file, int line) -{ - m_count--; - Dmsg4(sd_dbglvl+1, "dunlock from %s:%d postcnt=%d JobId=%u\n", file, line, - m_count, get_jobid_from_tid()); - V(m_mutex); -} - -void DEVICE::_r_dunlock(const char *file, int line) -{ - this->_dunlock(file, line); -} - -#endif - - -/* - * This is a recursive lock that checks if the device is blocked. - * - * When blocked is set, all threads EXCEPT thread with id no_wait_id - * must wait. The no_wait_id thread is out obtaining a new volume - * and preparing the label. - */ -#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()); -#endif - this->dlock(); - if (this->blocked() && !pthread_equal(this->no_wait_id, pthread_self())) { - this->num_waiting++; /* indicate that I am waiting */ - while (this->blocked()) { - Dmsg3(sd_dbglvl, "r_dlock blked=%s no_wait=%p me=%p\n", this->print_blocked(), - this->no_wait_id, pthread_self()); - if ((stat = pthread_cond_wait(&this->wait, &m_mutex)) != 0) { - berrno be; - this->dunlock(); - Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"), - be.bstrerror(stat)); - } - } - this->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(), - * but the device is not locked (i.e. no P on device). Also, - * the current thread can do slip through the dev->r_lock() - * calls without blocking. - */ -void _block_device(const char *file, int line, DEVICE *dev, int state) -{ - ASSERT(dev->blocked() == BST_NOT_BLOCKED); - dev->set_blocked(state); /* make other threads wait */ - dev->no_wait_id = pthread_self(); /* allow us to continue */ - Dmsg3(sd_dbglvl, "set blocked=%s from %s:%d\n", dev->print_blocked(), file, line); -} - -/* - * Unblock the device, and wake up anyone who went to sleep. - * Enter: device locked - * Exit: device locked - */ -void _unblock_device(const char *file, int line, DEVICE *dev) -{ - Dmsg3(sd_dbglvl, "unblock %s from %s:%d\n", dev->print_blocked(), file, line); - ASSERT(dev->blocked()); - dev->set_blocked(BST_NOT_BLOCKED); - dev->no_wait_id = 0; - if (dev->num_waiting > 0) { - pthread_cond_broadcast(&dev->wait); /* wake them up */ - } -} - -/* - * Enter with device locked and blocked - * Exit with device unlocked and blocked by us. - */ -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(); - hold->dev_prev_blocked = dev->dev_prev_blocked; - hold->no_wait_id = dev->no_wait_id; - dev->set_blocked(state); - Dmsg1(sd_dbglvl, "steal lock. new=%s\n", dev->print_blocked()); - dev->no_wait_id = pthread_self(); - dev->dunlock(); -} - -/* - * Enter with device blocked by us but not locked - * Exit with device locked, and blocked by previous owner - */ -void _give_back_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold) -{ - Dmsg3(sd_dbglvl, "return lock. old=%s from %s:%d\n", - dev->print_blocked(), file, line); - dev->dlock(); - dev->set_blocked(hold->dev_blocked); - dev->dev_prev_blocked = hold->dev_prev_blocked; - dev->no_wait_id = hold->no_wait_id; - Dmsg1(sd_dbglvl, "return lock. new=%s\n", dev->print_blocked()); - if (dev->num_waiting > 0) { - pthread_cond_broadcast(&dev->wait); /* wake them up */ - } -} diff --git a/bacula/src/stored/locks.c b/bacula/src/stored/locks.c new file mode 100644 index 0000000000..c57559dbf4 --- /dev/null +++ b/bacula/src/stored/locks.c @@ -0,0 +1,236 @@ +/* + 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. +*/ +/* + * Collection of Bacula Storage daemon locking software + * + * Kern Sibbald, 2000-2007. June 2007 + * + * Version $Id$ + */ + +#include "bacula.h" /* pull in global headers */ +#include "stored.h" /* pull in Storage Deamon headers */ + +#ifdef SD_DEBUG_LOCK +const int dbglvl = 0; +#else +const int dbglvl = 500; +#endif + + +void DEVICE::block(int why) +{ + r_dlock(); /* need recursive lock to block */ + block_device(this, why); + r_dunlock(); +} + +void DEVICE::unblock(bool locked) +{ + if (!locked) { + dlock(); + } + unblock_device(this); + dunlock(); +} + + +#ifdef SD_DEBUG_LOCK +void DEVICE::_dlock(const char *file, int line) +{ + Dmsg4(sd_dbglvl, "dlock from %s:%d precnt=%d JobId=%u\n", file, line, + m_count, get_jobid_from_tid()); + /* Note, this *really* should be protected by a mutex, but + * since it is only debug code we don't worry too much. + */ + if (m_count > 0 && pthread_equal(m_pid, pthread_self())) { + Dmsg5(sd_dbglvl, "Possible DEADLOCK!! lock held by JobId=%u from %s:%d m_count=%d JobId=%u\n", + get_jobid_from_tid(m_pid), + file, line, m_count, get_jobid_from_tid()); + } + P(m_mutex); + m_pid = pthread_self(); + m_count++; +} + +void DEVICE::_dunlock(const char *file, int line) +{ + m_count--; + Dmsg4(sd_dbglvl+1, "dunlock from %s:%d postcnt=%d JobId=%u\n", file, line, + m_count, get_jobid_from_tid()); + V(m_mutex); +} + +void DEVICE::_r_dunlock(const char *file, int line) +{ + this->_dunlock(file, line); +} + +#endif + + +/* + * This is a recursive lock that checks if the device is blocked. + * + * When blocked is set, all threads EXCEPT thread with id no_wait_id + * must wait. The no_wait_id thread is out obtaining a new volume + * and preparing the label. + */ +#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()); +#endif + this->dlock(); + if (this->blocked() && !pthread_equal(this->no_wait_id, pthread_self())) { + this->num_waiting++; /* indicate that I am waiting */ + while (this->blocked()) { + Dmsg3(sd_dbglvl, "r_dlock blked=%s no_wait=%p me=%p\n", this->print_blocked(), + this->no_wait_id, pthread_self()); + if ((stat = pthread_cond_wait(&this->wait, &m_mutex)) != 0) { + berrno be; + this->dunlock(); + Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"), + be.bstrerror(stat)); + } + } + this->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(), + * but the device is not locked (i.e. no P on device). Also, + * the current thread can do slip through the dev->r_lock() + * calls without blocking. + */ +void _block_device(const char *file, int line, DEVICE *dev, int state) +{ + ASSERT(dev->blocked() == BST_NOT_BLOCKED); + dev->set_blocked(state); /* make other threads wait */ + dev->no_wait_id = pthread_self(); /* allow us to continue */ + Dmsg3(sd_dbglvl, "set blocked=%s from %s:%d\n", dev->print_blocked(), file, line); +} + +/* + * Unblock the device, and wake up anyone who went to sleep. + * Enter: device locked + * Exit: device locked + */ +void _unblock_device(const char *file, int line, DEVICE *dev) +{ + Dmsg3(sd_dbglvl, "unblock %s from %s:%d\n", dev->print_blocked(), file, line); + ASSERT(dev->blocked()); + dev->set_blocked(BST_NOT_BLOCKED); + dev->no_wait_id = 0; + if (dev->num_waiting > 0) { + pthread_cond_broadcast(&dev->wait); /* wake them up */ + } +} + +/* + * Enter with device locked and blocked + * Exit with device unlocked and blocked by us. + */ +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(); + hold->dev_prev_blocked = dev->dev_prev_blocked; + hold->no_wait_id = dev->no_wait_id; + dev->set_blocked(state); + Dmsg1(sd_dbglvl, "steal lock. new=%s\n", dev->print_blocked()); + dev->no_wait_id = pthread_self(); + dev->dunlock(); +} + +/* + * Enter with device blocked by us but not locked + * Exit with device locked, and blocked by previous owner + */ +void _give_back_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold) +{ + Dmsg3(sd_dbglvl, "return lock. old=%s from %s:%d\n", + dev->print_blocked(), file, line); + dev->dlock(); + dev->set_blocked(hold->dev_blocked); + dev->dev_prev_blocked = hold->dev_prev_blocked; + dev->no_wait_id = hold->no_wait_id; + Dmsg1(sd_dbglvl, "return lock. new=%s\n", dev->print_blocked()); + if (dev->num_waiting > 0) { + pthread_cond_broadcast(&dev->wait); /* wake them up */ + } +} + +const char *DEVICE::print_blocked() const +{ + switch (m_blocked) { + case BST_NOT_BLOCKED: + return "BST_NOT_BLOCKED"; + case BST_UNMOUNTED: + return "BST_UNMOUNTED"; + case BST_WAITING_FOR_SYSOP: + return "BST_WAITING_FOR_SYSOP"; + case BST_DOING_ACQUIRE: + return "BST_DOING_ACQUIRE"; + case BST_WRITING_LABEL: + return "BST_WRITING_LABEL"; + case BST_UNMOUNTED_WAITING_FOR_SYSOP: + return "BST_UNMOUNTED_WAITING_FOR_SYSOP"; + case BST_MOUNT: + return "BST_MOUNT"; + default: + return _("unknown blocked code"); + } +} + + +/* + * Check if the device is blocked or not + */ +bool is_device_unmounted(DEVICE *dev) +{ + bool stat; + int blocked = dev->blocked(); + stat = (blocked == BST_UNMOUNTED) || + (blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP); + return stat; +} + diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 1fd5355f14..bbdf17b536 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -126,12 +126,6 @@ void dvd_remove_empty_part(DCR *dcr); bool open_device(DCR *dcr); bool first_open_device(DCR *dcr); bool fixup_device_block_write_error(DCR *dcr); -void _lock_device(const char *file, int line, DEVICE *dev); -void _unlock_device(const char *file, int line, DEVICE *dev); -void _block_device(const char *file, int line, DEVICE *dev, int state); -void _unblock_device(const char *file, int line, DEVICE *dev); -void _steal_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state); -void _give_back_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold); void set_new_volume_parameters(DCR *dcr); void set_new_file_parameters(DCR *dcr); bool is_device_unmounted(DEVICE *dev); @@ -170,6 +164,15 @@ void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose); bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec); bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec); +/* From locks.c */ +void _lock_device(const char *file, int line, DEVICE *dev); +void _unlock_device(const char *file, int line, DEVICE *dev); +void _block_device(const char *file, int line, DEVICE *dev, int state); +void _unblock_device(const char *file, int line, DEVICE *dev); +void _steal_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state); +void _give_back_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold); + + /* From match_bsr.c */ int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, SESSION_LABEL *sesrec);