2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 Bacula® is a registered trademark of Kern Sibbald.
17 * Collection of Bacula Storage daemon locking software
19 * Kern Sibbald, June 2007
23 #include "bacula.h" /* pull in global headers */
24 #include "stored.h" /* pull in Storage Deamon headers */
27 const int dbglvl = 300;
29 const int dbglvl = 500;
35 * The Storage daemon has three locking concepts that must be
38 * 1. dblock blocking the device, which means that the device
39 * is "marked" in use. When setting and removing the
40 block, the device is locked, but after dblock is
41 called the device is unlocked.
42 * 2. Lock() simple mutex that locks the device structure. A Lock
43 * can be acquired while a device is blocked if it is not
45 * 3. rLock(locked) "recursive" Lock, when means that a Lock (mutex)
46 * will be acquired on the device if it is not blocked
47 * by some other thread. If the device was blocked by
48 * the current thread, it will acquire the lock.
49 * If some other thread has set a block on the device,
50 * this call will wait until the device is unblocked.
51 * Can be called with locked true, which means the
54 * A lock is normally set when modifying the device structure.
55 * A rLock is normally acquired when you want to block the device
56 * i.e. it will wait until the device is not blocked.
57 * A block is normally set during long operations like writing to
59 * If you are writing the device, you will normally block and
61 * A lock cannot be violated. No other thread can touch the
62 * device while a lock is set.
63 * When a block is set, every thread accept the thread that set
64 * the block will block if rLock is called.
65 * A device can be blocked for multiple reasons, labeling, writing,
66 * acquiring (opening) the device, waiting for the operator, unmounted,
68 * Under certain conditions the block that is set on a device can be
69 * stolen and the device can be used by another thread. For example,
70 * a device is blocked because it is waiting for the operator to
71 * mount a tape. The operator can then unmount the device, and label
72 * a tape, re-mount it, give back the block, and the job will continue.
77 * DEVICE::Lock() does P(m_mutex) (in dev.h)
78 * DEVICE::Unlock() does V(m_mutex)
80 * DEVICE::rLock(locked) allows locking the device when this thread
81 * already has the device blocked.
84 * if blocked and not same thread that locked
86 * leaves device locked
88 * DEVICE::rUnlock() unlocks but does not unblock
91 * DEVICE::dblock(why) does
92 * rLock(); (recursive device lock)
93 * block_device(this, why)
96 * DEVICE::dunblock does
101 * block_device() does (must be locked and not blocked at entry)
105 * unblock_device() does (must be blocked at entry)
108 * set unblocked status
111 * pthread_cond_broadcast
113 * steal_device_lock() does (must be locked and blocked at entry)
115 * set new blocked status
119 * give_back_device_lock() does (must be blocked but not locked)
121 * reset blocked status
122 * save previous blocked
125 * pthread_cond_broadcast
129 void DEVICE::dblock(int why)
131 rLock(false); /* need recursive lock to block */
132 block_device(this, why);
136 void DEVICE::dunblock(bool locked)
141 unblock_device(this);
148 * Debug DEVICE locks N.B.
152 #ifdef DEV_DEBUG_LOCK
154 void DEVICE::dbg_Lock(const char *file, int line)
156 Dmsg3(sd_dbglvl, "Lock from %s:%d precnt=%d\n", file, line, m_count);
157 bthread_mutex_lock_p(&m_mutex, file, line);
158 m_pid = pthread_self();
162 void DEVICE::dbg_Unlock(const char *file, int line)
165 Dmsg3(sd_dbglvl, "Unlock from %s:%d postcnt=%d\n", file, line, m_count);
166 bthread_mutex_unlock_p(&m_mutex, file, line);
169 void DEVICE::dbg_rUnlock(const char *file, int line)
171 Dmsg2(sd_dbglvl, "rUnlock from %s:%d\n", file, line);
172 dbg_Unlock(file, line);
183 void DEVICE::rUnlock()
193 void DEVICE::Unlock()
198 #endif /* DEV_DEBUG_LOCK */
201 * This is a recursive lock that checks if the device is blocked.
203 * When blocked is set, all threads EXCEPT thread with id no_wait_id
204 * must wait. The no_wait_id thread is out obtaining a new volume
205 * and preparing the label.
207 #ifdef DEV_DEBUG_LOCK
208 void DEVICE::dbg_rLock(const char *file, int line, bool locked)
210 Dmsg3(sd_dbglvl, "rLock blked=%s from %s:%d\n", print_blocked(),
214 /* lockmgr version of P(m_mutex) */
215 bthread_mutex_lock_p(&m_mutex, file, line);
219 if (blocked() && !pthread_equal(no_wait_id, pthread_self())) {
220 num_waiting++; /* indicate that I am waiting */
224 /* thread id on Win32 may be a struct */
225 Dmsg3(sd_dbglvl, "rLock blked=%s no_wait=%p me=%p\n", print_blocked(),
226 no_wait_id, pthread_self());
228 if ((stat = bthread_cond_wait_p(&this->wait, &m_mutex, file, line)) != 0) {
230 this->dbg_Unlock(file, line);
231 Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
235 num_waiting--; /* no longer waiting */
238 #else /* DEV_DEBUG_LOCK */
240 void DEVICE::rLock(bool locked)
247 if (blocked() && !pthread_equal(no_wait_id, pthread_self())) {
248 num_waiting++; /* indicate that I am waiting */
252 /* thread id on Win32 may be a struct */
253 Dmsg3(sd_dbglvl, "rLock blked=%s no_wait=%p me=%p\n", print_blocked(),
254 no_wait_id, pthread_self());
256 if ((stat = pthread_cond_wait(&this->wait, &m_mutex)) != 0) {
259 Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
263 num_waiting--; /* no longer waiting */
267 #endif /* DEV_DEBUG_LOCK */
271 void DEVICE::dbg_Lock_acquire(const char *file, int line)
273 Dmsg2(sd_dbglvl, "Lock_acquire from %s:%d\n", file, line);
274 bthread_mutex_lock_p(&acquire_mutex, file, line);
277 void DEVICE::dbg_Unlock_acquire(const char *file, int line)
279 Dmsg2(sd_dbglvl, "Unlock_acquire from %s:%d\n", file, line);
280 bthread_mutex_unlock_p(&acquire_mutex, file, line);
283 void DEVICE::dbg_Lock_read_acquire(const char *file, int line)
285 Dmsg2(sd_dbglvl, "Lock_read_acquire from %s:%d\n", file, line);
286 bthread_mutex_lock_p(&read_acquire_mutex, file, line);
289 void DEVICE::dbg_Unlock_read_acquire(const char *file, int line)
291 Dmsg2(sd_dbglvl, "Unlock_read_acquire from %s:%d\n", file, line);
292 bthread_mutex_unlock_p(&read_acquire_mutex, file, line);
295 void DEVICE::dbg_Lock_VolCatInfo(const char *file, int line)
297 bthread_mutex_lock_p(&volcat_mutex, file, line);
300 void DEVICE::dbg_Unlock_VolCatInfo(const char *file, int line)
302 bthread_mutex_unlock_p(&volcat_mutex, file, line);
307 void DEVICE::Lock_acquire()
312 void DEVICE::Unlock_acquire()
317 void DEVICE::Lock_read_acquire()
319 P(read_acquire_mutex);
322 void DEVICE::Unlock_read_acquire()
324 V(read_acquire_mutex);
327 void DEVICE::Lock_VolCatInfo()
332 void DEVICE::Unlock_VolCatInfo()
341 /* Main device access control */
342 int DEVICE::init_mutex()
344 return pthread_mutex_init(&m_mutex, NULL);
347 /* Write device acquire mutex */
348 int DEVICE::init_acquire_mutex()
350 return pthread_mutex_init(&acquire_mutex, NULL);
353 /* Read device acquire mutex */
354 int DEVICE::init_read_acquire_mutex()
356 return pthread_mutex_init(&read_acquire_mutex, NULL);
359 /* VolCatInfo mutex */
360 int DEVICE::init_volcat_mutex()
362 return pthread_mutex_init(&volcat_mutex, NULL);
366 int DEVICE::init_dcrs_mutex()
368 return pthread_mutex_init(&dcrs_mutex, NULL);
371 /* Set order in which device locks must be acquired */
372 void DEVICE::set_mutex_priorities()
374 /* Ensure that we respect this order in P/V operations */
375 bthread_mutex_set_priority(&m_mutex, PRIO_SD_DEV_ACCESS);
376 bthread_mutex_set_priority(&spool_mutex, PRIO_SD_DEV_SPOOL);
377 bthread_mutex_set_priority(&acquire_mutex, PRIO_SD_DEV_ACQUIRE);
380 int DEVICE::next_vol_timedwait(const struct timespec *timeout)
382 return pthread_cond_timedwait(&wait_next_vol, &m_mutex, timeout);
387 * Block all other threads from using the device
388 * Device must already be locked. After this call,
389 * the device is blocked to any thread calling dev->rLock(),
390 * but the device is not locked (i.e. no P on device). Also,
391 * the current thread can do slip through the dev->rLock()
392 * calls without blocking.
394 void _block_device(const char *file, int line, DEVICE *dev, int state)
396 ASSERT2(dev->blocked() == BST_NOT_BLOCKED, "Block request of device already blocked");
397 dev->set_blocked(state); /* make other threads wait */
398 dev->no_wait_id = pthread_self(); /* allow us to continue */
399 Dmsg3(sd_dbglvl, "set blocked=%s from %s:%d\n", dev->print_blocked(), file, line);
403 * Unblock the device, and wake up anyone who went to sleep.
404 * Enter: device locked
405 * Exit: device locked
407 void _unblock_device(const char *file, int line, DEVICE *dev)
409 Dmsg3(sd_dbglvl, "unblock %s from %s:%d\n", dev->print_blocked(), file, line);
410 ASSERT2(dev->blocked(), "Unblock request of device not blocked");
411 dev->set_blocked(BST_NOT_BLOCKED);
412 clear_thread_id(dev->no_wait_id);
413 if (dev->num_waiting > 0) {
414 pthread_cond_broadcast(&dev->wait); /* wake them up */
419 * Enter with device locked and blocked
420 * Exit with device unlocked and blocked by us.
422 void _steal_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state)
424 Dmsg3(sd_dbglvl, "steal lock. old=%s from %s:%d\n", dev->print_blocked(),
426 hold->dev_blocked = dev->blocked();
427 hold->dev_prev_blocked = dev->dev_prev_blocked;
428 hold->no_wait_id = dev->no_wait_id;
429 dev->set_blocked(state);
430 Dmsg1(sd_dbglvl, "steal lock. new=%s\n", dev->print_blocked());
431 dev->no_wait_id = pthread_self();
436 * Enter with device blocked by us but not locked
437 * Exit with device locked, and blocked by previous owner
439 void _give_back_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold)
441 Dmsg3(sd_dbglvl, "return lock. old=%s from %s:%d\n",
442 dev->print_blocked(), file, line);
444 dev->set_blocked(hold->dev_blocked);
445 dev->dev_prev_blocked = hold->dev_prev_blocked;
446 dev->no_wait_id = hold->no_wait_id;
447 Dmsg1(sd_dbglvl, "return lock. new=%s\n", dev->print_blocked());
448 if (dev->num_waiting > 0) {
449 pthread_cond_broadcast(&dev->wait); /* wake them up */
453 const char *DEVICE::print_blocked() const
456 case BST_NOT_BLOCKED:
457 return "BST_NOT_BLOCKED";
459 return "BST_UNMOUNTED";
460 case BST_WAITING_FOR_SYSOP:
461 return "BST_WAITING_FOR_SYSOP";
462 case BST_DOING_ACQUIRE:
463 return "BST_DOING_ACQUIRE";
464 case BST_WRITING_LABEL:
465 return "BST_WRITING_LABEL";
466 case BST_UNMOUNTED_WAITING_FOR_SYSOP:
467 return "BST_UNMOUNTED_WAITING_FOR_SYSOP";
471 return "BST_DESPOOLING";
473 return "BST_RELEASING";
475 return _("unknown blocked code");
481 * Check if the device is blocked or not
483 bool DEVICE::is_device_unmounted()
488 stat = (blk == BST_UNMOUNTED) ||
489 (blk == BST_UNMOUNTED_WAITING_FOR_SYSOP);