]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: remove mtab locking
authorKarel Zak <kzak@redhat.com>
Fri, 17 Jun 2022 16:04:06 +0000 (18:04 +0200)
committerKarel Zak <kzak@redhat.com>
Fri, 17 Jun 2022 16:04:06 +0000 (18:04 +0200)
Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/src/lock.c
libmount/src/mountP.h
libmount/src/tab_update.c

index f730af18c76fc5039f0c513c33565759c9c4d1db..48354064720933782a399de1ea742bc83419e47c 100644 (file)
 /**
  * SECTION: lock
  * @title: Locking
- * @short_description: locking methods for /etc/mtab or another libmount files
+ * @short_description: locking methods for utab or another libmount files
+ *
+ * Since v2.39 libmount does nto support classic mtab locking. Now all is based
+ * on flock only.
  *
- * The mtab lock is backwards compatible with the standard linux /etc/mtab
- * locking.  Note, it's necessary to use the same locking schema in all
- * applications that access the file.
  */
 #include <sys/time.h>
 #include <time.h>
  */
 struct libmnt_lock {
        char    *lockfile;      /* path to lock file (e.g. /etc/mtab~) */
-       char    *linkfile;      /* path to link file (e.g. /etc/mtab~.<id>) */
        int     lockfile_fd;    /* lock file descriptor */
 
        unsigned int    locked :1,      /* do we own the lock? */
-                       sigblock :1,    /* block signals when locked */
-                       simplelock :1;  /* use flock rather than normal mtab lock */
+                       sigblock :1;    /* block signals when locked */
 
        sigset_t oldsigmask;
 };
@@ -51,46 +49,37 @@ struct libmnt_lock {
 /**
  * mnt_new_lock:
  * @datafile: the file that should be covered by the lock
- * @id: unique linkfile identifier or 0 (default is getpid())
+ * @id: ignored by library
  *
  * Returns: newly allocated lock handler or NULL on case of error.
  */
-struct libmnt_lock *mnt_new_lock(const char *datafile, pid_t id)
+struct libmnt_lock *mnt_new_lock(const char *datafile, pid_t id __attribute__((__unused__)))
 {
        struct libmnt_lock *ml = NULL;
-       char *lo = NULL, *ln = NULL;
+       char *lo = NULL;
        size_t losz;
 
        if (!datafile)
                return NULL;
 
-       /* for flock we use "foo.lock, for mtab "foo~"
-        */
        losz = strlen(datafile) + sizeof(".lock");
        lo = malloc(losz);
        if (!lo)
                goto err;
 
-       /* default is mtab~ lock */
-       snprintf(lo, losz, "%s~", datafile);
+       snprintf(lo, losz, "%s.lock", datafile);
 
-       if (asprintf(&ln, "%s~.%d", datafile, id ? : getpid()) == -1) {
-               ln = NULL;
-               goto err;
-       }
        ml = calloc(1, sizeof(*ml) );
        if (!ml)
                goto err;
 
        ml->lockfile_fd = -1;
-       ml->linkfile = ln;
        ml->lockfile = lo;
 
-       DBG(LOCKS, ul_debugobj(ml, "alloc: default linkfile=%s, lockfile=%s", ln, lo));
+       DBG(LOCKS, ul_debugobj(ml, "alloc: lockfile=%s", lo));
        return ml;
 err:
        free(lo);
-       free(ln);
        free(ml);
        return NULL;
 }
@@ -108,7 +97,6 @@ void mnt_free_lock(struct libmnt_lock *ml)
                return;
        DBG(LOCKS, ul_debugobj(ml, "free%s", ml->locked ? " !!! LOCKED !!!" : ""));
        free(ml->lockfile);
-       free(ml->linkfile);
        free(ml);
 }
 
@@ -131,38 +119,6 @@ int mnt_lock_block_signals(struct libmnt_lock *ml, int enable)
        return 0;
 }
 
-/* don't export this to API
- */
-int mnt_lock_use_simplelock(struct libmnt_lock *ml, int enable)
-{
-       size_t sz;
-
-       if (!ml)
-               return -EINVAL;
-
-       assert(ml->lockfile);
-
-       DBG(LOCKS, ul_debugobj(ml, "flock: %s", enable ? "ENABLED" : "DISABLED"));
-       ml->simplelock = enable ? 1 : 0;
-
-       sz = strlen(ml->lockfile);
-       assert(sz);
-
-       /* Change lock name:
-        *
-        *      flock:     "<name>.lock"
-        *      mtab lock: "<name>~"
-        */
-       if (ml->simplelock && endswith(ml->lockfile, "~"))
-               memcpy(ml->lockfile + sz - 1, ".lock", 6);
-
-       else if (!ml->simplelock && endswith(ml->lockfile, ".lock"))
-                memcpy(ml->lockfile + sz - 5, "~", 2);
-
-       DBG(LOCKS, ul_debugobj(ml, "new lock filename: '%s'", ml->lockfile));
-       return 0;
-}
-
 /*
  * Returns path to lockfile.
  */
