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