Re: Possible race condition in pg_mkdir_p()? - Mailing list pgsql-hackers

From Ning Yu
Subject Re: Possible race condition in pg_mkdir_p()?
Date
Msg-id CAKmaiL09rBaYheHoG+6TTeaER1nXG9+=56fz4F-DR_cXuchjug@mail.gmail.com
Whole thread Raw
In response to Re: Possible race condition in pg_mkdir_p()?  (Michael Paquier <michael@paquier.xyz>)
Responses Re: Possible race condition in pg_mkdir_p()?  (Michael Paquier <michael@paquier.xyz>)
List pgsql-hackers
On Tue, Jul 30, 2019 at 4:04 PM Michael Paquier <michael@paquier.xyz> wrote:
>
> On Tue, Jul 23, 2019 at 02:54:20PM +0800, Ning Yu wrote:
> > MakePGDirectory() is also called in TablespaceCreateDbspace(), EEXIST is
> > considered as non-error for parent directories, however as it considers
> > EEXIST as a failure for the last level of the path so the logic is
> > still correct,
>
> So the complains here are about two things:
> - In some code paths calling mkdir, we don't care about the fact that
> EEXIST can happen for something else than a folder.  This could be a
> problem if we have conflicts in the backend related to the naming of
> the files/folders created.  I find a bit surprising to not perform
> the sanity checks in MakePGDirectory() in your patch.  What of all the
> existing callers of this routine?

Thanks for the reply.  There are several callers of MakePGDirectory(), most of
them already treats EEXIST as an error; TablespaceCreateDbspace() already has
a proper checking for the target dir, it has the chance to fail on a
concurrently created dir, but at least it will not be confused by a file with
the same name; PathNameCreateTemporaryDir() is fixed by our patch 0004, we
will call stat() after mkdir() to double check the result.

In fact personally I'm thinking that whether could we replace all uses of
MakePGDirectory() with pg_mkdir_p(), so we could simplify
TablespaceCreateDbspace() and PathNameCreateTemporaryDir() and other callers
significantly.

> - pg_mkdir_p is pretty bad at detecting problems with concurrent
> creation of parent directories, leading to random failures where these
> should not happen.
>
> I may be missing something, but your patch does not actually fix
> problem 2, no?  Trying to do an initdb with a set of N folders using
> the same parent folders not created still results in random failures.

Well, we should have fixed problem 2, this is our major purpose of the patch
0001, it performs sanity check with stat() after mkdir() at each part of the
path.

The initdb test was just the one used by us to verify our fix, here is our
script:

        n=4
        testdir=testdir
        datadir=$testdir/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z
        logdir=$testdir/logs

        rm -rf $testdir
        mkdir -p $logdir

        for i in `seq $n`; do
            initdb -D $datadir/$i >$logdir/$i.log 2>&1 &
        done

        wait

        # check for failures
        grep 'could not create directory' $logdir/*

We have provided a test module in patch 0002 to perform a similar test, it
calls pg_mkdir_p() concurrently to trigger the issue, which has higher fail
rate than initdb.  With the patch 0001 both the initdb test and the test
module will always succeed in our local environment.

Thanks
Ning

> --
> Michael



pgsql-hackers by date:

Previous
From: Wh isere
Date:
Subject: Re: query1 followed by query2 at maximum distance vs current fixed distance
Next
From: Konstantin Knizhnik
Date:
Subject: Re: Built-in connection pooler