~ubuntu-branches/debian/stretch/lvm2/stretch

« back to all changes in this revision

Viewing changes to lib/misc/lvm-flock.c

  • Committer: Package Import Robot
  • Author(s): Bastian Blank
  • Date: 2014-08-19 15:37:06 UTC
  • mfrom: (30.1.11 sid)
  • Revision ID: package-import@ubuntu.com-20140819153706-0p2sc6a53ef7xnvl
Tags: 2.02.109-1
New upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
 
3
 * Copyright (C) 2004-2014 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 "config.h"
 
18
#include "lvm-file.h"
 
19
#include "lvm-flock.h"
 
20
#include "lvm-signal.h"
 
21
#include "locking.h"
 
22
 
 
23
#include <sys/file.h>
 
24
#include <fcntl.h>
 
25
 
 
26
struct lock_list {
 
27
        struct dm_list list;
 
28
        int lf;
 
29
        char *res;
 
30
};
 
31
 
 
32
static struct dm_list _lock_list;
 
33
static int _prioritise_write_locks;
 
34
 
 
35
/* Drop lock known to be shared with another file descriptor. */
 
36
static void _drop_shared_flock(const char *file, int fd)
 
37
{
 
38
        log_debug_locking("_drop_shared_flock %s.", file);
 
39
 
 
40
        if (close(fd) < 0)
 
41
                log_sys_debug("close", file);
 
42
}
 
43
 
 
44
static void _undo_flock(const char *file, int fd)
 
45
{
 
46
        struct stat buf1, buf2;
 
47
 
 
48
        log_debug_locking("_undo_flock %s", file);
 
49
        if (!flock(fd, LOCK_NB | LOCK_EX) &&
 
50
            !stat(file, &buf1) &&
 
51
            !fstat(fd, &buf2) &&
 
52
            is_same_inode(buf1, buf2))
 
53
                if (unlink(file))
 
54
                        log_sys_debug("unlink", file);
 
55
 
 
56
        if (close(fd) < 0)
 
57
                log_sys_debug("close", file);
 
58
}
 
59
 
 
60
static int _release_lock(const char *file, int unlock)
 
61
{
 
62
        struct lock_list *ll;
 
63
        struct dm_list *llh, *llt;
 
64
 
 
65
        dm_list_iterate_safe(llh, llt, &_lock_list) {
 
66
                ll = dm_list_item(llh, struct lock_list);
 
67
 
 
68
                if (!file || !strcmp(ll->res, file)) {
 
69
                        dm_list_del(llh);
 
70
                        if (unlock) {
 
71
                                log_very_verbose("Unlocking %s", ll->res);
 
72
                                if (flock(ll->lf, LOCK_NB | LOCK_UN))
 
73
                                        log_sys_debug("flock", ll->res);
 
74
                                _undo_flock(ll->res, ll->lf);
 
75
                        } else
 
76
                                _drop_shared_flock(ll->res, ll->lf);
 
77
 
 
78
                        dm_free(ll->res);
 
79
                        dm_free(llh);
 
80
 
 
81
                        if (file)
 
82
                                return 1;
 
83
                }
 
84
        }
 
85
 
 
86
        return 0;
 
87
}
 
88
 
 
89
void release_flocks(int unlock)
 
90
{
 
91
        _release_lock(NULL, unlock);
 
92
}
 
93
 
 
94
static int _do_flock(const char *file, int *fd, int operation, uint32_t nonblock)
 
95
{
 
96
        int r = 1;
 
97
        int old_errno;
 
98
        struct stat buf1, buf2;
 
99
 
 
100
        log_debug_locking("_do_flock %s %c%c", file,
 
101
                          operation == LOCK_EX ? 'W' : 'R', nonblock ? ' ' : 'B');
 
102
        do {
 
103
                if ((*fd > -1) && close(*fd))
 
104
                        log_sys_debug("close", file);
 
105
 
 
106
                if ((*fd = open(file, O_CREAT | O_APPEND | O_RDWR, 0777)) < 0) {
 
107
                        log_sys_error("open", file);
 
108
                        return 0;
 
109
                }
 
110
 
 
111
                if (nonblock)
 
112
                        operation |= LOCK_NB;
 
113
                else
 
114
                        sigint_allow();
 
115
 
 
116
                r = flock(*fd, operation);
 
117
                old_errno = errno;
 
118
                if (!nonblock) {
 
119
                        sigint_restore();
 
120
                        if (sigint_caught())
 
121
                                log_error("Giving up waiting for lock.");
 
122
                }
 
123
 
 
124
                if (r) {
 
125
                        errno = old_errno;
 
126
                        log_sys_error("flock", file);
 
127
                        if (close(*fd))
 
128
                                log_sys_debug("close", file);
 
129
                        *fd = -1;
 
130
                        return 0;
 
131
                }
 
132
 
 
133
                if (!stat(file, &buf1) && !fstat(*fd, &buf2) &&
 
134
                    is_same_inode(buf1, buf2))
 
135
                        return 1;
 
136
        } while (!nonblock);
 
137
 
 
138
        return_0;
 
139
}
 
