2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Collection of Bacula Storage daemon locking software
31 * Kern Sibbald, 2000-2007. June 2007
35 #include "bacula.h" /* pull in global headers */
36 #include "stored.h" /* pull in Storage Deamon headers */
41 const int dbglvl = 500;
47 * The Storage daemon has three locking concepts that must be
50 * 1. dblock blocking the device, which means that the device
51 * is "marked" in use. When setting and removing the
52 block, the device is locked, but after dblock is
53 called the device is unlocked.
54 * 2. dlock() simple mutex that locks the device structure. A dlock
55 * can be acquired while a device is blocked if it is not
57 * 3. r_dlock(locked) "recursive" dlock, when means that a dlock (mutex)
58 * will be acquired on the device if it is not blocked
59 * by some other thread. If the device was blocked by
60 * the current thread, it will acquire the lock.
61 * If some other thread has set a block on the device,
62 * this call will wait until the device is unblocked.
63 * Can be called with locked true, which means the
64 * dlock is already set
66 * A lock is normally set when modifying the device structure.
67 * A r_lock is normally acquired when you want to block the device
68 * i.e. it will wait until the device is not blocked.
69 * A block is normally set during long operations like writing to
71 * If you are writing the device, you will normally block and
73 * A lock cannot be violated. No other thread can touch the
74 * device while a lock is set.
75 * When a block is set, every thread accept the thread that set
76 * the block will block if r_dlock is called.
77 * A device can be blocked for multiple reasons, labeling, writing,
78 * acquiring (opening) the device, waiting for the operator, unmounted,
80 * Under certain conditions the block that is set on a device can be
81 * stolen and the device can be used by another thread. For example,
82 * a device is blocked because it is waiting for the operator to
83 * mount a tape. The operator can then unmount the device, and label
84 * a tape, re-mount it, give back the block, and the job will continue.
89 * DEVICE::dlock() does P(m_mutex) (in dev.h)
90 * DEVICE::dunlock() does V(m_mutex)
92 * DEVICE::r_dlock(locked) allows locking the device when this thread
93 * already has the device blocked.
96 * if blocked and not same thread that locked
98 * leaves device locked
100 * DEVICE::r_dunlock() unlocks but does not unblock
103 * DEVICE::dblock(why) does
104 * r_dlock(); (recursive device lock)
105 * block_device(this, why)
108 * DEVICE::dunblock does
113 * block_device() does (must be locked and not blocked at entry)
117 * unblock_device() does (must be blocked at entry)
120 * set unblocked status
123 * pthread_cond_broadcast
125 * steal_device_lock() does (must be locked and blocked at entry)
127 * set new blocked status
131 * give_back_device_lock() does (must be blocked but not locked)
133 * reset blocked status
134 * save previous blocked
137 * pthread_cond_broadcast
142 void DEVICE::dblock(int why)
144 r_dlock(); /* need recursive lock to block */
145 block_device(this, why);
149 void DEVICE::dunblock(bool locked)
154 unblock_device(this);
160 void DCR::_dlock(const char *file, int line)
162 dev->_dlock(file, line);
165 void DCR::_dunlock(const char *file, int line)
167 m_dev_locked = false;
168 dev->_dunlock(file, line);
172 void DEVICE::_dlock(const char *file, int line)
174 Dmsg3(sd_dbglvl, "dlock from %s:%d precnt=%d\n", file, line, m_count);
175 /* Note, this *really* should be protected by a mutex, but
176 * since it is only debug code we don't worry too much.
178 if (m_count > 0 && pthread_equal(m_pid, pthread_self())) {
179 Dmsg4(sd_dbglvl, "Possible DEADLOCK!! lock held by JobId=%u from %s:%d m_count=%d\n",
180 get_jobid_from_tid(m_pid),
181 file, line, m_count);
184 m_pid = pthread_self();
188 void DEVICE::_dunlock(const char *file, int line)
191 Dmsg3(sd_dbglvl+1, "dunlock from %s:%d postcnt=%d\n", file, line, m_count);
195 void DEVICE::_r_dunlock(const char *file, int line)
197 this->_dunlock(file, line);
204 * This is a recursive lock that checks if the device is blocked.
206 * When blocked is set, all threads EXCEPT thread with id no_wait_id
207 * must wait. The no_wait_id thread is out obtaining a new volume
208 * and preparing the label.
211 void DEVICE::_r_dlock(const char *file, int line, bool locked)
213 Dmsg3(sd_dbglvl+1, "r_dlock blked=%s from %s:%d\n", this->print_blocked(),
216 void DEVICE::r_dlock(bool locked)
221 P(m_mutex); /* this->dlock(); */
222 m_count++; /* this->dlock() */
224 if (this->blocked() && !pthread_equal(this->no_wait_id, pthread_self())) {
225 this->num_waiting++; /* indicate that I am waiting */
226 while (this->blocked()) {
228 /* thread id on Win32 may be a struct */
229 Dmsg3(sd_dbglvl, "r_dlock blked=%s no_wait=%p me=%p\n", this->print_blocked(),
230 this->no_wait_id, pthread_self());
232 if ((stat = pthread_cond_wait(&this->wait, &m_mutex)) != 0) {
235 Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
239 this->num_waiting--; /* no longer waiting */
244 * Block all other threads from using the device
245 * Device must already be locked. After this call,
246 * the device is blocked to any thread calling dev->r_lock(),
247 * but the device is not locked (i.e. no P on device). Also,
248 * the current thread can do slip through the dev->r_lock()
249 * calls without blocking.
251 void _block_device(const char *file, int line, DEVICE *dev, int state)
253 // ASSERT(lmgr_mutex_is_locked(&dev->m_mutex) == 1);
254 ASSERT(dev->blocked() == BST_NOT_BLOCKED);
255 dev->set_blocked(state); /* make other threads wait */
256 dev->no_wait_id = pthread_self(); /* allow us to continue */
257 Dmsg3(sd_dbglvl, "set blocked=%s from %s:%d\n", dev->print_blocked(), file, line);
261 * Unblock the device, and wake up anyone who went to sleep.
262 * Enter: device locked
263 * Exit: device locked
265 void _unblock_device(const char *file, int line, DEVICE *dev)
267 Dmsg3(sd_dbglvl, "unblock %s from %s:%d\n", dev->print_blocked(), file, line);
268 // ASSERT(lmgr_mutex_is_locked(&dev->m_mutex) == 1);
269 ASSERT(dev->blocked());
270 // ASSERT(dev->no_wait_id == pthread_self());
271 dev->set_blocked(BST_NOT_BLOCKED);
272 clear_thread_id(dev->no_wait_id);
273 if (dev->num_waiting > 0) {
274 pthread_cond_broadcast(&dev->wait); /* wake them up */
279 * Enter with device locked and blocked
280 * Exit with device unlocked and blocked by us.
282 void _steal_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state)
285 Dmsg3(sd_dbglvl, "steal lock. old=%s from %s:%d\n", dev->print_blocked(),
287 hold->dev_blocked = dev->blocked();
288 hold->dev_prev_blocked = dev->dev_prev_blocked;
289 hold->no_wait_id = dev->no_wait_id;
290 dev->set_blocked(state);
291 Dmsg1(sd_dbglvl, "steal lock. new=%s\n", dev->print_blocked());
292 dev->no_wait_id = pthread_self();
297 * Enter with device blocked by us but not locked
298 * Exit with device locked, and blocked by previous owner
300 void _give_back_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold)
302 Dmsg3(sd_dbglvl, "return lock. old=%s from %s:%d\n",
303 dev->print_blocked(), file, line);
305 dev->set_blocked(hold->dev_blocked);
306 dev->dev_prev_blocked = hold->dev_prev_blocked;
307 dev->no_wait_id = hold->no_wait_id;
308 Dmsg1(sd_dbglvl, "return lock. new=%s\n", dev->print_blocked());
309 if (dev->num_waiting > 0) {
310 pthread_cond_broadcast(&dev->wait); /* wake them up */
314 const char *DEVICE::print_blocked() const
317 case BST_NOT_BLOCKED:
318 return "BST_NOT_BLOCKED";
320 return "BST_UNMOUNTED";
321 case BST_WAITING_FOR_SYSOP:
322 return "BST_WAITING_FOR_SYSOP";
323 case BST_DOING_ACQUIRE:
324 return "BST_DOING_ACQUIRE";
325 case BST_WRITING_LABEL:
326 return "BST_WRITING_LABEL";
327 case BST_UNMOUNTED_WAITING_FOR_SYSOP:
328 return "BST_UNMOUNTED_WAITING_FOR_SYSOP";
332 return "BST_DESPOOLING";
334 return "BST_RELEASING";
336 return _("unknown blocked code");
342 * Check if the device is blocked or not
344 bool DEVICE::is_device_unmounted()
348 stat = (blk == BST_UNMOUNTED) ||
349 (blk == BST_UNMOUNTED_WAITING_FOR_SYSOP);