1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5 Copyright (C) 2016-2020 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 "stored/device_control_record.h"
33 #include "lib/edit.h"
34 #include "lib/util.h"
35 #include "lib/berrno.h"
36
37 namespace storagedaemon {
38
39 /**
40 * The Storage daemon has three locking concepts that must be understood:
41 *
42 * 1. dblock blocking the device, which means that the device
43 * is "marked" in use. When setting and removing the
44 * block, the device is locked, but after dblock is
45 * called the device is unlocked.
46 * 2. Lock() simple mutex that locks the device structure. A Lock
47 * can be acquired while a device is blocked if it is not
48 * locked.
49 * 3. rLock(locked) "recursive" Lock, when means that a Lock (mutex)
50 * will be acquired on the device if it is not blocked
51 * by some other thread. If the device was blocked by
52 * the current thread, it will acquire the lock.
53 * If some other thread has set a block on the device,
54 * this call will wait until the device is unblocked.
55 * Can be called with locked true, which means the
56 * Lock is already set
57 *
58 * - A lock is normally set when modifying the device structure.
59 * - A rLock is normally acquired when you want to block the device
60 * i.e. it will wait until the device is not blocked.
61 * - A block is normally set during long operations like writing to the device.
62 * - If you are writing the device, you will normally block and lock it.
63 * - A lock cannot be violated. No other thread can touch the
64 * device while a lock is set.
65 * - When a block is set, every thread accept the thread that set
66 * the block will block if rLock is called.
67 * - A device can be blocked for multiple reasons, labeling, writing,
68 * acquiring (opening) the device, waiting for the operator, unmounted,
69 * ...
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 * Functions:
78 *
79 * Device::Lock() does P(mutex_) (in dev.h)
80 * Device::Unlock() does V(mutex_)
81 *
82 * Device::rLock(locked) allows locking the device when this thread
83 * already has the device blocked.
84 * - if (!locked)
85 * Lock()
86 * - if blocked and not same thread that locked
87 * pthread_cond_wait
88 * - leaves device locked
89 *
90 * Device::rUnlock() Unlocks but does not unblock same as Unlock();
91 *
92 * Device::dblock(why) does
93 * - rLock(); (recursive device lock)
94 * - BlockDevice(this, why)
95 * - rUnlock()
96 *
97 * Device::dunblock does
98 * - Lock()
99 * - UnblockDevice()
100 * - Unlock()
101 *
102 * BlockDevice() does (must be locked and not blocked at entry)
103 * - set blocked status
104 * - set our pid
105 *
106 * UnblockDevice() does (must be blocked at entry)
107 * - (locked on entry)
108 * - (locked on exit)
109 * - set unblocked status
110 * - clear pid
111 * - if waiting threads
112 * pthread_cond_broadcast
113 *
114 * StealDeviceLock() does (must be locked and blocked at entry)
115 * - save status
116 * - set new blocked status
117 * - set new pid
118 * - Unlock()
119 *
120 * GiveBackDeviceLock() does (must be blocked but not locked)
121 * - Lock()
122 * - reset blocked status
123 * - save previous blocked
124 * - reset pid
125 * - if waiting threads
126 * pthread_cond_broadcast
127 */
dblock(int why)128 void Device::dblock(int why)
129 {
130 rLock(false); /* need recursive lock to block */
131 BlockDevice(this, why);
132 rUnlock();
133 }
134
dunblock(bool locked)135 void Device::dunblock(bool locked)
136 {
137 if (!locked) { Lock(); }
138 UnblockDevice(this);
139 Unlock();
140 }
141
142 /**
143 * DeviceControlRecord locks N.B.
144 */
145 /**
146 * Multiple rLock implementation
147 */
mLock(bool locked)148 void DeviceControlRecord::mLock(bool locked)
149 {
150 P(r_mutex);
151 if (IsDevLocked()) {
152 V(r_mutex);
153 return;
154 }
155 dev->rLock(locked);
156 IncDevLock();
157 V(r_mutex);
158 return;
159 }
160
161 /**
162 * Multiple rUnlock implementation
163 */
mUnlock()164 void DeviceControlRecord::mUnlock()
165 {
166 P(r_mutex);
167 if (!IsDevLocked()) {
168 V(r_mutex);
169 Emsg1(M_ABORT, 0, "Call on dcr mUnlock when not locked\n");
170 }
171 DecDevLock();
172 /*
173 * When the count goes to zero, unlock it
174 */
175 if (!IsDevLocked()) { dev->rUnlock(); }
176 V(r_mutex);
177 return;
178 }
179
180 /**
181 * Device locks N.B.
182 */
rUnlock()183 void Device::rUnlock() { Unlock(); }
184
Lock()185 void Device::Lock() { P(mutex_); }
186
Unlock()187 void Device::Unlock() { V(mutex_); }
188
Lock_acquire()189 void Device::Lock_acquire() { P(acquire_mutex); }
190
Unlock_acquire()191 void Device::Unlock_acquire() { V(acquire_mutex); }
192
Lock_read_acquire()193 void Device::Lock_read_acquire() { P(read_acquire_mutex); }
194
Unlock_read_acquire()195 void Device::Unlock_read_acquire() { V(read_acquire_mutex); }
196
197 /**
198 * Main device access control
199 */
InitMutex()200 int Device::InitMutex() { return pthread_mutex_init(&mutex_, NULL); }
201
202 /**
203 * Write device acquire mutex
204 */
InitAcquireMutex()205 int Device::InitAcquireMutex()
206 {
207 return pthread_mutex_init(&acquire_mutex, NULL);
208 }
209
210 /**
211 * Read device acquire mutex
212 */
InitReadAcquireMutex()213 int Device::InitReadAcquireMutex()
214 {
215 return pthread_mutex_init(&read_acquire_mutex, NULL);
216 }
217
NextVolTimedwait(const struct timespec * timeout)218 int Device::NextVolTimedwait(const struct timespec* timeout)
219 {
220 return pthread_cond_timedwait(&wait_next_vol, &mutex_, timeout);
221 }
222
223 /**
224 * This is a recursive lock that checks if the device is blocked.
225 *
226 * When blocked is set, all threads EXCEPT thread with id no_wait_id
227 * must wait. The no_wait_id thread is out obtaining a new volume
228 * and preparing the label.
229 */
rLock(bool locked)230 void Device::rLock(bool locked)
231 {
232 if (!locked) {
233 Lock();
234 count_++;
235 }
236
237 if (blocked() && !pthread_equal(no_wait_id, pthread_self())) {
238 num_waiting++; /* indicate that I am waiting */
239 while (blocked()) {
240 int status;
241 char ed1[50], ed2[50];
242
243 Dmsg3(sd_debuglevel, "rLock blked=%s no_wait=%s me=%s\n", print_blocked(),
244 edit_pthread(no_wait_id, ed1, sizeof(ed1)),
245 edit_pthread(pthread_self(), ed2, sizeof(ed2)));
246 if ((status = pthread_cond_wait(&wait, &mutex_)) != 0) {
247 BErrNo be;
248 this->Unlock();
249 Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
250 be.bstrerror(status));
251 }
252 }
253 num_waiting--; /* no longer waiting */
254 }
255 }
256
257 /**
258 * Block all other threads from using the device
259 *
260 * Device must already be locked. After this call,
261 * the device is blocked to any thread calling dev->rLock(),
262 * but the device is not locked (i.e. no P on device). Also,
263 * the current thread can do slip through the dev->rLock()
264 * calls without blocking.
265 */
_blockDevice(const char * file,int line,Device * dev,int state)266 void _blockDevice(const char* file, int line, Device* dev, int state)
267 {
268 ASSERT(dev->blocked() == BST_NOT_BLOCKED);
269 dev->SetBlocked(state); /* make other threads wait */
270 dev->no_wait_id = pthread_self(); /* allow us to continue */
271 Dmsg3(sd_debuglevel, "set blocked=%s from %s:%d\n", dev->print_blocked(),
272 file, line);
273 }
274
275 /**
276 * Unblock the device, and wake up anyone who went to sleep.
277 * Enter: device locked
278 * Exit: device locked
279 */
_unBlockDevice(const char * file,int line,Device * dev)280 void _unBlockDevice(const char* file, int line, Device* dev)
281 {
282 Dmsg3(sd_debuglevel, "unblock %s from %s:%d\n", dev->print_blocked(), file,
283 line);
284 ASSERT(dev->blocked());
285 dev->SetBlocked(BST_NOT_BLOCKED);
286 ClearThreadId(dev->no_wait_id);
287 if (dev->num_waiting > 0) {
288 pthread_cond_broadcast(&dev->wait); /* wake them up */
289 }
290 }
291
292 /**
293 * Enter with device locked and blocked
294 * Exit with device unlocked and blocked by us.
295 */
_stealDeviceLock(const char * file,int line,Device * dev,bsteal_lock_t * hold,int state)296 void _stealDeviceLock(const char* file,
297 int line,
298 Device* dev,
299 bsteal_lock_t* hold,
300 int state)
301 {
302 Dmsg3(sd_debuglevel, "steal lock. old=%s from %s:%d\n", dev->print_blocked(),
303 file, line);
304 hold->dev_blocked = dev->blocked();
305 hold->dev_prev_blocked = dev->dev_prev_blocked;
306 hold->no_wait_id = dev->no_wait_id;
307 dev->SetBlocked(state);
308 Dmsg1(sd_debuglevel, "steal lock. new=%s\n", dev->print_blocked());
309 dev->no_wait_id = pthread_self();
310 dev->Unlock();
311 }
312
313 /**
314 * Enter with device blocked by us but not locked
315 * Exit with device locked, and blocked by previous owner
316 */
_giveBackDeviceLock(const char * file,int line,Device * dev,bsteal_lock_t * hold)317 void _giveBackDeviceLock(const char* file,
318 int line,
319 Device* dev,
320 bsteal_lock_t* hold)
321 {
322 Dmsg3(sd_debuglevel, "return lock. old=%s from %s:%d\n", dev->print_blocked(),
323 file, line);
324 dev->Lock();
325 dev->SetBlocked(hold->dev_blocked);
326 dev->dev_prev_blocked = hold->dev_prev_blocked;
327 dev->no_wait_id = hold->no_wait_id;
328 Dmsg1(sd_debuglevel, "return lock. new=%s\n", dev->print_blocked());
329 if (dev->num_waiting > 0) {
330 pthread_cond_broadcast(&dev->wait); /* wake them up */
331 }
332 }
333
print_blocked() const334 const char* Device::print_blocked() const
335 {
336 switch (blocked_) {
337 case BST_NOT_BLOCKED:
338 return "BST_NOT_BLOCKED";
339 case BST_UNMOUNTED:
340 return "BST_UNMOUNTED";
341 case BST_WAITING_FOR_SYSOP:
342 return "BST_WAITING_FOR_SYSOP";
343 case BST_DOING_ACQUIRE:
344 return "BST_DOING_ACQUIRE";
345 case BST_WRITING_LABEL:
346 return "BST_WRITING_LABEL";
347 case BST_UNMOUNTED_WAITING_FOR_SYSOP:
348 return "BST_UNMOUNTED_WAITING_FOR_SYSOP";
349 case BST_MOUNT:
350 return "BST_MOUNT";
351 case BST_DESPOOLING:
352 return "BST_DESPOOLING";
353 case BST_RELEASING:
354 return "BST_RELEASING";
355 default:
356 return _("unknown blocked code");
357 }
358 }
359
360 /**
361 * Check if the device is blocked or not
362 */
IsDeviceUnmounted()363 bool Device::IsDeviceUnmounted()
364 {
365 bool status;
366 int blk = blocked();
367
368 status = (blk == BST_UNMOUNTED) || (blk == BST_UNMOUNTED_WAITING_FOR_SYSOP);
369
370 return status;
371 }
372
373 } /* namespace storagedaemon */
374