[PATCH 2 of 2] lock: include Linux pid namespace identifier in prefix

Jun Wu quark at fb.com
Fri Feb 10 19:50:55 EST 2017


I'd like to note that although this patch prevents repo corruption when
running hg inside different containers (which has different pid namespaces),
it does not prevent deadlock - if an hg process is SIGKILL-ed, every other
process will not able to take or remove the lock.

I think if we do know the repo is not on NFS, and the system supports
flock(), flock() is way more robust and solves all kinds of pain here.

I hereby propose a new repo requirement "flock", once set, use flock instead
of the traditional lock file. It's off by default. Thoughts?

Excerpts from Jun Wu's message of 2017-02-10 14:09:35 -0800:
> # HG changeset patch
> # User Jun Wu <quark at fb.com>
> # Date 1486763791 28800
> #      Fri Feb 10 13:56:31 2017 -0800
> # Node ID 1884652829f6e68bde6ab3e9b0e9ca1da9bed40c
> # Parent  f8eb762559b242ec12b199db1ce27c2930881c75
> # Available At https://bitbucket.org/quark-zju/hg-draft 
> #              hg pull https://bitbucket.org/quark-zju/hg-draft  -r 1884652829f6
> lock: include Linux pid namespace identifier in prefix
> 
> Previously, the lock only contains a hostname as an attempt to detect pid
> namespace difference. However, that's not enough on modern Linux - a single
> hostname could have different pid namespaces.
> 
> That means if people run hg inside different PID namespaces with a same UTS
> namespae, the lock would be broken - an hg proccess in pid namespace A will
> think the lock having a "random" pid in pid namespace B is "dead" and remove
> it.
> 
> This patch solves the above issue by appending an PID namespace identifier of
> the current process to the lock prefix ("hostname"). It depends on /proc
> being mounted properly. But I don't think there is a better way to get pid
> namespace identifier reliably.
> 
> diff --git a/mercurial/lock.py b/mercurial/lock.py
> --- a/mercurial/lock.py
> +++ b/mercurial/lock.py
> @@ -10,4 +10,5 @@ from __future__ import absolute_import
>  import contextlib
>  import errno
> +import os
>  import socket
>  import time
> @@ -16,4 +17,5 @@ import warnings
>  from . import (
>      error,
> +    pycompat,
>      util,
>  )
> @@ -23,7 +25,15 @@ def _getlockprefix():
>  
>      It's useful to detect "dead" processes and remove stale locks with
> -    confidence. Typically it's just hostname.
> +    confidence. Typically it's just hostname. On modern linux, we include an
> +    extra Linux-specific pid namespace identifier.
>      """
> -    return socket.gethostname()
> +    result = socket.gethostname()
> +    if pycompat.sysplatform.startswith('linux'):
> +        try:
> +            result += '/%x' % os.stat('/proc/self/ns/pid').st_ino
> +        except OSError as ex:
> +            if ex.errno not in (errno.ENOENT, errno.EACCES, errno.ENOTDIR):
> +                raise
> +    return result
>  
>  class lock(object):


More information about the Mercurial-devel mailing list