Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 : : * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
4 : : *
5 : : * This file is part of LVM2.
6 : : *
7 : : * This copyrighted material is made available to anyone wishing to use,
8 : : * modify, copy, or redistribute it subject to the terms and conditions
9 : : * of the GNU Lesser General Public License v.2.1.
10 : : *
11 : : * You should have received a copy of the GNU Lesser General Public License
12 : : * along with this program; if not, write to the Free Software Foundation,
13 : : * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 : : */
15 : :
16 : : #include "lib.h"
17 : : #include "locking.h"
18 : : #include "locking_types.h"
19 : : #include "activate.h"
20 : : #include "config.h"
21 : : #include "defaults.h"
22 : : #include "lvm-file.h"
23 : : #include "lvm-string.h"
24 : : #include "lvmcache.h"
25 : :
26 : : #include <limits.h>
27 : : #include <unistd.h>
28 : : #include <sys/stat.h>
29 : : #include <sys/file.h>
30 : : #include <fcntl.h>
31 : : #include <signal.h>
32 : :
33 : : struct lock_list {
34 : : struct dm_list list;
35 : : int lf;
36 : : char *res;
37 : : };
38 : :
39 : : static struct dm_list _lock_list;
40 : : static char _lock_dir[NAME_LEN];
41 : : static int _prioritise_write_locks;
42 : :
43 : : static sig_t _oldhandler;
44 : : static sigset_t _fullsigset, _intsigset;
45 : : static volatile sig_atomic_t _handler_installed;
46 : :
47 : 2 : static void _undo_flock(const char *file, int fd)
48 : : {
49 : : struct stat buf1, buf2;
50 : :
51 : 2 : log_debug("_undo_flock %s", file);
52 [ + - + - + : 6 : if (!flock(fd, LOCK_NB | LOCK_EX) &&
- + - ]
[ + - ]
53 : 2 : !stat(file, &buf1) &&
54 : 2 : !fstat(fd, &buf2) &&
55 : 4 : is_same_inode(buf1, buf2))
56 [ - + ]: 2 : if (unlink(file))
57 : 0 : log_sys_error("unlink", file);
58 : :
59 [ - + ]: 2 : if (close(fd) < 0)
60 : 0 : log_sys_error("close", file);
61 : 2 : }
62 : :
63 : 2 : static int _release_lock(const char *file, int unlock)
64 : : {
65 : : struct lock_list *ll;
66 : : struct dm_list *llh, *llt;
67 : :
68 [ + + ]: 2 : dm_list_iterate_safe(llh, llt, &_lock_list) {
69 : 1 : ll = dm_list_item(llh, struct lock_list);
70 : :
71 [ + - ][ + - ]: 1 : if (!file || !strcmp(ll->res, file)) {
72 : 1 : dm_list_del(llh);
73 [ + - ]: 1 : if (unlock) {
74 : 1 : log_very_verbose("Unlocking %s", ll->res);
75 [ - + ]: 1 : if (flock(ll->lf, LOCK_NB | LOCK_UN))
76 : 0 : log_sys_error("flock", ll->res);
77 : : }
78 : :
79 : 1 : _undo_flock(ll->res, ll->lf);
80 : :
81 : 1 : dm_free(ll->res);
82 : 1 : dm_free(llh);
83 : :
84 [ + - ]: 1 : if (file)
85 : 1 : return 1;
86 : : }
87 : : }
88 : :
89 : 2 : return 0;
90 : : }
91 : :
92 : 1 : static void _fin_file_locking(void)
93 : : {
94 : 1 : _release_lock(NULL, 1);
95 : 1 : }
96 : :
97 : 0 : static void _reset_file_locking(void)
98 : : {
99 : 0 : _release_lock(NULL, 0);
100 : 0 : }
101 : :
102 : 2 : static void _remove_ctrl_c_handler(void)
103 : : {
104 : 2 : siginterrupt(SIGINT, 0);
105 [ - + ]: 2 : if (!_handler_installed)
106 : 0 : return;
107 : :
108 : 2 : _handler_installed = 0;
109 : :
110 : 2 : sigprocmask(SIG_SETMASK, &_fullsigset, NULL);
111 [ - + ]: 2 : if (signal(SIGINT, _oldhandler) == SIG_ERR)
112 : 2 : log_sys_error("signal", "_remove_ctrl_c_handler");
113 : : }
114 : :
115 : 0 : static void _trap_ctrl_c(int sig __attribute((unused)))
116 : : {
117 : 0 : _remove_ctrl_c_handler();
118 : 0 : log_error("CTRL-c detected: giving up waiting for lock");
119 : 0 : }
120 : :
121 : 2 : static void _install_ctrl_c_handler()
122 : : {
123 : 2 : _handler_installed = 1;
124 : :
125 [ - + ]: 2 : if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR) {
126 : 0 : _handler_installed = 0;
127 : 0 : return;
128 : : }
129 : :
130 : 2 : sigprocmask(SIG_SETMASK, &_intsigset, NULL);
131 : 2 : siginterrupt(SIGINT, 1);
132 : : }
133 : :
134 : 2 : static int _do_flock(const char *file, int *fd, int operation, uint32_t nonblock)
135 : : {
136 : 2 : int r = 1;
137 : : int old_errno;
138 : : struct stat buf1, buf2;
139 : :
140 [ - + ][ + + ]: 2 : log_debug("_do_flock %s %c%c",
141 : : file, operation == LOCK_EX ? 'W' : 'R', nonblock ? ' ' : 'B');
142 : : do {
143 [ - + ][ # # ]: 2 : if ((*fd > -1) && close(*fd))
144 : 0 : log_sys_error("close", file);
145 : :
146 [ - + ]: 2 : if ((*fd = open(file, O_CREAT | O_APPEND | O_RDWR, 0777)) < 0) {
147 : 0 : log_sys_error("open", file);
148 : 0 : return 0;
149 : : }
150 : :
151 [ - + ]: 2 : if (nonblock)
152 : 0 : operation |= LOCK_NB;
153 : : else
154 : 2 : _install_ctrl_c_handler();
155 : :
156 : 2 : r = flock(*fd, operation);
157 : 2 : old_errno = errno;
158 [ + - ]: 2 : if (!nonblock)
159 : 2 : _remove_ctrl_c_handler();
160 : :
161 [ - + ]: 2 : if (r) {
162 : 0 : errno = old_errno;
163 : 0 : log_sys_error("flock", file);
164 : 0 : close(*fd);
165 : 0 : return 0;
166 : : }
167 : :
168 [ + - ][ + - ]: 2 : if (!stat(file, &buf1) && !fstat(*fd, &buf2) &&
[ + - ][ + - ]
169 : 4 : is_same_inode(buf1, buf2))
170 : 2 : return 1;
171 [ # # ]: 0 : } while (!nonblock);
172 : :
173 : 2 : return_0;
174 : : }
175 : :
176 : : #define AUX_LOCK_SUFFIX ":aux"
177 : :
178 : 1 : static int _do_write_priority_flock(const char *file, int *fd, int operation, uint32_t nonblock)
179 : : {
180 : 1 : int r, fd_aux = -1;
181 : 1 : char *file_aux = alloca(strlen(file) + sizeof(AUX_LOCK_SUFFIX));
182 : :
183 : 1 : strcpy(file_aux, file);
184 : 1 : strcat(file_aux, AUX_LOCK_SUFFIX);
185 : :
186 [ + - ]: 1 : if ((r = _do_flock(file_aux, &fd_aux, LOCK_EX, 0))) {
187 [ - + ]: 1 : if (operation == LOCK_EX) {
188 : 0 : r = _do_flock(file, fd, operation, nonblock);
189 : 0 : _undo_flock(file_aux, fd_aux);
190 : : } else {
191 : 1 : _undo_flock(file_aux, fd_aux);
192 : 1 : r = _do_flock(file, fd, operation, nonblock);
193 : : }
194 : : }
195 : :
196 : 1 : return r;
197 : : }
198 : :
199 : 2 : static int _lock_file(const char *file, uint32_t flags)
200 : : {
201 : : int operation;
202 : 2 : uint32_t nonblock = flags & LCK_NONBLOCK;
203 : : int r;
204 : :
205 : : struct lock_list *ll;
206 : : char state;
207 : :
208 [ + - + - ]: 2 : switch (flags & LCK_TYPE_MASK) {
209 : : case LCK_READ:
210 : 1 : operation = LOCK_SH;
211 : 1 : state = 'R';
212 : 1 : break;
213 : : case LCK_WRITE:
214 : 0 : operation = LOCK_EX;
215 : 0 : state = 'W';
216 : 0 : break;
217 : : case LCK_UNLOCK:
218 : 1 : return _release_lock(file, 1);
219 : : default:
220 : 0 : log_error("Unrecognised lock type: %d", flags & LCK_TYPE_MASK);
221 : 0 : return 0;
222 : : }
223 : :
224 [ - + ]: 1 : if (!(ll = dm_malloc(sizeof(struct lock_list))))
225 : 0 : return_0;
226 : :
227 [ - + ]: 1 : if (!(ll->res = dm_strdup(file))) {
228 : 0 : dm_free(ll);
229 : 0 : return_0;
230 : : }
231 : :
232 : 1 : ll->lf = -1;
233 : :
234 [ - + ]: 1 : log_very_verbose("Locking %s %c%c", ll->res, state,
235 : : nonblock ? ' ' : 'B');
236 : :
237 [ + - ]: 1 : if (_prioritise_write_locks)
238 : 1 : r = _do_write_priority_flock(file, &ll->lf, operation, nonblock);
239 : : else
240 : 0 : r = _do_flock(file, &ll->lf, operation, nonblock);
241 : :
242 [ + - ]: 1 : if (r)
243 : 1 : dm_list_add(&_lock_list, &ll->list);
244 : : else {
245 : 0 : dm_free(ll->res);
246 : 0 : dm_free(ll);
247 : 0 : stack;
248 : : }
249 : :
250 : 2 : return r;
251 : : }
252 : :
253 : 2 : static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
254 : : uint32_t flags)
255 : : {
256 : : char lockfile[PATH_MAX];
257 : :
258 [ + - - ]: 2 : switch (flags & LCK_SCOPE_MASK) {
259 : : case LCK_VG:
260 : : /* Skip cache refresh for VG_GLOBAL - the caller handles it */
261 [ - + ]: 2 : if (strcmp(resource, VG_GLOBAL))
262 : 0 : lvmcache_drop_metadata(resource, 0);
263 : :
264 : : /* LCK_CACHE does not require a real lock */
265 [ - + ]: 2 : if (flags & LCK_CACHE)
266 : 0 : break;
267 : :
268 [ + - ]: 2 : if (*resource == '#')
269 : 2 : dm_snprintf(lockfile, sizeof(lockfile),
270 : : "%s/P_%s", _lock_dir, resource + 1);
271 : : else
272 : 0 : dm_snprintf(lockfile, sizeof(lockfile),
273 : : "%s/V_%s", _lock_dir, resource);
274 : :
275 [ - + ]: 2 : if (!_lock_file(lockfile, flags))
276 : 0 : return_0;
277 : 2 : break;
278 : : case LCK_LV:
279 [ # # # # # : 0 : switch (flags & LCK_TYPE_MASK) {
# # ]
280 : : case LCK_UNLOCK:
281 : 0 : log_very_verbose("Unlocking LV %s", resource);
282 [ # # ]: 0 : if (!lv_resume_if_active(cmd, resource))
283 : 0 : return 0;
284 : 0 : break;
285 : : case LCK_NULL:
286 : 0 : log_very_verbose("Locking LV %s (NL)", resource);
287 [ # # ]: 0 : if (!lv_deactivate(cmd, resource))
288 : 0 : return 0;
289 : 0 : break;
290 : : case LCK_READ:
291 : 0 : log_very_verbose("Locking LV %s (R)", resource);
292 [ # # ]: 0 : if (!lv_activate_with_filter(cmd, resource, 0))
293 : 0 : return 0;
294 : 0 : break;
295 : : case LCK_PREAD:
296 : 0 : log_very_verbose("Locking LV %s (PR) - ignored", resource);
297 : 0 : break;
298 : : case LCK_WRITE:
299 : 0 : log_very_verbose("Locking LV %s (W)", resource);
300 [ # # ]: 0 : if (!lv_suspend_if_active(cmd, resource))
301 : 0 : return 0;
302 : 0 : break;
303 : : case LCK_EXCL:
304 : 0 : log_very_verbose("Locking LV %s (EX)", resource);
305 [ # # ]: 0 : if (!lv_activate_with_filter(cmd, resource, 1))
306 : 0 : return 0;
307 : : break;
308 : : default:
309 : : break;
310 : : }
311 : 0 : break;
312 : : default:
313 : 0 : log_error("Unrecognised lock scope: %d",
314 : : flags & LCK_SCOPE_MASK);
315 : 0 : return 0;
316 : : }
317 : :
318 : 2 : return 1;
319 : : }
320 : :
321 : 1 : int init_file_locking(struct locking_type *locking, struct cmd_context *cmd)
322 : : {
323 : 1 : locking->lock_resource = _file_lock_resource;
324 : 1 : locking->reset_locking = _reset_file_locking;
325 : 1 : locking->fin_locking = _fin_file_locking;
326 : 1 : locking->flags = 0;
327 : :
328 : : /* Get lockfile directory from config file */
329 : 1 : strncpy(_lock_dir, find_config_tree_str(cmd, "global/locking_dir",
330 : : DEFAULT_LOCK_DIR),
331 : : sizeof(_lock_dir));
332 : :
333 : 1 : _prioritise_write_locks =
334 : 1 : find_config_tree_bool(cmd, "global/prioritise_write_locks",
335 : : DEFAULT_PRIORITISE_WRITE_LOCKS);
336 : :
337 [ - + ]: 1 : if (!dm_create_dir(_lock_dir))
338 : 0 : return 0;
339 : :
340 : : /* Trap a read-only file system */
341 [ - + ][ # # ]: 1 : if ((access(_lock_dir, R_OK | W_OK | X_OK) == -1) && (errno == EROFS))
342 : 0 : return 0;
343 : :
344 : 1 : dm_list_init(&_lock_list);
345 : :
346 [ + - - + ]: 1 : if (sigfillset(&_intsigset) || sigfillset(&_fullsigset)) {
347 : 0 : log_sys_error("sigfillset", "init_file_locking");
348 : 0 : return 0;
349 : : }
350 : :
351 [ - + ]: 1 : if (sigdelset(&_intsigset, SIGINT)) {
352 : 0 : log_sys_error("sigdelset", "init_file_locking");
353 : 0 : return 0;
354 : : }
355 : :
356 : 1 : return 1;
357 : : }
|