140
 
 
141
#define AUX_LOCK_SUFFIX ":aux"
 
142
 
 
143
static int _do_write_priority_flock(const char *file, int *fd, int operation, uint32_t nonblock)
 
144
{
 
145
        int r, fd_aux = -1;
 
146
        char *file_aux = alloca(strlen(file) + sizeof(AUX_LOCK_SUFFIX));
 
147
 
 
148
        strcpy(file_aux, file);
 
149
        strcat(file_aux, AUX_LOCK_SUFFIX);
 
150
 
 
151
        if ((r = _do_flock(file_aux, &fd_aux, LOCK_EX, 0))) {
 
152
                if (operation == LOCK_EX) {
 
153
                        r = _do_flock(file, fd, operation, nonblock);
 
154
                        _undo_flock(file_aux, fd_aux);
 
155
                } else {
 
156
                        _undo_flock(file_aux, fd_aux);
 
157
                        r = _do_flock(file, fd, operation, nonblock);
 
158
                }
 
159
        }
 
160
 
 
161
        return r;
 
162
}
 
163
 
 
164
int lock_file(const char *file, uint32_t flags)
 
165
{
 
166
        int operation;
 
167
        uint32_t nonblock = flags & LCK_NONBLOCK;
 
168
        int r;
 
169
 
 
170
        struct lock_list *ll;
 
171
        char state;
 
172
 
 
173
        switch (flags & LCK_TYPE_MASK) {
 
174
        case LCK_READ:
 
175
                operation = LOCK_SH;
 
176
                state = 'R';
 
177
                break;
 
178
        case LCK_WRITE:
 
179
                operation = LOCK_EX;
 
180
                state = 'W';
 
181
                break;
 
182
        case LCK_UNLOCK:
 
183
                return _release_lock(file, 1);
 
184
        default:
 
185
                log_error("Unrecognised lock type: %d", flags & LCK_TYPE_MASK);
 
186
                return 0;
 
187
        }
 
188
 
 
189
        if (!(ll = dm_malloc(sizeof(struct lock_list))))
 
190
                return_0;
 
191
 
 
192
        if (!(ll->res = dm_strdup(file))) {
 
193
                dm_free(ll);
 
194
                return_0;
 
195
        }
 
196
 
 
197
        ll->lf = -1;
 
198
 
 
199
        log_very_verbose("Locking %s %c%c", ll->res, state,
 
200
                         nonblock ? ' ' : 'B');
 
201
 
 
202
        (void) dm_prepare_selinux_context(file, S_IFREG);
 
203
        if (_prioritise_write_locks)
 
204
                r = _do_write_priority_flock(file, &ll->lf, operation, nonblock);
 
205
        else 
 
206
                r = _do_flock(file, &ll->lf, operation, nonblock);
 
207
        (void) dm_prepare_selinux_context(NULL, 0);
 
208
 
 
209
        if (r)
 
210
                dm_list_add(&_lock_list, &ll->list);
 
211
        else {
 
212
                dm_free(ll->res);
 
213
                dm_free(ll);
 
214
                stack;
 
215
        }
 
216
 
 
217
        return r;
 
218
}
 
219
 
 
220
void init_flock(struct cmd_context *cmd)
 
221
{
 
222
        dm_list_init(&_lock_list);
 
223
 
 
224
        _prioritise_write_locks =
 
225
            find_config_tree_bool(cmd, global_prioritise_write_locks_CFG, NULL);
 
226
}