]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/lock.c
Big backport from Enterprise
[bacula/bacula] / bacula / src / stored / lock.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 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 = 300;
31 #else
32 const int dbglvl = 500;
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  *   steal_device_lock() does (must be locked and blocked at entry)
117  *                    save status
118  *                    set new blocked status
119  *                    set new pid
120  *                    Unlock()
121  *
122  *   give_back_device_lock() does (must be blocked but not locked)
123  *                    Lock()
124  *                    reset blocked status
125  *                    save previous blocked
126  *                    reset pid
127  *                    if waiting threads
128  *                       pthread_cond_broadcast
129  *
130  */
131
132 void DEVICE::dblock(int why)
133 {
134    rLock(false);              /* need recursive lock to block */
135    block_device(this, why);
136    rUnlock();
137 }
138
139 void DEVICE::dunblock(bool locked)
140 {
141    if (!locked) {
142       Lock();
143    }
144    unblock_device(this);
145    Unlock();
146 }
147
148
149
150 /*
151  * Debug DEVICE locks  N.B.
152  *
153  */
154
155 #ifdef DEV_DEBUG_LOCK
156
157 void DEVICE::dbg_Lock(const char *file, int line)
158 {
159    Dmsg4(sd_dbglvl, "Lock %s from %s:%d precnt=%d\n", device->hdr.name, file, line, m_count);
160    bthread_mutex_lock_p(&m_mutex, file, line);
161    m_pid = pthread_self();
162    m_count++;
163 }
164
165 void DEVICE::dbg_Unlock(const char *file, int line)
166 {
167    m_count--;
168    clear_thread_id(m_pid);
169    Dmsg4(sd_dbglvl, "Unlock %s from %s:%d postcnt=%d\n", device->hdr.name, file, line, m_count);
170    bthread_mutex_unlock_p(&m_mutex, file, line);
171 }
172
173 void DEVICE::dbg_rUnlock(const char *file, int line)
174 {
175    Dmsg2(sd_dbglvl, "rUnlock from %s:%d\n", file, line);
176    dbg_Unlock(file, line);
177 }
178
179 #else
180
181 /*
182  * DEVICE locks  N.B.
183  *
184  */
185
186
187 void DEVICE::rUnlock()
188 {
189    Unlock();
190 }
191
192 void DEVICE::Lock()
193 {
194    P(m_mutex);
195 }
196
197 void DEVICE::Unlock()
198 {
199    V(m_mutex);
200 }
201
202 #endif /* DEV_DEBUG_LOCK */
203
204 /*
205  * This is a recursive lock that checks if the device is blocked.
206  *
207  * When blocked is set, all threads EXCEPT thread with id no_wait_id
208  * must wait. The no_wait_id thread is out obtaining a new volume
209  * and preparing the label.
210  */
211 #ifdef DEV_DEBUG_LOCK
212 void DEVICE::dbg_rLock(const char *file, int line, bool locked)
213 {
214    Dmsg3(sd_dbglvl, "Enter rLock blked=%s from %s:%d\n", print_blocked(),
215          file, line);
216    if (!locked) {
217       /* lockmgr version of P(m_mutex) */
218       Dmsg4(sd_dbglvl, "Lock %s in rLock %s from %s:%d\n",
219          device->hdr.name, print_blocked(), file, line);
220       bthread_mutex_lock_p(&m_mutex, file, line);
221       m_count++;
222    }
223
224    if (blocked() && !pthread_equal(no_wait_id, pthread_self())) {
225       num_waiting++;             /* indicate that I am waiting */
226       while (blocked()) {
227          int stat;
228 #ifndef HAVE_WIN32
229          /* thread id on Win32 may be a struct */
230          Dmsg5(sd_dbglvl, "Blocked by %d %s in rLock blked=%s no_wait=%p me=%p\n",
231             blocked_by, device->hdr.name, print_blocked(), no_wait_id, pthread_self());
232 #endif
233          if ((stat = bthread_cond_wait_p(&this->wait, &m_mutex, file, line)) != 0) {
234             berrno be;
235             this->dbg_Unlock(file, line);
236             Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
237                be.bstrerror(stat));
238          }
239       }
240       num_waiting--;             /* no longer waiting */
241    }
242 }
243 #else /* DEV_DEBUG_LOCK */
244
245 void DEVICE::rLock(bool locked)
246 {
247    if (!locked) {
248       Lock();
249       m_count++;
250    }
251
252    if (blocked() && !pthread_equal(no_wait_id, pthread_self())) {
253       num_waiting++;             /* indicate that I am waiting */
254       while (blocked()) {
255          int stat;
256 #ifndef HAVE_WIN32
257          /* thread id on Win32 may be a struct */
258          Dmsg5(sd_dbglvl, "Blocked by %d rLock %s blked=%s no_wait=%p me=%p\n",
259             blocked_by, device->hdr.name, print_blocked(), no_wait_id, pthread_self());
260 #endif
261          if ((stat = pthread_cond_wait(&this->wait, &m_mutex)) != 0) {
262             berrno be;
263             this->Unlock();
264             Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
265                be.bstrerror(stat));
266          }
267       }
268       num_waiting--;             /* no longer waiting */
269    }
270 }
271
272 #endif  /* DEV_DEBUG_LOCK */
273
274 #ifdef SD_DEBUG_LOCK
275
276 void DEVICE::dbg_Lock_acquire(const char *file, int line)
277 {
278    Dmsg2(sd_dbglvl, "Lock_acquire from %s:%d\n", file, line);
279    bthread_mutex_lock_p(&acquire_mutex, file, line);
280 }
281
282 void DEVICE::dbg_Unlock_acquire(const char *file, int line)
283 {
284    Dmsg2(sd_dbglvl, "Unlock_acquire from %s:%d\n", file, line);
285    bthread_mutex_unlock_p(&acquire_mutex, file, line);
286 }
287
288 void DEVICE::dbg_Lock_read_acquire(const char *file, int line)
289 {
290    Dmsg2(sd_dbglvl, "Lock_read_acquire from %s:%d\n", file, line);
291    bthread_mutex_lock_p(&read_acquire_mutex, file, line);
292 }
293
294 void DEVICE::dbg_Unlock_read_acquire(const char *file, int line)
295 {
296    Dmsg2(sd_dbglvl, "Unlock_read_acquire from %s:%d\n", file, line);
297    bthread_mutex_unlock_p(&read_acquire_mutex, file, line);
298 }
299
300 void DEVICE::dbg_Lock_VolCatInfo(const char *file, int line)
301 {
302    bthread_mutex_lock_p(&volcat_mutex, file, line);
303 }
304
305 void DEVICE::dbg_Unlock_VolCatInfo(const char *file, int line)
306 {
307    bthread_mutex_unlock_p(&volcat_mutex, file, line);
308 }
309
310 #else
311
312 void DEVICE::Lock_acquire()
313 {
314    P(acquire_mutex);
315 }
316
317 void DEVICE::Unlock_acquire()
318 {
319    V(acquire_mutex);
320 }
321
322 void DEVICE::Lock_read_acquire()
323 {
324    P(read_acquire_mutex);
325 }
326
327 void DEVICE::Unlock_read_acquire()
328 {
329    V(read_acquire_mutex);
330 }
331
332 void DEVICE::Lock_VolCatInfo()
333 {
334    P(volcat_mutex);
335 }
336
337 void DEVICE::Unlock_VolCatInfo()
338 {
339    V(volcat_mutex);
340 }
341
342
343
344 #endif
345
346 /* Main device access control */
347 int DEVICE::init_mutex()
348 {
349    return pthread_mutex_init(&m_mutex, NULL);
350 }
351
352 /* Mutex around the freespace command */
353 int DEVICE::init_freespace_mutex()
354 {
355    return pthread_mutex_init(&freespace_mutex, NULL);
356 }
357
358 /* Write device acquire mutex */
359 int DEVICE::init_acquire_mutex()
360 {
361    return pthread_mutex_init(&acquire_mutex, NULL);
362 }
363
364 /* Read device acquire mutex */
365 int DEVICE::init_read_acquire_mutex()
366 {
367    return pthread_mutex_init(&read_acquire_mutex, NULL);
368 }
369
370 /* VolCatInfo mutex */
371 int DEVICE::init_volcat_mutex()
372 {
373    return pthread_mutex_init(&volcat_mutex, NULL);
374 }
375
376 /* dcrs mutex */
377 int DEVICE::init_dcrs_mutex()
378 {
379    return pthread_mutex_init(&dcrs_mutex, NULL);
380 }
381
382 /* Set order in which device locks must be acquired */
383 void DEVICE::set_mutex_priorities()
384 {
385    /* Ensure that we respect this order in P/V operations */
386    bthread_mutex_set_priority(&m_mutex,       PRIO_SD_DEV_ACCESS);
387    bthread_mutex_set_priority(&spool_mutex,   PRIO_SD_DEV_SPOOL);
388    bthread_mutex_set_priority(&acquire_mutex, PRIO_SD_DEV_ACQUIRE);
389 }
390
391 int DEVICE::next_vol_timedwait(const struct timespec *timeout)
392 {
393    return pthread_cond_timedwait(&wait_next_vol, &m_mutex, timeout);
394 }
395
396
397 /*
398  * Block all other threads from using the device
399  *  Device must already be locked.  After this call,
400  *  the device is blocked to any thread calling dev->rLock(),
401  *  but the device is not locked (i.e. no P on device).  Also,
402  *  the current thread can do slip through the dev->rLock()
403  *  calls without blocking.
404  */
405 void _block_device(const char *file, int line, DEVICE *dev, int state)
406 {
407    ASSERT2(dev->blocked() == BST_NOT_BLOCKED, "Block request of device already blocked");
408    dev->set_blocked(state);           /* make other threads wait */
409    dev->no_wait_id = pthread_self();  /* allow us to continue */
410    dev->blocked_by = get_jobid_from_tsd();
411    Dmsg4(sd_dbglvl, "Blocked %s %s from %s:%d\n",
412       dev->device->hdr.name, dev->print_blocked(), file, line);
413 }
414
415 /*
416  * Unblock the device, and wake up anyone who went to sleep.
417  * Enter: device locked
418  * Exit:  device locked
419  */
420 void _unblock_device(const char *file, int line, DEVICE *dev)
421 {
422    Dmsg4(sd_dbglvl, "Unblocked %s %s from %s:%d\n", dev->device->hdr.name,
423       dev->print_blocked(), file, line);
424    ASSERT2(dev->blocked(), "Unblock request of device not blocked");
425    dev->set_blocked(BST_NOT_BLOCKED);
426    dev->blocked_by = 0;
427    clear_thread_id(dev->no_wait_id);
428    if (dev->num_waiting > 0) {
429       pthread_cond_broadcast(&dev->wait); /* wake them up */
430    }
431 }
432
433 /*
434  * Enter with device locked and blocked
435  * Exit with device unlocked and blocked by us.
436  */
437 void _steal_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state)
438 {
439    Dmsg4(sd_dbglvl, "Steal lock %s old=%s from %s:%d\n",
440       dev->device->hdr.name, dev->print_blocked(), file, line);
441    hold->dev_blocked = dev->blocked();
442    hold->dev_prev_blocked = dev->dev_prev_blocked;
443    hold->no_wait_id = dev->no_wait_id;
444    hold->blocked_by = dev->blocked_by;
445    dev->set_blocked(state);
446    Dmsg1(sd_dbglvl, "steal lock. new=%s\n", dev->print_blocked());
447    dev->no_wait_id = pthread_self();
448    dev->blocked_by = get_jobid_from_tsd();
449    dev->Unlock();
450 }
451
452 /*
453  * Enter with device blocked by us but not locked
454  * Exit with device locked, and blocked by previous owner
455  */
456 void _give_back_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold)
457 {
458    Dmsg4(sd_dbglvl, "Return lock %s old=%s from %s:%d\n",
459       dev->device->hdr.name, dev->print_blocked(), file, line);
460    dev->Lock();
461    dev->set_blocked(hold->dev_blocked);
462    dev->dev_prev_blocked = hold->dev_prev_blocked;
463    dev->no_wait_id = hold->no_wait_id;
464    dev->blocked_by = hold->blocked_by;
465    Dmsg1(sd_dbglvl, "return lock. new=%s\n", dev->print_blocked());
466    if (dev->num_waiting > 0) {
467       pthread_cond_broadcast(&dev->wait); /* wake them up */
468    }
469 }
470
471 const char *DEVICE::print_blocked() const
472 {
473    switch (m_blocked) {
474    case BST_NOT_BLOCKED:
475       return "BST_NOT_BLOCKED";
476    case BST_UNMOUNTED:
477       return "BST_UNMOUNTED";
478    case BST_WAITING_FOR_SYSOP:
479       return "BST_WAITING_FOR_SYSOP";
480    case BST_DOING_ACQUIRE:
481       return "BST_DOING_ACQUIRE";
482    case BST_WRITING_LABEL:
483       return "BST_WRITING_LABEL";
484    case BST_UNMOUNTED_WAITING_FOR_SYSOP:
485       return "BST_UNMOUNTED_WAITING_FOR_SYSOP";
486    case BST_MOUNT:
487       return "BST_MOUNT";
488    case BST_DESPOOLING:
489       return "BST_DESPOOLING";
490    case BST_RELEASING:
491       return "BST_RELEASING";
492    default:
493       return _("unknown blocked code");
494    }
495 }
496
497
498 /*
499  * Check if the device is blocked or not
500  */
501 bool DEVICE::is_device_unmounted()
502 {
503    bool stat;
504
505    int blk = blocked();
506    stat = (blk == BST_UNMOUNTED) ||
507           (blk == BST_UNMOUNTED_WAITING_FOR_SYSOP);
508    return stat;
509 }