@@ -171,24 +127,12 @@ static const char *mnt_lock_get_lockfile(struct libmnt_lock *ml)
        return ml ? ml->lockfile : NULL;
 }
 
-/*
- * Note that the filename is generated by mnt_new_lock() and depends on
- * getpid() or 'id' argument of the mnt_new_lock() function.
- *
- * Returns: unique (per process/thread) path to linkfile.
- */
-static const char *mnt_lock_get_linkfile(struct libmnt_lock *ml)
-{
-       return ml ? ml->linkfile : NULL;
-}
-
 /*
  * Simple flocking
  */
 static void unlock_simplelock(struct libmnt_lock *ml)
 {
        assert(ml);
-       assert(ml->simplelock);
 
        if (ml->lockfile_fd >= 0) {
                DBG(LOCKS, ul_debugobj(ml, "%s: unflocking",
@@ -205,7 +149,6 @@ static int lock_simplelock(struct libmnt_lock *ml)
        const mode_t lock_mask = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
 
        assert(ml);
-       assert(ml->simplelock);
 
        lfile = mnt_lock_get_lockfile(ml);
 
@@ -257,281 +200,14 @@ err:
        return rc;
 }
 
-/*
- * traditional mtab locking
- */
-
-static void mnt_lockalrm_handler(int sig __attribute__((__unused__)))
-{
-       /* do nothing, say nothing, be nothing */
-}
-
-/*
- * Waits for F_SETLKW, unfortunately we have to use SIGALRM here to interrupt
- * fcntl() to avoid neverending waiting.
- *
- * Returns: 0 on success, 1 on timeout, -errno on error.
- */
-static int mnt_wait_mtab_lock(struct libmnt_lock *ml, struct flock *fl, time_t maxtime)
-{
-       struct timeval now = { 0 };
-       struct sigaction sa, osa;
-       int ret = 0;
-
-       gettime_monotonic(&now);
-       DBG(LOCKS, ul_debugobj(ml, "(%d) waiting for F_SETLKW (now=%lu, maxtime=%lu, diff=%lu)",
-                               getpid(),
-                               (unsigned long) now.tv_sec,
-                               (unsigned long) maxtime,
-                               (unsigned long) (maxtime - now.tv_sec)));
-
-       if (now.tv_sec >= maxtime)
-               return 1;               /* timeout */
-
-       /* setup ALARM handler -- we don't want to wait forever */
-       sa.sa_flags = 0;
-       sa.sa_handler = mnt_lockalrm_handler;
-       sigfillset (&sa.sa_mask);
-
-       sigaction(SIGALRM, &sa, &osa);
-
-
-       alarm(maxtime - now.tv_sec);
-       if (fcntl(ml->lockfile_fd, F_SETLKW, fl) == -1)
-               ret = errno == EINTR ? 1 : -errno;
-       alarm(0);
-
-       /* restore old sigaction */
-       sigaction(SIGALRM, &osa, NULL);
-
-       DBG(LOCKS, ul_debugobj(ml, "(%d) leaving mnt_wait_setlkw(), rc=%d",
-                               getpid(), ret));
-       return ret;
-}
-
-/*
- * Create the mtab lock file.
- *
- * The old code here used flock on a lock file /etc/mtab~ and deleted
- * this lock file afterwards. However, as rgooch remarks, that has a
- * race: a second mount may be waiting on the lock and proceed as
- * soon as the lock file is deleted by the first mount, and immediately
- * afterwards a third mount comes, creates a new /etc/mtab~, applies
- * flock to that, and also proceeds, so that the second and third mount
- * are now both scribbling in /etc/mtab.
- *
- * The new code uses a link() instead of a creat(), where we proceed
- * only if it was us that created the lock, and hence we always have
- * to delete the lock afterwards. Now the use of flock() is in principle
- * superfluous, but avoids an arbitrary sleep().
- *
- * Where does the link point to? Obvious choices are mtab and mtab~~.
- * HJLu points out that the latter leads to races. Right now we use
- * mtab~.pid instead.
- *
- *
- * The original mount locking code has used sleep(1) between attempts and
- * maximal number of attempts has been 5.
- *
- * There was a very small number of attempts and extremely long waiting (1s)
- * that is useless on machines with large number of mount processes.
- *
- * Now we wait for a few thousand microseconds between attempts and we have a global
- * time limit (30s) rather than a limit for the number of attempts. The advantage
- * is that this method also counts time which we spend in fcntl(F_SETLKW) and
- * the number of attempts is not restricted.
- * -- kzak@redhat.com [Mar-2007]
- *
- *
- * This mtab locking code has been refactored and moved to libmount. The mtab
- * locking is really not perfect (e.g. SIGALRM), but it's stable, reliable and
- * backwardly compatible code.
- *
- * Don't forget that this code has to be compatible with 3rd party mounts
- * (/sbin/mount.foo) and has to work with NFS.
- * -- kzak@redhat.com [May-2009]
- */
-
-/* maximum seconds between the first and the last attempt */
-#define MOUNTLOCK_MAXTIME              30
-
-/* sleep time (in microseconds, max=999999) between attempts */
-#define MOUNTLOCK_WAITTIME             5000
-
-static void unlock_mtab(struct libmnt_lock *ml)
-{
-       if (!ml)
-               return;
-
-       if (!ml->locked && ml->lockfile && ml->linkfile)
-       {
-               /* We (probably) have all the files, but we don't own the lock,
-                * Really? Check it! Maybe ml->locked wasn't set properly
-                * because the code was interrupted by a signal. Paranoia? Yes.
-                *
-                * We own the lock when linkfile == lockfile.
-                */
-               struct stat lo, li;
-
-               if (!stat(ml->lockfile, &lo) && !stat(ml->linkfile, &li) &&
-                   lo.st_dev == li.st_dev && lo.st_ino == li.st_ino)
-                       ml->locked = 1;
-       }
-
-       if (ml->linkfile)
-               unlink(ml->linkfile);
-       if (ml->lockfile_fd >= 0)
-               close(ml->lockfile_fd);
-       if (ml->locked && ml->lockfile) {
-               unlink(ml->lockfile);
-               DBG(LOCKS, ul_debugobj(ml, "unlink %s", ml->lockfile));
-       }
-}
-
-static int lock_mtab(struct libmnt_lock *ml)
-{
-       int i, rc = -1;
-       struct timespec waittime = { 0 };;
-       struct timeval maxtime = { 0 };
-       const char *lockfile, *linkfile;
-
-       if (!ml)
-               return -EINVAL;
-       if (ml->locked)
-               return 0;
-
-       lockfile = mnt_lock_get_lockfile(ml);
-       if (!lockfile)
-               return -EINVAL;
-       linkfile = mnt_lock_get_linkfile(ml);
-       if (!linkfile)
-               return -EINVAL;
-
-       if (ml->sigblock) {
-               /*
-                * Block all signals when locked, mnt_unlock_file() will
-                * restore the old mask.
-                */
-               sigset_t sigs;
-
-               sigemptyset(&ml->oldsigmask);
-               sigfillset(&sigs);
-               sigdelset(&sigs, SIGTRAP);
-               sigdelset(&sigs, SIGALRM);
-               sigprocmask(SIG_BLOCK, &sigs, &ml->oldsigmask);
-       }
-
-       i = open(linkfile, O_WRONLY|O_CREAT|O_CLOEXEC, S_IRUSR|S_IWUSR);
-       if (i < 0) {
-               /* linkfile does not exist (as a file) and we cannot create it.
-                * Read-only or full filesystem? Too many files open in the system?
-                */
-               if (errno > 0)
-                       rc = -errno;
-               goto failed;
-       }
-       close(i);
-
-       gettime_monotonic(&maxtime);
-       maxtime.tv_sec += MOUNTLOCK_MAXTIME;
-
-       waittime.tv_sec = 0;
-       waittime.tv_nsec = (1000 * MOUNTLOCK_WAITTIME);
-
-       /* Repeat until it was us who made the link */
-       while (!ml->locked) {
-               struct timeval now = { 0 };
-               struct flock flock;
-               int j;
-
-               j = link(linkfile, lockfile);
-               if (j == 0)
-                       ml->locked = 1;
-
-               if (j < 0 && errno != EEXIST) {
-                       if (errno > 0)
-                               rc = -errno;
-                       goto failed;
-               }
-               ml->lockfile_fd = open(lockfile, O_WRONLY|O_CLOEXEC);
-
-               if (ml->lockfile_fd < 0) {
-                       /* Strange... Maybe the file was just deleted? */
-                       int errsv = errno;
-                       gettime_monotonic(&now);
-                       if (errsv == ENOENT && now.tv_sec < maxtime.tv_sec) {
-                               ml->locked = 0;
-                               continue;
-                       }
-                       if (errsv > 0)
-                               rc = -errsv;
-                       goto failed;
-               }
-
-               flock.l_type = F_WRLCK;
-               flock.l_whence = SEEK_SET;
-               flock.l_start = 0;
-               flock.l_len = 0;
-
-               if (ml->locked) {
-                       /* We made the link. Now claim the lock. */
-                       if (fcntl (ml->lockfile_fd, F_SETLK, &flock) == -1) {
-                               DBG(LOCKS, ul_debugobj(ml,
-                                       "%s: can't F_SETLK lockfile, errno=%d\n",
-                                       lockfile, errno));
-                               /* proceed, since it was us who created the lockfile anyway */
-                       }
-                       break;
-               }
-
-               /* Someone else made the link. Wait. */
-               int err = mnt_wait_mtab_lock(ml, &flock, maxtime.tv_sec);
-
-               if (err == 1) {
-                       DBG(LOCKS, ul_debugobj(ml,
-                               "%s: can't create link: time out (perhaps "
-                               "there is a stale lock file?)", lockfile));
-                       rc = -ETIMEDOUT;
-                       goto failed;
-
-               } else if (err < 0) {
-                       rc = err;
-                       goto failed;
-               }
-               nanosleep(&waittime, NULL);
-               close(ml->lockfile_fd);
-               ml->lockfile_fd = -1;
-       }
-       DBG(LOCKS, ul_debugobj(ml, "%s: (%d) successfully locked",
-                                       lockfile, getpid()));
-       unlink(linkfile);
-       return 0;
-
-failed:
-       mnt_unlock_file(ml);
-       return rc;
-}
-
-
 /**
  * mnt_lock_file
  * @ml: pointer to struct libmnt_lock instance
  *
- * Creates a lock file (e.g. /etc/mtab~). Note that this function may
- * use alarm().
- *
- * Your application always has to call mnt_unlock_file() before exit.
- *
- * Traditional mtab locking scheme:
- *
- *   1. create linkfile (e.g. /etc/mtab~.$PID)
- *   2. link linkfile --> lockfile (e.g. /etc/mtab~.$PID --> /etc/mtab~)
- *   3. a) link() success: setups F_SETLK lock (see fcntl(2))
- *      b) link() failed:  wait (max 30s) on F_SETLKW lock, goto 2.
- *
+ * Creates a lock file.
+*
  * Note that when the lock is used by mnt_update_table() interface then libmount
- * uses flock() for private library file /run/mount/utab. The fcntl(2) is used only
- * for backwardly compatible stuff like /etc/mtab.
+ * uses flock() for private library file /run/mount/utab.
  *
  * Returns: 0 on success or negative number in case of error (-ETIMEOUT is case
  * of stale lock file).
@@ -541,10 +217,7 @@ int mnt_lock_file(struct libmnt_lock *ml)
        if (!ml)
                return -EINVAL;
 
-       if (ml->simplelock)
-               return lock_simplelock(ml);
-
-       return lock_mtab(ml);
+       return lock_simplelock(ml);
 }
 
 /**
@@ -562,10 +235,7 @@ void mnt_unlock_file(struct libmnt_lock *ml)
        DBG(LOCKS, ul_debugobj(ml, "(%d) %s", getpid(),
                        ml->locked ? "unlocking" : "cleaning"));
 
-       if (ml->simplelock)
-               unlock_simplelock(ml);
-       else
-               unlock_mtab(ml);
+       unlock_simplelock(ml);
 
        ml->locked = 0;
        ml->lockfile_fd = -1;
index 7a8ed0b863a7c73de8767a5d4401cc34fdef5671..ffd9ba4fe3be2148f86aad3de8d24e0259318aa8 100644 (file)
@@ -394,9 +394,6 @@ struct libmnt_context
 /* Flags usable with MS_BIND|MS_REMOUNT */
 #define MNT_BIND_SETTABLE      (MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_NOATIME|MS_NODIRATIME|MS_RELATIME|MS_RDONLY|MS_NOSYMFOLLOW)
 
-/* lock.c */
-extern int mnt_lock_use_simplelock(struct libmnt_lock *ml, int enable);
-
 /* optmap.c */
 extern const struct libmnt_optmap *mnt_optmap_get_entry(
                             struct libmnt_optmap const **maps,
index b045b1dcb520cac4b1aad600a26f66ab52bb54d7..f914df4122f7c88779a9cd481783c08edf102aed 100644 (file)
@@ -854,8 +854,6 @@ int mnt_update_table(struct libmnt_update *upd, struct libmnt_lock *lc)
                if (lc)
                        mnt_lock_block_signals(lc, TRUE);
        }
-       if (lc)
-               mnt_lock_use_simplelock(lc, TRUE);      /* use flock */
 
        if (!upd->fs && upd->target)
                rc = update_remove_entry(upd, lc);      /* umount */
@@ -890,8 +888,6 @@ int mnt_update_already_done(struct libmnt_update *upd, struct libmnt_lock *lc)
                if (lc)
                        mnt_lock_block_signals(lc, TRUE);
        }
-       if (lc)
-               mnt_lock_use_simplelock(lc, TRUE);      /* use flock */
        if (lc) {
                rc = mnt_lock_file(lc);
                if (rc) {