2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 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
36 #include "bacula.h" /* pull in global headers */
37 #include "stored.h" /* pull in Storage Deamon headers */
42 const int dbglvl = 500;
48 * The Storage daemon has three locking concepts that must be
51 * 1. dblock blocking the device, which means that the device
52 * is "marked" in use. When setting and removing the
53 block, the device is locked, but after dblock is
54 called the device is unlocked.
55 * 2. dlock() simple mutex that locks the device structure. A dlock
56 * can be acquired while a device is blocked if it is not
58 * 3. r_dlock "recursive" dlock, when means that a dlock (mutex)
59 * will be acquired on the device if it is not blocked
60 * by some other thread. If the device was blocked by
61 * the current thread, it will acquire the lock.
62 * If some other thread has set a block on the device,
63 * this call will wait until the device is unblocked.
65 * A lock is normally set when modifying the device structure.
66 * A r_lock is normally acquired when you want to block the device
67 * i.e. it will wait until the device is not blocked.
68 * A block is normally set during long operations like writing to
70 * If you are writing the device, you will normally block and
72 * A lock cannot be violated. No other thread can touch the
73 * device while a lock is set.
74 * When a block is set, every thread accept the thread that set
75 * the block will block if r_dlock is called.
76 * A device can be blocked for multiple reasons, labeling, writing,
77 * acquiring (opening) the device, waiting for the operator, unmounted,
79 * Under certain conditions the block that is set on a device can be
80 * stolen and the device can be used by another thread. For example,
81 * a device is blocked because it is waiting for the operator to
82 * mount a tape. The operator can then unmount the device, and label
83 * a tape, re-mount it, give back the block, and the job will continue.
88 * DEVICE::dlock() does P(m_mutex) (in dev.h)
89 * DEVICE::dunlock() does V(m_mutex)
91 * DEVICE::r_dlock() allows locking the device when this thread
92 already has the device blocked.
94 * if blocked and not same thread that locked
96 * leaves device locked
98 * DEVICE::r_dunlock() unlocks but does not unblock
101 * DEVICE::dblock(why) does
102 * r_dlock(); (recursive device lock)
103 * block_device(this, why)
106 * DEVICE::dunblock does
111 * block_device() does (must be locked and not blocked at entry)
115 * unblock_device() does (must be blocked at entry)
118 * set unblocked status
121 * pthread_cond_broadcast
123 * steal_device_lock() does (must be locked and blocked at entry)
125 * set new blocked status
129 * give_back_device_lock() does (must be blocked but not locked)
131 * reset blocked status
132 * save previous blocked
135 * pthread_cond_broadcast
140 void DEVICE::dblock(int why)
142 r_dlock(); /* need recursive lock to block */
143 block_device(this, why);
147 void DEVICE::dunblock(bool locked)
152 unblock_device(this);
158 void DEVICE::_dlock(const char *file, int line)
160 Dmsg4(sd_dbglvl, "dlock from %s:%d precnt=%d JobId=%u\n", file, line,
161 m_count, get_jobid_from_tid());
162 /* Note, this *really* should be protected by a mutex, but
163 * since it is only debug code we don't worry too much.
165 if (m_count > 0 && pthread_equal(m_pid, pthread_self())) {
166 Dmsg5(sd_dbglvl, "Possible DEADLOCK!! lock held by JobId=%u from %s:%d m_count=%d JobId=%u\n",
167 get_jobid_from_tid(m_pid),
168 file, line, m_count, get_jobid_from_tid());
171 m_pid = pthread_self();
175 void DEVICE::_dunlock(const char *file, int line)
178 Dmsg4(sd_dbglvl+1, "dunlock from %s:%d postcnt=%d JobId=%u\n", file, line,
179 m_count, get_jobid_from_tid());
183 void DEVICE::_r_dunlock(const char *file, int line)
185 this->_dunlock(file, line);
192 * This is a recursive lock that checks if the device is blocked.
194 * When blocked is set, all threads EXCEPT thread with id no_wait_id
195 * must wait. The no_wait_id thread is out obtaining a new volume
196 * and preparing the label.
199 void DEVICE::_r_dlock(const char *file, int line)
201 Dmsg4(sd_dbglvl+1, "r_dlock blked=%s from %s:%d JobId=%u\n", this->print_blocked(),
202 file, line, get_jobid_from_tid());
204 void DEVICE::r_dlock()
209 if (this->blocked() && !pthread_equal(this->no_wait_id, pthread_self())) {
210 this->num_waiting++; /* indicate that I am waiting */
211 while (this->blocked()) {
213 /* thread id on Win32 may be a struct */
214 Dmsg3(sd_dbglvl, "r_dlock blked=%s no_wait=%p me=%p\n", this->print_blocked(),
215 this->no_wait_id, pthread_self());
217 if ((stat = pthread_cond_wait(&this->wait, &m_mutex)) != 0) {
220 Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
224 this->num_waiting--; /* no longer waiting */
229 * Block all other threads from using the device
230 * Device must already be locked. After this call,
231 * the device is blocked to any thread calling dev->r_lock(),
232 * but the device is not locked (i.e. no P on device). Also,
233 * the current thread can do slip through the dev->r_lock()
234 * calls without blocking.
236 void _block_device(const char *file, int line, DEVICE *dev, int state)
238 ASSERT(dev->blocked() == BST_NOT_BLOCKED);
239 dev->set_blocked(state); /* make other threads wait */
240 dev->no_wait_id = pthread_self(); /* allow us to continue */
241 Dmsg3(sd_dbglvl, "set blocked=%s from %s:%d\n", dev->print_blocked(), file, line);
245 * Unblock the device, and wake up anyone who went to sleep.
246 * Enter: device locked
247 * Exit: device locked
249 void _unblock_device(const char *file, int line, DEVICE *dev)
251 Dmsg3(sd_dbglvl, "unblock %s from %s:%d\n", dev->print_blocked(), file, line);
252 ASSERT(dev->blocked());
253 dev->set_blocked(BST_NOT_BLOCKED);
254 clear_thread_id(dev->no_wait_id);
255 if (dev->num_waiting > 0) {
256 pthread_cond_broadcast(&dev->wait); /* wake them up */
261 * Enter with device locked and blocked
262 * Exit with device unlocked and blocked by us.
264 void _steal_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state)
267 Dmsg3(sd_dbglvl, "steal lock. old=%s from %s:%d\n", dev->print_blocked(),
269 hold->dev_blocked = dev->blocked();
270 hold->dev_prev_blocked = dev->dev_prev_blocked;
271 hold->no_wait_id = dev->no_wait_id;
272 dev->set_blocked(state);
273 Dmsg1(sd_dbglvl, "steal lock. new=%s\n", dev->print_blocked());
274 dev->no_wait_id = pthread_self();
279 * Enter with device blocked by us but not locked
280 * Exit with device locked, and blocked by previous owner
282 void _give_back_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold)
284 Dmsg3(sd_dbglvl, "return lock. old=%s from %s:%d\n",
285 dev->print_blocked(), file, line);
287 dev->set_blocked(hold->dev_blocked);
288 dev->dev_prev_blocked = hold->dev_prev_blocked;
289 dev->no_wait_id = hold->no_wait_id;
290 Dmsg1(sd_dbglvl, "return lock. new=%s\n", dev->print_blocked());
291 if (dev->num_waiting > 0) {
292 pthread_cond_broadcast(&dev->wait); /* wake them up */
296 const char *DEVICE::print_blocked() const
299 case BST_NOT_BLOCKED:
300 return "BST_NOT_BLOCKED";
302 return "BST_UNMOUNTED";
303 case BST_WAITING_FOR_SYSOP:
304 return "BST_WAITING_FOR_SYSOP";
305 case BST_DOING_ACQUIRE:
306 return "BST_DOING_ACQUIRE";
307 case BST_WRITING_LABEL:
308 return "BST_WRITING_LABEL";
309 case BST_UNMOUNTED_WAITING_FOR_SYSOP:
310 return "BST_UNMOUNTED_WAITING_FOR_SYSOP";
314 return "BST_DESPOOLING";
316 return _("unknown blocked code");
322 * Check if the device is blocked or not
324 bool is_device_unmounted(DEVICE *dev)
327 int blocked = dev->blocked();
328 stat = (blocked == BST_UNMOUNTED) ||
329 (blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);