]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/lock.c
Move reservations message lock to lock jcr only this
[bacula/bacula] / bacula / src / stored / lock.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 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 John Walker.
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 void DEVICE::block(int why)
47 {
48    r_dlock();              /* need recursive lock to block */
49    block_device(this, why);
50    r_dunlock();
51 }
52
53 void DEVICE::unblock(bool locked)
54 {
55    if (!locked) {
56       dlock();
57    }
58    unblock_device(this);
59    dunlock();
60 }
61
62
63 #ifdef SD_DEBUG_LOCK
64 void DEVICE::_dlock(const char *file, int line)
65 {
66    Dmsg4(sd_dbglvl, "dlock from %s:%d precnt=%d JobId=%u\n", file, line,
67          m_count, get_jobid_from_tid()); 
68    /* Note, this *really* should be protected by a mutex, but
69     *  since it is only debug code we don't worry too much.  
70     */
71    if (m_count > 0 && pthread_equal(m_pid, pthread_self())) {
72       Dmsg5(sd_dbglvl, "Possible DEADLOCK!! lock held by JobId=%u from %s:%d m_count=%d JobId=%u\n", 
73             get_jobid_from_tid(m_pid),
74             file, line, m_count, get_jobid_from_tid());
75    }
76    P(m_mutex);
77    m_pid = pthread_self();
78    m_count++; 
79 }
80
81 void DEVICE::_dunlock(const char *file, int line)
82 {
83    m_count--; 
84    Dmsg4(sd_dbglvl+1, "dunlock from %s:%d postcnt=%d JobId=%u\n", file, line,
85          m_count, get_jobid_from_tid()); 
86    V(m_mutex);   
87 }
88
89 void DEVICE::_r_dunlock(const char *file, int line)
90 {
91    this->_dunlock(file, line);
92 }
93
94 #endif
95
96
97 /*
98  * This is a recursive lock that checks if the device is blocked.
99  *
100  * When blocked is set, all threads EXCEPT thread with id no_wait_id
101  * must wait. The no_wait_id thread is out obtaining a new volume
102  * and preparing the label.
103  */
104 #ifdef SD_DEBUG_LOCK
105 void DEVICE::_r_dlock(const char *file, int line)
106 #else
107 void DEVICE::r_dlock()
108 #endif
109 {
110    int stat;
111 #ifdef SD_DEBUG_LOCK
112    Dmsg4(sd_dbglvl+1, "r_dlock blked=%s from %s:%d JobId=%u\n", this->print_blocked(),
113          file, line, get_jobid_from_tid());
114 #else
115    Dmsg1(sd_dbglvl, "reclock blked=%s\n", this->print_blocked());
116 #endif
117    this->dlock();   
118    if (this->blocked() && !pthread_equal(this->no_wait_id, pthread_self())) {
119       this->num_waiting++;             /* indicate that I am waiting */
120       while (this->blocked()) {
121          Dmsg3(sd_dbglvl, "r_dlock blked=%s no_wait=%p me=%p\n", this->print_blocked(),
122                this->no_wait_id, pthread_self());
123          if ((stat = pthread_cond_wait(&this->wait, &m_mutex)) != 0) {
124             berrno be;
125             this->dunlock();
126             Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
127                be.bstrerror(stat));
128          }
129       }
130       this->num_waiting--;             /* no longer waiting */
131    }
132 }
133
134 /*
135  * Block all other threads from using the device
136  *  Device must already be locked.  After this call,
137  *  the device is blocked to any thread calling dev->r_lock(),
138  *  but the device is not locked (i.e. no P on device).  Also,
139  *  the current thread can do slip through the dev->r_lock()
140  *  calls without blocking.
141  */
142 void _block_device(const char *file, int line, DEVICE *dev, int state)
143 {
144    ASSERT(dev->blocked() == BST_NOT_BLOCKED);
145    dev->set_blocked(state);           /* make other threads wait */
146    dev->no_wait_id = pthread_self();  /* allow us to continue */
147    Dmsg3(sd_dbglvl, "set blocked=%s from %s:%d\n", dev->print_blocked(), file, line);
148 }
149
150 /*
151  * Unblock the device, and wake up anyone who went to sleep.
152  * Enter: device locked
153  * Exit:  device locked
154  */
155 void _unblock_device(const char *file, int line, DEVICE *dev)
156 {
157    Dmsg3(sd_dbglvl, "unblock %s from %s:%d\n", dev->print_blocked(), file, line);
158    ASSERT(dev->blocked());
159    dev->set_blocked(BST_NOT_BLOCKED);
160    dev->no_wait_id = 0;
161    if (dev->num_waiting > 0) {
162       pthread_cond_broadcast(&dev->wait); /* wake them up */
163    }
164 }
165
166 /*
167  * Enter with device locked and blocked
168  * Exit with device unlocked and blocked by us.
169  */
170 void _steal_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state)
171 {
172
173    Dmsg3(sd_dbglvl, "steal lock. old=%s from %s:%d\n", dev->print_blocked(),
174       file, line);
175    hold->dev_blocked = dev->blocked();
176    hold->dev_prev_blocked = dev->dev_prev_blocked;
177    hold->no_wait_id = dev->no_wait_id;
178    dev->set_blocked(state);
179    Dmsg1(sd_dbglvl, "steal lock. new=%s\n", dev->print_blocked());
180    dev->no_wait_id = pthread_self();
181    dev->dunlock();
182 }
183
184 /*
185  * Enter with device blocked by us but not locked
186  * Exit with device locked, and blocked by previous owner
187  */
188 void _give_back_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold)
189 {
190    Dmsg3(sd_dbglvl, "return lock. old=%s from %s:%d\n",
191       dev->print_blocked(), file, line);
192    dev->dlock();
193    dev->set_blocked(hold->dev_blocked);
194    dev->dev_prev_blocked = hold->dev_prev_blocked;
195    dev->no_wait_id = hold->no_wait_id;
196    Dmsg1(sd_dbglvl, "return lock. new=%s\n", dev->print_blocked());
197    if (dev->num_waiting > 0) {
198       pthread_cond_broadcast(&dev->wait); /* wake them up */
199    }
200 }
201
202 const char *DEVICE::print_blocked() const 
203 {
204    switch (m_blocked) {
205    case BST_NOT_BLOCKED:
206       return "BST_NOT_BLOCKED";
207    case BST_UNMOUNTED:
208       return "BST_UNMOUNTED";
209    case BST_WAITING_FOR_SYSOP:
210       return "BST_WAITING_FOR_SYSOP";
211    case BST_DOING_ACQUIRE:
212       return "BST_DOING_ACQUIRE";
213    case BST_WRITING_LABEL:
214       return "BST_WRITING_LABEL";
215    case BST_UNMOUNTED_WAITING_FOR_SYSOP:
216       return "BST_UNMOUNTED_WAITING_FOR_SYSOP";
217    case BST_MOUNT:
218       return "BST_MOUNT";
219    default:
220       return _("unknown blocked code");
221    }
222 }
223
224
225 /*
226  * Check if the device is blocked or not
227  */
228 bool is_device_unmounted(DEVICE *dev)
229 {
230    bool stat;
231    int blocked = dev->blocked();
232    stat = (blocked == BST_UNMOUNTED) ||
233           (blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
234    return stat;
235 }
236