2
* Copyright (C) 2009 Karel Zak <kzak@redhat.com>
4
* This file may be redistributed under the terms of the
5
* GNU Lesser General Public License.
11
* @short_description: locking methods for /etc/mtab or another libmount files
13
* The mtab lock is backwardly compatible with the standard linux /etc/mtab
14
* locking. Note, it's necessary to use the same locking schema in all
15
* application that access the file.
24
#include "pathnames.h"
31
char *lockfile; /* path to lock file (e.g. /etc/mtab~) */
32
char *linkfile; /* path to link file (e.g. /etc/mtab~.<id>) */
33
int lockfile_fd; /* lock file descriptor */
35
unsigned int locked :1, /* do we own the lock? */
36
sigblock :1, /* block signals when locked */
37
simplelock :1; /* use flock rather than normal mtab lock */
45
* @datafile: the file that should be covered by the lock
46
* @id: unique linkfile identifier or 0 (default is getpid())
48
* Returns: newly allocated lock handler or NULL on case of error.
50
struct libmnt_lock *mnt_new_lock(const char *datafile, pid_t id)
52
struct libmnt_lock *ml = NULL;
53
char *lo = NULL, *ln = NULL;
59
/* for flock we use "foo.lock, for mtab "foo~"
61
losz = strlen(datafile) + sizeof(".lock");
66
/* default is mtab~ lock */
67
snprintf(lo, losz, "%s~", datafile);
69
if (asprintf(&ln, "%s~.%d", datafile, id ? : getpid()) == -1) {
73
ml = calloc(1, sizeof(*ml) );
81
DBG(LOCKS, mnt_debug_h(ml, "alloc: default linkfile=%s, lockfile=%s", ln, lo));
93
* @ml: struct libmnt_lock handler
95
* Deallocates mnt_lock.
97
void mnt_free_lock(struct libmnt_lock *ml)
101
DBG(LOCKS, mnt_debug_h(ml, "free%s", ml->locked ? " !!! LOCKED !!!" : ""));
108
* mnt_lock_block_signals:
109
* @ml: struct libmnt_lock handler
110
* @enable: TRUE/FALSE
112
* Block/unblock signals when the lock is locked, the signals are not blocked
115
* Returns: <0 on error, 0 on success.
117
int mnt_lock_block_signals(struct libmnt_lock *ml, int enable)
121
DBG(LOCKS, mnt_debug_h(ml, "signals: %s", enable ? "BLOCKED" : "UNBLOCKED"));
122
ml->sigblock = enable ? 1 : 0;
126
/* don't export this to API
128
int mnt_lock_use_simplelock(struct libmnt_lock *ml, int enable)
135
assert(ml->lockfile);
137
DBG(LOCKS, mnt_debug_h(ml, "flock: %s", enable ? "ENABLED" : "DISABLED"));
138
ml->simplelock = enable ? 1 : 0;
140
sz = strlen(ml->lockfile);
144
* flock: "<name>.lock"
145
* mtab lock: "<name>~"
147
if (ml->simplelock && endswith(ml->lockfile, "~"))
148
memcpy(ml->lockfile + sz - 1, ".lock", 6);
150
else if (!ml->simplelock && endswith(ml->lockfile, ".lock"))
151
memcpy(ml->lockfile + sz - 5, "~", 2);
153
DBG(LOCKS, mnt_debug_h(ml, "new lock filename: '%s'", ml->lockfile));
158
* Returns path to lockfile.
160
static const char *mnt_lock_get_lockfile(struct libmnt_lock *ml)
162
return ml ? ml->lockfile : NULL;
166
* Note that the filename is generated by mnt_new_lock() and depends on
167
* getpid() or 'id' argument of the mnt_new_lock() function.
169
* Returns: unique (per process/thread) path to linkfile.
171
static const char *mnt_lock_get_linkfile(struct libmnt_lock *ml)
173
return ml ? ml->linkfile : NULL;
179
static void unlock_simplelock(struct libmnt_lock *ml)
182
assert(ml->simplelock);
184
if (ml->lockfile_fd >= 0) {
185
DBG(LOCKS, mnt_debug_h(ml, "%s: unflocking",
186
mnt_lock_get_lockfile(ml)));
187
close(ml->lockfile_fd);
191
static int lock_simplelock(struct libmnt_lock *ml)
197
assert(ml->simplelock);
199
lfile = mnt_lock_get_lockfile(ml);
201
DBG(LOCKS, mnt_debug_h(ml, "%s: locking", lfile));
205
sigemptyset(&ml->oldsigmask);
207
sigprocmask(SIG_BLOCK, &sigs, &ml->oldsigmask);
210
ml->lockfile_fd = open(lfile, O_RDONLY|O_CREAT|O_CLOEXEC,
211
S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH);
212
if (ml->lockfile_fd < 0) {
217
while (flock(ml->lockfile_fd, LOCK_EX) < 0) {
219
if ((errno == EAGAIN) || (errno == EINTR))
222
close(ml->lockfile_fd);
223
ml->lockfile_fd = -1;
231
sigprocmask(SIG_SETMASK, &ml->oldsigmask, NULL);
236
* traditional mtab locking
239
static void mnt_lockalrm_handler(int sig __attribute__((__unused__)))
241
/* do nothing, say nothing, be nothing */
245
* Waits for F_SETLKW, unfortunately we have to use SIGALRM here to interrupt
246
* fcntl() to avoid never ending waiting.
248
* Returns: 0 on success, 1 on timeout, -errno on error.
250
static int mnt_wait_mtab_lock(struct libmnt_lock *ml, struct flock *fl, time_t maxtime)
253
struct sigaction sa, osa;
256
gettimeofday(&now, NULL);
258
if (now.tv_sec >= maxtime)
259
return 1; /* timeout */
261
/* setup ALARM handler -- we don't want to wait forever */
263
sa.sa_handler = mnt_lockalrm_handler;
264
sigfillset (&sa.sa_mask);
266
sigaction(SIGALRM, &sa, &osa);
268
DBG(LOCKS, mnt_debug_h(ml, "(%d) waiting for F_SETLKW", getpid()));
270
alarm(maxtime - now.tv_sec);
271
if (fcntl(ml->lockfile_fd, F_SETLKW, fl) == -1)
272
ret = errno == EINTR ? 1 : -errno;
275
/* restore old sigaction */
276
sigaction(SIGALRM, &osa, NULL);
278
DBG(LOCKS, mnt_debug_h(ml, "(%d) leaving mnt_wait_setlkw(), rc=%d",
284
* Create the mtab lock file.
286
* The old code here used flock on a lock file /etc/mtab~ and deleted
287
* this lock file afterwards. However, as rgooch remarks, that has a
288
* race: a second mount may be waiting on the lock and proceed as
289
* soon as the lock file is deleted by the first mount, and immediately
290
* afterwards a third mount comes, creates a new /etc/mtab~, applies
291
* flock to that, and also proceeds, so that the second and third mount
292
* now both are scribbling in /etc/mtab.
294
* The new code uses a link() instead of a creat(), where we proceed
295
* only if it was us that created the lock, and hence we always have
296
* to delete the lock afterwards. Now the use of flock() is in principle
297
* superfluous, but avoids an arbitrary sleep().
299
* Where does the link point to? Obvious choices are mtab and mtab~~.
300
* HJLu points out that the latter leads to races. Right now we use
301
* mtab~.<pid> instead.
304
* The original mount locking code has used sleep(1) between attempts and
305
* maximal number of attempts has been 5.
307
* There was very small number of attempts and extremely long waiting (1s)
308
* that is useless on machines with large number of mount processes.
310
* Now we wait few thousand microseconds between attempts and we have a global
311
* time limit (30s) rather than limit for number of attempts. The advantage
312
* is that this method also counts time which we spend in fcntl(F_SETLKW) and
313
* number of attempts is not restricted.
314
* -- kzak@redhat.com [Mar-2007]
317
* This mtab locking code has been refactored and moved to libmount. The mtab
318
* locking is really not perfect (e.g. SIGALRM), but it's stable, reliable and
319
* backwardly compatible code.
321
* Don't forget that this code has to be compatible with 3rd party mounts
322
* (/sbin/mount.<foo>) and has to work with NFS.
323
* -- kzak@redhat.com [May-2009]
326
/* maximum seconds between first and last attempt */
327
#define MOUNTLOCK_MAXTIME 30
329
/* sleep time (in microseconds, max=999999) between attempts */
330
#define MOUNTLOCK_WAITTIME 5000
332
static void unlock_mtab(struct libmnt_lock *ml)
337
if (!ml->locked && ml->lockfile && ml->linkfile)
339
/* We have (probably) all files, but we don't own the lock,
340
* Really? Check it! Maybe ml->locked wasn't set properly
341
* because code was interrupted by signal. Paranoia? Yes.
343
* We own the lock when linkfile == lockfile.
347
if (!stat(ml->lockfile, &lo) && !stat(ml->linkfile, &li) &&
348
lo.st_dev == li.st_dev && lo.st_ino == li.st_ino)
353
unlink(ml->linkfile);
354
if (ml->lockfile_fd >= 0)
355
close(ml->lockfile_fd);
356
if (ml->locked && ml->lockfile) {
357
unlink(ml->lockfile);
358
DBG(LOCKS, mnt_debug_h(ml, "unlink %s", ml->lockfile));
362
static int lock_mtab(struct libmnt_lock *ml)
365
struct timespec waittime;
366
struct timeval maxtime;
367
const char *lockfile, *linkfile;
374
lockfile = mnt_lock_get_lockfile(ml);
377
linkfile = mnt_lock_get_linkfile(ml);
383
* Block all signals when locked, mnt_unlock_file() will
384
* restore the old mask.
388
sigemptyset(&ml->oldsigmask);
390
sigdelset(&sigs, SIGTRAP);
391
sigdelset(&sigs, SIGALRM);
392
sigprocmask(SIG_BLOCK, &sigs, &ml->oldsigmask);
395
i = open(linkfile, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
397
/* linkfile does not exist (as a file) and we cannot create it.
398
* Read-only or full filesystem? Too many files open in the system?
406
gettimeofday(&maxtime, NULL);
407
maxtime.tv_sec += MOUNTLOCK_MAXTIME;
410
waittime.tv_nsec = (1000 * MOUNTLOCK_WAITTIME);
412
/* Repeat until it was us who made the link */
413
while (!ml->locked) {
418
j = link(linkfile, lockfile);
422
if (j < 0 && errno != EEXIST) {
427
ml->lockfile_fd = open(lockfile, O_WRONLY);
429
if (ml->lockfile_fd < 0) {
430
/* Strange... Maybe the file was just deleted? */
432
gettimeofday(&now, NULL);
433
if (errsv == ENOENT && now.tv_sec < maxtime.tv_sec) {
442
flock.l_type = F_WRLCK;
443
flock.l_whence = SEEK_SET;
448
/* We made the link. Now claim the lock. */
449
if (fcntl (ml->lockfile_fd, F_SETLK, &flock) == -1) {
450
DBG(LOCKS, mnt_debug_h(ml,
451
"%s: can't F_SETLK lockfile, errno=%d\n",
453
/* proceed, since it was us who created the lockfile anyway */
457
/* Someone else made the link. Wait. */
458
int err = mnt_wait_mtab_lock(ml, &flock, maxtime.tv_sec);
461
DBG(LOCKS, mnt_debug_h(ml,
462
"%s: can't create link: time out (perhaps "
463
"there is a stale lock file?)", lockfile));
467
} else if (err < 0) {
471
nanosleep(&waittime, NULL);
472
close(ml->lockfile_fd);
473
ml->lockfile_fd = -1;
476
DBG(LOCKS, mnt_debug_h(ml, "%s: (%d) successfully locked",
477
lockfile, getpid()));
489
* @ml: pointer to struct libmnt_lock instance
491
* Creates lock file (e.g. /etc/mtab~). Note that this function may
494
* Your application has to always call mnt_unlock_file() before exit.
496
* Traditional mtab locking scheme:
498
* 1. create linkfile (e.g. /etc/mtab~.$PID)
499
* 2. link linkfile --> lockfile (e.g. /etc/mtab~.$PID --> /etc/mtab~)
500
* 3. a) link() success: setups F_SETLK lock (see fcnlt(2))
501
* b) link() failed: wait (max 30s) on F_SETLKW lock, goto 2.
503
* Returns: 0 on success or negative number in case of error (-ETIMEOUT is case
504
* of stale lock file).
506
int mnt_lock_file(struct libmnt_lock *ml)
512
return lock_simplelock(ml);
514
return lock_mtab(ml);
521
* Unlocks the file. The function could be called independently on the
522
* lock status (for example from exit(3)).
524
void mnt_unlock_file(struct libmnt_lock *ml)
529
DBG(LOCKS, mnt_debug_h(ml, "(%d) %s", getpid(),
530
ml->locked ? "unlocking" : "cleaning"));
533
unlock_simplelock(ml);
538
ml->lockfile_fd = -1;
541
DBG(LOCKS, mnt_debug_h(ml, "restoring sigmask"));
542
sigprocmask(SIG_SETMASK, &ml->oldsigmask, NULL);
548
struct libmnt_lock *lock;
551
* read number from @filename, increment the number and
552
* write the number back to the file
554
void increment_data(const char *filename, int verbose, int loopno)
560
if (!(f = fopen(filename, "r")))
561
err(EXIT_FAILURE, "%d: failed to open: %s", getpid(), filename);
563
if (!fgets(buf, sizeof(buf), f))
564
err(EXIT_FAILURE, "%d failed read: %s", getpid(), filename);
569
if (!(f = fopen(filename, "w")))
570
err(EXIT_FAILURE, "%d: failed to open: %s", getpid(), filename);
572
fprintf(f, "%ld", num);
576
fprintf(stderr, "%d: %s: %ld --> %ld (loop=%d)\n", getpid(),
577
filename, num - 1, num, loopno);
580
void clean_lock(void)
584
mnt_unlock_file(lock);
588
void sig_handler(int sig)
590
errx(EXIT_FAILURE, "\n%d: catch signal: %s\n", getpid(), strsignal(sig));
593
int test_lock(struct libmnt_test *ts, int argc, char *argv[])
598
const char *datafile = NULL;
599
int verbose = 0, loops = 0, l, idx = 1;
604
if (strcmp(argv[idx], "--synctime") == 0) {
605
synctime = (time_t) atol(argv[idx + 1]);
608
if (idx < argc && strcmp(argv[idx], "--verbose") == 0) {
614
datafile = argv[idx++];
616
loops = atoi(argv[idx++]);
618
if (!datafile || !loops)
622
fprintf(stderr, "%d: start: synctime=%u, datafile=%s, loops=%d\n",
623
getpid(), (int) synctime, datafile, loops);
627
/* be paranoid and call exit() (=clean_lock()) for all signals */
632
sa.sa_handler = sig_handler;
634
sigfillset(&sa.sa_mask);
636
while (sigismember(&sa.sa_mask, ++sig) != -1 && sig != SIGCHLD)
637
sigaction (sig, &sa, (struct sigaction *) 0);
640
/* start the test in exactly defined time */
642
gettimeofday(&tv, NULL);
643
if (synctime && synctime - tv.tv_sec > 1) {
644
usecs = ((synctime - tv.tv_sec) * 1000000UL) -
645
(1000000UL - tv.tv_usec);
650
for (l = 0; l < loops; l++) {
651
lock = mnt_new_lock(datafile, 0);
655
if (mnt_lock_file(lock) != 0) {
656
fprintf(stderr, "%d: failed to lock %s file\n",
661
increment_data(datafile, verbose, l);
663
mnt_unlock_file(lock);
667
/* The mount command usually finish after mtab update. We
668
* simulate this via short sleep -- it's also enough to make
669
* concurrent processes happy.
679
* Note that this test should be executed from a script that creates many
680
* parallel processes, otherwise this test does not make sense.
682
int main(int argc, char *argv[])
684
struct libmnt_test tss[] = {
685
{ "--lock", test_lock, " [--synctime <time_t>] [--verbose] <datafile> <loops> "
686
"increment a number in datafile" },
690
return mnt_run_test(tss, argc, argv);
693
#endif /* TEST_PROGRAM */