1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
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.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * Collection of Bacula Storage daemon locking software
21 *
22 * Kern Sibbald, June 2007
23 *
24 */
25
26 #include "bacula.h" /* pull in global headers */
27 #include "stored.h" /* pull in Storage Deamon headers */
28
29 #ifdef SD_DEBUG_LOCK
30 const int dbglvl = DT_LOCK|30;
31 #else
32 const int dbglvl = DT_LOCK|50;
33 #endif
34
35
36 /*
37 *
38 * The Storage daemon has three locking concepts that must be
39 * understood:
40 *
41 * 1. dblock blocking the device, which means that the device
42 * is "marked" in use. When setting and removing the
43 block, the device is locked, but after dblock is
44 called the device is unlocked.
45 * 2. Lock() simple mutex that locks the device structure. A Lock
46 * can be acquired while a device is blocked if it is not
47 * locked.
48 * 3. rLock(locked) "recursive" Lock, when means that a Lock (mutex)
49 * will be acquired on the device if it is not blocked
50 * by some other thread. If the device was blocked by
51 * the current thread, it will acquire the lock.
52 * If some other thread has set a block on the device,
53 * this call will wait until the device is unblocked.
54 * Can be called with locked true, which means the
55 * Lock is already set
56 *
57 * A lock is normally set when modifying the device structure.
58 * A rLock is normally acquired when you want to block the device
59 * i.e. it will wait until the device is not blocked.
60 * A block is normally set during long operations like writing to
61 * the device.
62 * If you are writing the device, you will normally block and
63 * lock it.
64 * A lock cannot be violated. No other thread can touch the
65 * device while a lock is set.
66 * When a block is set, every thread accept the thread that set
67 * the block will block if rLock is called.
68 * A device can be blocked for multiple reasons, labeling, writing,
69 * acquiring (opening) the device, waiting for the operator, unmounted,
70 * ...
71 * Under certain conditions the block that is set on a device can be
72 * stolen and the device can be used by another thread. For example,
73 * a device is blocked because it is waiting for the operator to
74 * mount a tape. The operator can then unmount the device, and label
75 * a tape, re-mount it, give back the block, and the job will continue.
76 *
77 *
78 * Functions:
79 *
80 * DEVICE::Lock() does P(m_mutex) (in dev.h)
81 * DEVICE::Unlock() does V(m_mutex)
82 *
83 * DEVICE::rLock(locked) allows locking the device when this thread
84 * already has the device blocked.
85 * if (!locked)
86 * Lock()
87 * if blocked and not same thread that locked
88 * pthread_cond_wait
89 * leaves device locked
90 *
91 * DEVICE::rUnlock() unlocks but does not unblock
92 * same as Unlock();
93 *
94 * DEVICE::dblock(why) does
95 * rLock(); (recursive device lock)
96 * block_device(this, why)
97 * rUnlock()
98 *
99 * DEVICE::dunblock does
100 * Lock()
101 * unblock_device()
102 * Unlock()
103 *
104 * block_device() does (must be locked and not blocked at entry)
105 * set blocked status
106 * set our pid
107 *
108 * unblock_device() does (must be blocked at entry)
109 * (locked on entry)
110 * (locked on exit)
111 * set unblocked status
112 * clear pid
113 * if waiting threads
114 * pthread_cond_broadcast
115 *
116 * obtain_device_block() does (must be locked and blocked at entry)
117 * save status
118 * set new blocked status
119 * set new pid
120 *
121 * give_back_device_block() does (must be blocked and locked)
122 * reset blocked status
123 * save previous blocked
124 * reset pid
125 * if waiting threads
126 * pthread_cond_broadcast
127 *
128 */
129
dblock(int why)130 void DEVICE::dblock(int why)
131 {
132 rLock(false); /* need recursive lock to block */
133 block_device(this, why);
134 rUnlock();
135 }
136
dunblock(bool locked)137 void DEVICE::dunblock(bool locked)
138 {
139 if (!locked) {
140 Lock();
141 }
142 unblock_device(this);
143 Unlock();
144 }
145
146
147
148 /*
149 * Debug DEVICE locks N.B.
150 *
151 */
152
153 #ifdef DEV_DEBUG_LOCK
154
dbg_Lock(const char * file,int line)155 void DEVICE::dbg_Lock(const char *file, int line)
156 {
157 Dmsg4(sd_dbglvl, "Lock %s from %s:%d precnt=%d\n", device->hdr.name, file, line, m_count);
158 bthread_mutex_lock_p(&m_mutex, file, line);
159 m_pid = pthread_self();
160 m_count++;
161 }
162
dbg_Unlock(const char * file,int line)163 void DEVICE::dbg_Unlock(const char *file, int line)
164 {
165 m_count--;
166 clear_thread_id(m_pid);
167 Dmsg4(sd_dbglvl, "Unlock %s from %s:%d postcnt=%d\n", device->hdr.name, file, line, m_count);
168 bthread_mutex_unlock_p(&m_mutex, file, line);
169 }
170
dbg_rUnlock(const char * file,int line)171 void DEVICE::dbg_rUnlock(const char *file, int line)
172 {
173 Dmsg2(sd_dbglvl, "rUnlock from %s:%d\n", file, line);
174 dbg_Unlock(file, line);
175 }
176
177 #else
178
179 /*
180 * DEVICE locks N.B.
181 *
182 */
183
184
rUnlock()185 void DEVICE::rUnlock()
186 {
187 Unlock();
188 }
189
Lock()190 void DEVICE::Lock()
191 {
192 P(m_mutex);
193 }
194
Unlock()195 void DEVICE::Unlock()
196 {
197 V(m_mutex);
198 }
199
200 #endif /* DEV_DEBUG_LOCK */
201
202 /*
203 * This is a recursive lock that checks if the device is blocked.
204 *
205 * When blocked is set, all threads EXCEPT thread with id no_wait_id
206 * must wait. The no_wait_id thread is out obtaining a new volume
207 * and preparing the label.
208 */
209 #ifdef DEV_DEBUG_LOCK
dbg_rLock(const char * file,int line,bool locked)210 void DEVICE::dbg_rLock(const char *file, int line, bool locked)
211 {
212 Dmsg3(sd_dbglvl, "Enter rLock blked=%s from %s:%d\n", print_blocked(),
213 file, line);
214 if (!locked) {
215 /* lockmgr version of P(m_mutex) */
216 Dmsg4(sd_dbglvl, "Lock %s in rLock %s from %s:%d\n",
217 device->hdr.name, print_blocked(), file, line);
218 bthread_mutex_lock_p(&m_mutex, file, line);
219 m_count++;
220 }
221
222 if (blocked() && !pthread_equal(no_wait_id, pthread_self())) {
223 num_waiting++; /* indicate that I am waiting */
224 while (blocked()) {
225 int stat;
226 #ifndef HAVE_WIN32
227 /* thread id on Win32 may be a struct */
228 Dmsg5(sd_dbglvl, "Blocked by %d %s in rLock blked=%s no_wait=%p me=%p\n",
229 blocked_by, device->hdr.name, print_blocked(), no_wait_id, pthread_self());
230 #endif
231 if ((stat = bthread_cond_wait_p(&this->wait, &m_mutex, file, line)) != 0) {
232 berrno be;
233 this->dbg_Unlock(file, line);
234 Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
235 be.bstrerror(stat));
236 }
237 }
238 num_waiting--; /* no longer waiting */
239 }
240 }
241 #else /* DEV_DEBUG_LOCK */
242
rLock(bool locked)243 void DEVICE::rLock(bool locked)
244 {
245 if (!locked) {
246 Lock();
247 m_count++;
248 }
249
250 if (blocked() && !pthread_equal(no_wait_id, pthread_self())) {
251 num_waiting++; /* indicate that I am waiting */
252 while (blocked()) {
253 int stat;
254 #ifndef HAVE_WIN32
255 /* thread id on Win32 may be a struct */
256 Dmsg5(sd_dbglvl, "Blocked by %d rLock %s blked=%s no_wait=%p me=%p\n",
257 blocked_by, device->hdr.name, print_blocked(), no_wait_id, pthread_self());
258 #endif
259 if ((stat = pthread_cond_wait(&this->wait, &m_mutex)) != 0) {
260 berrno be;
261 this->Unlock();
262 Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
263 be.bstrerror(stat));
264 }
265 }
266 num_waiting--; /* no longer waiting */
267 }
268 }
269
270 #endif /* DEV_DEBUG_LOCK */
271
272 #ifdef SD_DEBUG_LOCK
273
dbg_Lock_acquire(const char * file,int line)274 void DEVICE::dbg_Lock_acquire(const char *file, int line)
275 {
276 Dmsg2(sd_dbglvl, "Lock_acquire from %s:%d\n", file, line);
277 bthread_mutex_lock_p(&acquire_mutex, file, line);
278 }
279
dbg_Unlock_acquire(const char * file,int line)280 void DEVICE::dbg_Unlock_acquire(const char *file, int line)
281 {
282 Dmsg2(sd_dbglvl, "Unlock_acquire from %s:%d\n", file, line);
283 bthread_mutex_unlock_p(&acquire_mutex, file, line);
284 }
285
dbg_Lock_read_acquire(const char * file,int line)286 void DEVICE::dbg_Lock_read_acquire(const char *file, int line)
287 {
288 Dmsg2(sd_dbglvl, "Lock_read_acquire from %s:%d\n", file, line);
289 bthread_mutex_lock_p(&read_acquire_mutex, file, line);
290 }
291
dbg_Unlock_read_acquire(const char * file,int line)292 void DEVICE::dbg_Unlock_read_acquire(const char *file, int line)
293 {
294 Dmsg2(sd_dbglvl, "Unlock_read_acquire from %s:%d\n", file, line);
295 bthread_mutex_unlock_p(&read_acquire_mutex, file, line);
296 }
297
dbg_Lock_VolCatInfo(const char * file,int line)298 void DEVICE::dbg_Lock_VolCatInfo(const char *file, int line)
299 {
300 bthread_mutex_lock_p(&volcat_mutex, file, line);
301 }
302
dbg_Unlock_VolCatInfo(const char * file,int line)303 void DEVICE::dbg_Unlock_VolCatInfo(const char *file, int line)
304 {
305 bthread_mutex_unlock_p(&volcat_mutex, file, line);
306 }
307
308 #else
309
Lock_acquire()310 void DEVICE::Lock_acquire()
311 {
312 P(acquire_mutex);
313 }
314
Unlock_acquire()315 void DEVICE::Unlock_acquire()
316 {
317 V(acquire_mutex);
318 }
319
Lock_read_acquire()320 void DEVICE::Lock_read_acquire()
321 {
322 P(read_acquire_mutex);
323 }
324
Unlock_read_acquire()325 void DEVICE::Unlock_read_acquire()
326 {
327 V(read_acquire_mutex);
328 }
329
Lock_VolCatInfo()330 void DEVICE::Lock_VolCatInfo()
331 {
332 P(volcat_mutex);
333 }
334
Unlock_VolCatInfo()335 void DEVICE::Unlock_VolCatInfo()
336 {
337 V(volcat_mutex);
338 }
339
340
341
342 #endif
343
344 /* Main device access control */
init_mutex()345 int DEVICE::init_mutex()
346 {
347 return pthread_mutex_init(&m_mutex, NULL);
348 }
349
350 /* Mutex around the freespace command */
init_freespace_mutex()351 int DEVICE::init_freespace_mutex()
352 {
353 return pthread_mutex_init(&freespace_mutex, NULL);
354 }
355
356 /* Write device acquire mutex */
init_acquire_mutex()357 int DEVICE::init_acquire_mutex()
358 {
359 return pthread_mutex_init(&acquire_mutex, NULL);
360 }
361
362 /* Read device acquire mutex */
init_read_acquire_mutex()363 int DEVICE::init_read_acquire_mutex()
364 {
365 return pthread_mutex_init(&read_acquire_mutex, NULL);
366 }
367
368 /* VolCatInfo mutex */
init_volcat_mutex()369 int DEVICE::init_volcat_mutex()
370 {
371 return pthread_mutex_init(&volcat_mutex, NULL);
372 }
373
374 /* dcrs mutex */
init_dcrs_mutex()375 int DEVICE::init_dcrs_mutex()
376 {
377 return pthread_mutex_init(&dcrs_mutex, NULL);
378 }
379
380 /* Set order in which device locks must be acquired */
set_mutex_priorities()381 void DEVICE::set_mutex_priorities()
382 {
383 /* Ensure that we respect this order in P/V operations */
384 bthread_mutex_set_priority(&m_mutex, PRIO_SD_DEV_ACCESS);
385 bthread_mutex_set_priority(&spool_mutex, PRIO_SD_DEV_SPOOL);
386 bthread_mutex_set_priority(&acquire_mutex, PRIO_SD_DEV_ACQUIRE);
387 }
388
next_vol_timedwait(const struct timespec * timeout)389 int DEVICE::next_vol_timedwait(const struct timespec *timeout)
390 {
391 return pthread_cond_timedwait(&wait_next_vol, &m_mutex, timeout);
392 }
393
394
395 /*
396 * Block all other threads from using the device
397 * Device must already be locked. After this call,
398 * the device is blocked to any thread calling dev->rLock(),
399 * but the device is not locked (i.e. no P on device). Also,
400 * the current thread can do slip through the dev->rLock()
401 * calls without blocking.
402 */
_block_device(const char * file,int line,DEVICE * dev,int state)403 void _block_device(const char *file, int line, DEVICE *dev, int state)
404 {
405 ASSERT2(dev->blocked() == BST_NOT_BLOCKED, "Block request of device already blocked");
406 dev->set_blocked(state); /* make other threads wait */
407 dev->no_wait_id = pthread_self(); /* allow us to continue */
408 dev->blocked_by = get_jobid_from_tsd();
409 Dmsg4(sd_dbglvl, "Blocked %s %s from %s:%d\n",
410 dev->device->hdr.name, dev->print_blocked(), file, line);
411 }
412
413 /*
414 * Unblock the device, and wake up anyone who went to sleep.
415 * Enter: device locked
416 * Exit: device locked
417 */
_unblock_device(const char * file,int line,DEVICE * dev)418 void _unblock_device(const char *file, int line, DEVICE *dev)
419 {
420 Dmsg4(sd_dbglvl, "Unblocked %s %s from %s:%d\n", dev->device->hdr.name,
421 dev->print_blocked(), file, line);
422 ASSERT2(dev->blocked(), "Unblock request of device not blocked");
423 dev->set_blocked(BST_NOT_BLOCKED);
424 dev->blocked_by = 0;
425 clear_thread_id(dev->no_wait_id);
426 if (dev->num_waiting > 0) {
427 pthread_cond_broadcast(&dev->wait); /* wake them up */
428 }
429 }
430
431 static pthread_mutex_t block_mutex = PTHREAD_MUTEX_INITIALIZER;
432 /*
433 * Enter and leave with device locked
434 *
435 * Note: actually this routine:
436 * returns true if it can either set or steal the device block
437 * returns false if it cannot block the device
438 */
_obtain_device_block(const char * file,int line,bsteal_lock_t * hold,int retry,int state)439 bool DEVICE::_obtain_device_block(const char *file, int line,
440 bsteal_lock_t *hold, int retry, int state)
441 {
442 int ret;
443 int r = retry;
444
445 if (!can_obtain_block() && !pthread_equal(no_wait_id, pthread_self())) {
446 num_waiting++; /* indicate that I am waiting */
447 while ((retry == 0 || r-- > 0) && !can_obtain_block()) {
448 if ((ret = bthread_cond_wait_p(&wait, &m_mutex, file, line)) != 0) {
449 berrno be;
450 Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
451 be.bstrerror(ret));
452 }
453 }
454 num_waiting--; /* no longer waiting */
455 }
456
457 P(block_mutex);
458 Dmsg4(sd_dbglvl, "Steal lock %s old=%s from %s:%d\n",
459 device->hdr.name, print_blocked(), file, line);
460
461 if (!can_obtain_block() && !pthread_equal(no_wait_id, pthread_self())) {
462 V(block_mutex);
463 return false;
464 }
465 hold->dev_blocked = blocked();
466 hold->dev_prev_blocked = dev_prev_blocked;
467 hold->no_wait_id = no_wait_id;
468 hold->blocked_by = blocked_by;
469 set_blocked(state);
470 Dmsg1(sd_dbglvl, "steal block. new=%s\n", print_blocked());
471 no_wait_id = pthread_self();
472 blocked_by = get_jobid_from_tsd();
473 V(block_mutex);
474 return true;
475 }
476
477 /*
478 * Enter with device blocked and locked by us
479 * Exit with device locked, and blocked by previous owner
480 */
_give_back_device_block(const char * file,int line,DEVICE * dev,bsteal_lock_t * hold)481 void _give_back_device_block(const char *file, int line,
482 DEVICE *dev, bsteal_lock_t *hold)
483 {
484 Dmsg4(sd_dbglvl, "Return lock %s old=%s from %s:%d\n",
485 dev->device->hdr.name, dev->print_blocked(), file, line);
486 P(block_mutex);
487 dev->set_blocked(hold->dev_blocked);
488 dev->dev_prev_blocked = hold->dev_prev_blocked;
489 dev->no_wait_id = hold->no_wait_id;
490 dev->blocked_by = hold->blocked_by;
491 Dmsg1(sd_dbglvl, "return lock. new=%s\n", dev->print_blocked());
492 if (dev->num_waiting > 0) {
493 pthread_cond_broadcast(&dev->wait); /* wake them up */
494 }
495 V(block_mutex);
496 }
497
print_blocked()498 const char *DEVICE::print_blocked() const
499 {
500 switch (m_blocked) {
501 case BST_NOT_BLOCKED:
502 return "BST_NOT_BLOCKED";
503 case BST_UNMOUNTED:
504 return "BST_UNMOUNTED";
505 case BST_WAITING_FOR_SYSOP:
506 return "BST_WAITING_FOR_SYSOP";
507 case BST_DOING_ACQUIRE:
508 return "BST_DOING_ACQUIRE";
509 case BST_WRITING_LABEL:
510 return "BST_WRITING_LABEL";
511 case BST_UNMOUNTED_WAITING_FOR_SYSOP:
512 return "BST_UNMOUNTED_WAITING_FOR_SYSOP";
513 case BST_MOUNT:
514 return "BST_MOUNT";
515 case BST_DESPOOLING:
516 return "BST_DESPOOLING";
517 case BST_RELEASING:
518 return "BST_RELEASING";
519 default:
520 return _("unknown blocked code");
521 }
522 }
523
524
525 /*
526 * Check if the device is blocked or not
527 */
is_device_unmounted()528 bool DEVICE::is_device_unmounted()
529 {
530 bool stat;
531
532 int blk = blocked();
533 stat = (blk == BST_UNMOUNTED) ||
534 (blk == BST_UNMOUNTED_WAITING_FOR_SYSOP);
535 return stat;
536 }
537