]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/lock.c
Check pool memory size for truncate op
[bacula/bacula] / bacula / src / stored / lock.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Collection of Bacula Storage daemon locking software
30  *
31  *  Kern Sibbald, 2000-2007.  June 2007
32  *
33  *   Version $Id$
34  */
35
36 #include "bacula.h"                   /* pull in global headers */
37 #include "stored.h"                   /* pull in Storage Deamon headers */
38
39 #ifdef SD_DEBUG_LOCK
40 const int dbglvl = 0;
41 #else
42 const int dbglvl = 500;
43 #endif
44
45
46 /*
47  *
48  * The Storage daemon has three locking concepts that must be
49  *   understood:
50  *
51  *  1. dblock    blocking the device, which means that the device
52  *               is "marked" in use.  When setting and removing the
53                  block, the device is locked, but after dblock is
54                  called the device is unlocked.
55  *  2. dlock()   simple mutex that locks the device structure. A dlock
56  *               can be acquired while a device is blocked if it is not
57  *               locked.      
58  *  3. r_dlock(locked)  "recursive" dlock, when means that a dlock (mutex)
59  *               will be acquired on the device if it is not blocked
60  *               by some other thread. If the device was blocked by
61  *               the current thread, it will acquire the lock.
62  *               If some other thread has set a block on the device,
63  *               this call will wait until the device is unblocked.
64  *               Can be called with locked true, which means the
65  *               dlock is already set
66  *
67  *  A lock is normally set when modifying the device structure.
68  *  A r_lock is normally acquired when you want to block the device
69  *    i.e. it will wait until the device is not blocked.
70  *  A block is normally set during long operations like writing to
71  *    the device.
72  *  If you are writing the device, you will normally block and 
73  *    lock it.
74  *  A lock cannot be violated. No other thread can touch the
75  *    device while a lock is set.  
76  *  When a block is set, every thread accept the thread that set
77  *    the block will block if r_dlock is called.
78  *  A device can be blocked for multiple reasons, labeling, writing,
79  *    acquiring (opening) the device, waiting for the operator, unmounted,
80  *    ...
81  *  Under certain conditions the block that is set on a device can be    
82  *    stolen and the device can be used by another thread. For example,
83  *    a device is blocked because it is waiting for the operator to  
84  *    mount a tape.  The operator can then unmount the device, and label
85  *    a tape, re-mount it, give back the block, and the job will continue.
86  *
87  *
88  * Functions:
89  *
90  *   DEVICE::dlock()   does P(m_mutex)     (in dev.h)
91  *   DEVICE::dunlock() does V(m_mutex)
92  *
93  *   DEVICE::r_dlock(locked) allows locking the device when this thread
94  *                     already has the device blocked.
95  *                    if (!locked)
96  *                       dlock()
97  *                    if blocked and not same thread that locked
98  *                       pthread_cond_wait
99  *                    leaves device locked 
100  *
101  *   DEVICE::r_dunlock() unlocks but does not unblock
102  *                    same as dunlock();
103  *
104  *   DEVICE::dblock(why)  does 
105  *                    r_dlock();         (recursive device lock)
106  *                    block_device(this, why) 
107  *                    r_dunlock()
108  *
109  *   DEVICE::dunblock does
110  *                    dlock()
111  *                    unblock_device()
112  *                    dunlock()
113  *
114  *   block_device() does  (must be locked and not blocked at entry)  
115  *                    set blocked status
116  *                    set our pid
117  *
118  *   unblock_device() does (must be blocked at entry)
119  *                        (locked on entry)
120  *                        (locked on exit)
121  *                    set unblocked status
122  *                    clear pid
123  *                    if waiting threads
124  *                       pthread_cond_broadcast
125  *
126  *   steal_device_lock() does (must be locked and blocked at entry)
127  *                    save status
128  *                    set new blocked status
129  *                    set new pid
130  *                    unlock()
131  *
132  *   give_back_device_lock() does (must be blocked but not locked)
133  *                    dlock()
134  *                    reset blocked status
135  *                    save previous blocked
136  *                    reset pid
137  *                    if waiting threads
138  *                       pthread_cond_broadcast
139  *
140  */
141
142
143 void DEVICE::dblock(int why)
144 {
145    r_dlock();              /* need recursive lock to block */
146    block_device(this, why);
147    r_dunlock();
148 }
149
150 void DEVICE::dunblock(bool locked)
151 {
152    if (!locked) {
153       dlock();
154    }
155    unblock_device(this);
156    dunlock();
157 }
158
159
160 #ifdef SD_DEBUG_LOCK
161 void DCR::_dlock(const char *file, int line)
162 {
163    dev->_dlock(file, line);
164    m_dev_locked = true;
165 }
166 void DCR::_dunlock(const char *file, int line)
167 {
168    m_dev_locked = false;
169    dev->_dunlock(file, line);
170
171 }
172
173 void DEVICE::_dlock(const char *file, int line)
174 {
175    Dmsg3(sd_dbglvl, "dlock from %s:%d precnt=%d\n", file, line, m_count); 
176    /* Note, this *really* should be protected by a mutex, but
177     *  since it is only debug code we don't worry too much.  
178     */
179    if (m_count > 0 && pthread_equal(m_pid, pthread_self())) {
180       Dmsg4(sd_dbglvl, "Possible DEADLOCK!! lock held by JobId=%u from %s:%d m_count=%d\n", 
181             get_jobid_from_tid(m_pid),
182             file, line, m_count);
183    }
184    P(m_mutex);
185    m_pid = pthread_self();
186    m_count++; 
187 }
188
189 void DEVICE::_dunlock(const char *file, int line)
190 {
191    m_count--; 
192    Dmsg3(sd_dbglvl+1, "dunlock from %s:%d postcnt=%d\n", file, line, m_count); 
193    V(m_mutex);   
194 }
195
196 void DEVICE::_r_dunlock(const char *file, int line)
197 {
198    this->_dunlock(file, line);
199 }
200
201 #endif
202
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 SD_DEBUG_LOCK
212 void DEVICE::_r_dlock(const char *file, int line, bool locked)
213 {
214    Dmsg3(sd_dbglvl+1, "r_dlock blked=%s from %s:%d\n", this->print_blocked(),
215          file, line);
216 #else
217 void DEVICE::r_dlock(bool locked)
218 {
219 #endif
220    int stat;
221    if (!locked) {
222       P(m_mutex); /*    this->dlock();   */
223       m_count++;  /*    this->dlock() */
224    }
225    if (this->blocked() && !pthread_equal(this->no_wait_id, pthread_self())) {
226       this->num_waiting++;             /* indicate that I am waiting */
227       while (this->blocked()) {
228 #ifndef HAVE_WIN32
229          /* thread id on Win32 may be a struct */
230          Dmsg3(sd_dbglvl, "r_dlock blked=%s no_wait=%p me=%p\n", this->print_blocked(),
231                this->no_wait_id, pthread_self());
232 #endif
233          if ((stat = pthread_cond_wait(&this->wait, &m_mutex)) != 0) {
234             berrno be;
235             this->dunlock();
236             Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
237                be.bstrerror(stat));
238          }
239       }
240       this->num_waiting--;             /* no longer waiting */
241    }
242 }
243
244 /*
245  * Block all other threads from using the device
246  *  Device must already be locked.  After this call,
247  *  the device is blocked to any thread calling dev->r_lock(),
248  *  but the device is not locked (i.e. no P on device).  Also,
249  *  the current thread can do slip through the dev->r_lock()
250  *  calls without blocking.
251  */
252 void _block_device(const char *file, int line, DEVICE *dev, int state)
253 {
254    ASSERT(dev->blocked() == BST_NOT_BLOCKED);
255    dev->set_blocked(state);           /* make other threads wait */
256    dev->no_wait_id = pthread_self();  /* allow us to continue */
257    Dmsg3(sd_dbglvl, "set blocked=%s from %s:%d\n", dev->print_blocked(), file, line);
258 }
259
260 /*
261  * Unblock the device, and wake up anyone who went to sleep.
262  * Enter: device locked
263  * Exit:  device locked
264  */
265 void _unblock_device(const char *file, int line, DEVICE *dev)
266 {
267    Dmsg3(sd_dbglvl, "unblock %s from %s:%d\n", dev->print_blocked(), file, line);
268    ASSERT(dev->blocked());
269    dev->set_blocked(BST_NOT_BLOCKED);
270    clear_thread_id(dev->no_wait_id);
271    if (dev->num_waiting > 0) {
272       pthread_cond_broadcast(&dev->wait); /* wake them up */
273    }
274 }
275
276 /*
277  * Enter with device locked and blocked
278  * Exit with device unlocked and blocked by us.
279  */
280 void _steal_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state)
281 {
282
283    Dmsg3(sd_dbglvl, "steal lock. old=%s from %s:%d\n", dev->print_blocked(),
284       file, line);
285    hold->dev_blocked = dev->blocked();
286    hold->dev_prev_blocked = dev->dev_prev_blocked;
287    hold->no_wait_id = dev->no_wait_id;
288    dev->set_blocked(state);
289    Dmsg1(sd_dbglvl, "steal lock. new=%s\n", dev->print_blocked());
290    dev->no_wait_id = pthread_self();
291    dev->dunlock();
292 }
293
294 /*
295  * Enter with device blocked by us but not locked
296  * Exit with device locked, and blocked by previous owner
297  */
298 void _give_back_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold)
299 {
300    Dmsg3(sd_dbglvl, "return lock. old=%s from %s:%d\n",
301       dev->print_blocked(), file, line);
302    dev->dlock();
303    dev->set_blocked(hold->dev_blocked);
304    dev->dev_prev_blocked = hold->dev_prev_blocked;
305    dev->no_wait_id = hold->no_wait_id;
306    Dmsg1(sd_dbglvl, "return lock. new=%s\n", dev->print_blocked());
307    if (dev->num_waiting > 0) {
308       pthread_cond_broadcast(&dev->wait); /* wake them up */
309    }
310 }
311
312 const char *DEVICE::print_blocked() const 
313 {
314    switch (m_blocked) {
315    case BST_NOT_BLOCKED:
316       return "BST_NOT_BLOCKED";
317    case BST_UNMOUNTED:
318       return "BST_UNMOUNTED";
319    case BST_WAITING_FOR_SYSOP:
320       return "BST_WAITING_FOR_SYSOP";
321    case BST_DOING_ACQUIRE:
322       return "BST_DOING_ACQUIRE";
323    case BST_WRITING_LABEL:
324       return "BST_WRITING_LABEL";
325    case BST_UNMOUNTED_WAITING_FOR_SYSOP:
326       return "BST_UNMOUNTED_WAITING_FOR_SYSOP";
327    case BST_MOUNT:
328       return "BST_MOUNT";
329    case BST_DESPOOLING:
330       return "BST_DESPOOLING";
331    case BST_RELEASING:
332       return "BST_RELEASING";
333    default:
334       return _("unknown blocked code");
335    }
336 }
337
338
339 /*
340  * Check if the device is blocked or not
341  */
342 bool DEVICE::is_device_unmounted()
343 {
344    bool stat;
345    int blk = blocked();
346    stat = (blk == BST_UNMOUNTED) ||
347           (blk == BST_UNMOUNTED_WAITING_FOR_SYSOP);
348    return stat;
349 }