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