1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5 Copyright (C) 2016-2016 Bareos GmbH & Co. KG
6
7 This program is Free Software; you can redistribute it and/or
8 modify it under the terms of version three of the GNU Affero General Public
9 License as published by the Free Software Foundation and included
10 in the file LICENSE.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
21 */
22 /*
23 * Kern Sibbald, June 2007
24 */
25 /*+
26 * @file
27 * Collection of Bacula Storage daemon locking software
28 */
29
30 #include "include/bareos.h" /* pull in global headers */
31 #include "stored/stored.h" /* pull in Storage Daemon headers */
32 #include "lib/edit.h"
33 #include "lib/util.h"
34 #include "lib/berrno.h"
35
36 namespace storagedaemon {
37
38 /**
39 * The Storage daemon has three locking concepts that must be 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 the device.
61 * - If you are writing the device, you will normally block and lock it.
62 * - A lock cannot be violated. No other thread can touch the
63 * device while a lock is set.
64 * - When a block is set, every thread accept the thread that set
65 * the block will block if rLock is called.
66 * - A device can be blocked for multiple reasons, labeling, writing,
67 * acquiring (opening) the device, waiting for the operator, unmounted,
68 * ...
69 *
70 * Under certain conditions the block that is set on a device can be
71 * stolen and the device can be used by another thread. For example,
72 * a device is blocked because it is waiting for the operator to
73 * mount a tape. The operator can then unmount the device, and label
74 * a tape, re-mount it, give back the block, and the job will continue.
75 *
76 * Functions:
77 *
78 * Device::Lock() does P(mutex_) (in dev.h)
79 * Device::Unlock() does V(mutex_)
80 *
81 * Device::rLock(locked) allows locking the device when this thread
82 * already has the device blocked.
83 * - if (!locked)
84 * Lock()
85 * - if blocked and not same thread that locked
86 * pthread_cond_wait
87 * - leaves device locked
88 *
89 * Device::rUnlock() Unlocks but does not unblock same as Unlock();
90 *
91 * Device::dblock(why) does
92 * - rLock(); (recursive device lock)
93 * - BlockDevice(this, why)
94 * - rUnlock()
95 *
96 * Device::dunblock does
97 * - Lock()
98 * - UnblockDevice()
99 * - Unlock()
100 *
101 * BlockDevice() does (must be locked and not blocked at entry)
102 * - set blocked status
103 * - set our pid
104 *
105 * UnblockDevice() does (must be blocked at entry)
106 * - (locked on entry)
107 * - (locked on exit)
108 * - set unblocked status
109 * - clear pid
110 * - if waiting threads
111 * pthread_cond_broadcast
112 *
113 * StealDeviceLock() does (must be locked and blocked at entry)
114 * - save status
115 * - set new blocked status
116 * - set new pid
117 * - Unlock()
118 *
119 * GiveBackDeviceLock() does (must be blocked but not locked)
120 * - Lock()
121 * - reset blocked status
122 * - save previous blocked
123 * - reset pid
124 * - if waiting threads
125 * pthread_cond_broadcast
126 */
dblock(int why)127 void Device::dblock(int why)
128 {
129 rLock(false); /* need recursive lock to block */
130 BlockDevice(this, why);
131 rUnlock();
132 }
133
dunblock(bool locked)134 void Device::dunblock(bool locked)
135 {
136 if (!locked) { Lock(); }
137 UnblockDevice(this);
138 Unlock();
139 }
140
141 #ifdef SD_DEBUG_LOCK
142 /**
143 * Debug DeviceControlRecord locks N.B.
144 *
145 */
dbg_mLock(const char * file,int line,bool locked)146 void DeviceControlRecord::dbg_mLock(const char* file, int line, bool locked)
147 {
148 real_P(r_mutex);
149 if (IsDevLocked()) {
150 real_V(r_mutex);
151 return;
152 }
153 Dmsg3(sd_debuglevel, "mLock %d from %s:%d\n", locked, file, line);
154 dev->dbg_rLock(file, line, locked);
155 IncDevLock();
156 real_V(r_mutex);
157 return;
158 }
159
dbg_mUnlock(const char * file,int line)160 void DeviceControlRecord::dbg_mUnlock(const char* file, int line)
161 {
162 Dmsg2(sd_debuglevel, "mUnlock from %s:%d\n", file, line);
163 real_P(r_mutex);
164 if (!IsDevLocked()) {
165 real_P(r_mutex);
166 ASSERT2(0, "Call on dcr mUnlock when not locked");
167 return;
168 }
169 DecDevLock();
170 /* When the count goes to zero, unlock it */
171 if (!IsDevLocked()) { dev->dbg_rUnlock(file, line); }
172 real_V(r_mutex);
173 return;
174 }
175
dbg_Unlock(const char * file,int line)176 void Device::dbg_Unlock(const char* file, int line)
177 {
178 count_--;
179 Dmsg3(sd_debuglevel, "Unlock from %s:%d postcnt=%d\n", file, line, count_);
180 pthread_mutex_unlock(&mutex_);
181 }
182
dbg_rUnlock(const char * file,int line)183 void Device::dbg_rUnlock(const char* file, int line)
184 {
185 Dmsg2(sd_debuglevel, "rUnlock from %s:%d\n", file, line);
186 dbg_Unlock(file, line);
187 }
188
dbg_Lock_acquire(const char * file,int line)189 void Device::dbg_Lock_acquire(const char* file, int line)
190 {
191 Dmsg2(sd_debuglevel, "Lock_acquire from %s:%d\n", file, line);
192 pthread_mutex_lock(&acquire_mutex);
193 }
194
dbg_Unlock_acquire(const char * file,int line)195 void Device::dbg_Unlock_acquire(const char* file, int line)
196 {
197 Dmsg2(sd_debuglevel, "Unlock_acquire from %s:%d\n", file, line);
198 pthread_mutex_unlock(&acquire_mutex);
199 }
200
dbg_Lock_read_acquire(const char * file,int line)201 void Device::dbg_Lock_read_acquire(const char* file, int line)
202 {
203 Dmsg2(sd_debuglevel, "Lock_read_acquire from %s:%d\n", file, line);
204 pthread_mutex_lock(&read_acquire_mutex);
205 }
206
dbg_Unlock_read_acquire(const char * file,int line)207 void Device::dbg_Unlock_read_acquire(const char* file, int line)
208 {
209 Dmsg2(sd_debuglevel, "Unlock_read_acquire from %s:%d\n", file, line);
210 pthread_mutex_unlock(&read_acquire_mutex);
211 }
212
213 #else
214
215 /**
216 * DeviceControlRecord locks N.B.
217 */
218 /**
219 * Multiple rLock implementation
220 */
mLock(bool locked)221 void DeviceControlRecord::mLock(bool locked)
222 {
223 P(r_mutex);
224 if (IsDevLocked()) {
225 V(r_mutex);
226 return;
227 }
228 dev->rLock(locked);
229 IncDevLock();
230 V(r_mutex);
231 return;
232 }
233
234 /**
235 * Multiple rUnlock implementation
236 */
mUnlock()237 void DeviceControlRecord::mUnlock()
238 {
239 P(r_mutex);
240 if (!IsDevLocked()) {
241 V(r_mutex);
242 ASSERT2(0, "Call on dcr mUnlock when not locked");
243 return;
244 }
245 DecDevLock();
246 /*
247 * When the count goes to zero, unlock it
248 */
249 if (!IsDevLocked()) { dev->rUnlock(); }
250 V(r_mutex);
251 return;
252 }
253
254 /**
255 * Device locks N.B.
256 */
rUnlock()257 void Device::rUnlock() { Unlock(); }
258
Lock()259 void Device::Lock() { P(mutex_); }
260
Unlock()261 void Device::Unlock() { V(mutex_); }
262
Lock_acquire()263 void Device::Lock_acquire() { P(acquire_mutex); }
264
Unlock_acquire()265 void Device::Unlock_acquire() { V(acquire_mutex); }
266
Lock_read_acquire()267 void Device::Lock_read_acquire() { P(read_acquire_mutex); }
268
Unlock_read_acquire()269 void Device::Unlock_read_acquire() { V(read_acquire_mutex); }
270
271 #endif
272
273 /**
274 * Main device access control
275 */
InitMutex()276 int Device::InitMutex() { return pthread_mutex_init(&mutex_, NULL); }
277
278 /**
279 * Write device acquire mutex
280 */
InitAcquireMutex()281 int Device::InitAcquireMutex()
282 {
283 return pthread_mutex_init(&acquire_mutex, NULL);
284 }
285
286 /**
287 * Read device acquire mutex
288 */
InitReadAcquireMutex()289 int Device::InitReadAcquireMutex()
290 {
291 return pthread_mutex_init(&read_acquire_mutex, NULL);
292 }
293
NextVolTimedwait(const struct timespec * timeout)294 int Device::NextVolTimedwait(const struct timespec* timeout)
295 {
296 return pthread_cond_timedwait(&wait_next_vol, &mutex_, timeout);
297 }
298
299 /**
300 * This is a recursive lock that checks if the device is blocked.
301 *
302 * When blocked is set, all threads EXCEPT thread with id no_wait_id
303 * must wait. The no_wait_id thread is out obtaining a new volume
304 * and preparing the label.
305 */
306 #ifdef SD_DEBUG_LOCK
dbg_rLock(const char * file,int line,bool locked)307 void Device::dbg_rLock(const char* file, int line, bool locked)
308 {
309 Dmsg3(sd_debuglevel, "rLock blked=%s from %s:%d\n", print_blocked(), file,
310 line);
311 if (!locked) {
312 pthread_mutex_lock(&mutex);
313 count_++;
314 }
315 #else
316 void Device::rLock(bool locked)
317 {
318 if (!locked) {
319 Lock();
320 count_++;
321 }
322 #endif
323
324 if (blocked() && !pthread_equal(no_wait_id, pthread_self())) {
325 num_waiting++; /* indicate that I am waiting */
326 while (blocked()) {
327 int status;
328 char ed1[50], ed2[50];
329
330 Dmsg3(sd_debuglevel, "rLock blked=%s no_wait=%s me=%s\n", print_blocked(),
331 edit_pthread(no_wait_id, ed1, sizeof(ed1)),
332 edit_pthread(pthread_self(), ed2, sizeof(ed2)));
333 if ((status = pthread_cond_wait(&wait, &mutex_)) != 0) {
334 BErrNo be;
335 this->Unlock();
336 Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
337 be.bstrerror(status));
338 }
339 }
340 num_waiting--; /* no longer waiting */
341 }
342 }
343
344 /**
345 * Block all other threads from using the device
346 *
347 * Device must already be locked. After this call,
348 * the device is blocked to any thread calling dev->rLock(),
349 * but the device is not locked (i.e. no P on device). Also,
350 * the current thread can do slip through the dev->rLock()
351 * calls without blocking.
352 */
353 void _blockDevice(const char* file, int line, Device* dev, int state)
354 {
355 ASSERT(dev->blocked() == BST_NOT_BLOCKED);
356 dev->SetBlocked(state); /* make other threads wait */
357 dev->no_wait_id = pthread_self(); /* allow us to continue */
358 Dmsg3(sd_debuglevel, "set blocked=%s from %s:%d\n", dev->print_blocked(),
359 file, line);
360 }
361
362 /**
363 * Unblock the device, and wake up anyone who went to sleep.
364 * Enter: device locked
365 * Exit: device locked
366 */
367 void _unBlockDevice(const char* file, int line, Device* dev)
368 {
369 Dmsg3(sd_debuglevel, "unblock %s from %s:%d\n", dev->print_blocked(), file,
370 line);
371 ASSERT(dev->blocked());
372 dev->SetBlocked(BST_NOT_BLOCKED);
373 ClearThreadId(dev->no_wait_id);
374 if (dev->num_waiting > 0) {
375 pthread_cond_broadcast(&dev->wait); /* wake them up */
376 }
377 }
378
379 /**
380 * Enter with device locked and blocked
381 * Exit with device unlocked and blocked by us.
382 */
383 void _stealDeviceLock(const char* file,
384 int line,
385 Device* dev,
386 bsteal_lock_t* hold,
387 int state)
388 {
389 Dmsg3(sd_debuglevel, "steal lock. old=%s from %s:%d\n", dev->print_blocked(),
390 file, line);
391 hold->dev_blocked = dev->blocked();
392 hold->dev_prev_blocked = dev->dev_prev_blocked;
393 hold->no_wait_id = dev->no_wait_id;
394 dev->SetBlocked(state);
395 Dmsg1(sd_debuglevel, "steal lock. new=%s\n", dev->print_blocked());
396 dev->no_wait_id = pthread_self();
397 dev->Unlock();
398 }
399
400 /**
401 * Enter with device blocked by us but not locked
402 * Exit with device locked, and blocked by previous owner
403 */
404 void _giveBackDeviceLock(const char* file,
405 int line,
406 Device* dev,
407 bsteal_lock_t* hold)
408 {
409 Dmsg3(sd_debuglevel, "return lock. old=%s from %s:%d\n", dev->print_blocked(),
410 file, line);
411 dev->Lock();
412 dev->SetBlocked(hold->dev_blocked);
413 dev->dev_prev_blocked = hold->dev_prev_blocked;
414 dev->no_wait_id = hold->no_wait_id;
415 Dmsg1(sd_debuglevel, "return lock. new=%s\n", dev->print_blocked());
416 if (dev->num_waiting > 0) {
417 pthread_cond_broadcast(&dev->wait); /* wake them up */
418 }
419 }
420
421 const char* Device::print_blocked() const
422 {
423 switch (blocked_) {
424 case BST_NOT_BLOCKED:
425 return "BST_NOT_BLOCKED";
426 case BST_UNMOUNTED:
427 return "BST_UNMOUNTED";
428 case BST_WAITING_FOR_SYSOP:
429 return "BST_WAITING_FOR_SYSOP";
430 case BST_DOING_ACQUIRE:
431 return "BST_DOING_ACQUIRE";
432 case BST_WRITING_LABEL:
433 return "BST_WRITING_LABEL";
434 case BST_UNMOUNTED_WAITING_FOR_SYSOP:
435 return "BST_UNMOUNTED_WAITING_FOR_SYSOP";
436 case BST_MOUNT:
437 return "BST_MOUNT";
438 case BST_DESPOOLING:
439 return "BST_DESPOOLING";
440 case BST_RELEASING:
441 return "BST_RELEASING";
442 default:
443 return _("unknown blocked code");
444 }
445 }
446
447 /**
448 * Check if the device is blocked or not
449 */
450 bool Device::IsDeviceUnmounted()
451 {
452 bool status;
453 int blk = blocked();
454
455 status = (blk == BST_UNMOUNTED) || (blk == BST_UNMOUNTED_WAITING_FOR_SYSOP);
456
457 return status;
458 }
459
460 } /* namespace storagedaemon */
461