From d40104b8a35f01d31cad1f11e312e76e034ffc4a Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 29 Dec 2015 13:29:00 +0100 Subject: fileutil: fix race in ProcessTempDir One goroutine decides that it needs to clean up an instance, but before it tries to delete pid file it is preempted. Then another goroutine cleans up this instances and creates a new instances in the same dir. Then first goroutine removes already new pid file and removes the used dir. Fix this by using flock on a lock file. Add a test. --- fileutil/fileutil.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'fileutil/fileutil.go') diff --git a/fileutil/fileutil.go b/fileutil/fileutil.go index 34e2562fa..a019a14ea 100644 --- a/fileutil/fileutil.go +++ b/fileutil/fileutil.go @@ -59,14 +59,25 @@ func WriteTempFile(data []byte) (string, error) { // ProcessTempDir creates a new temp dir in where and returns its path and an unique index. // It also cleans up old, unused temp dirs after dead processes. func ProcessTempDir(where string) (string, int, error) { - for i := 0; i < 1e4; i++ { + lk := filepath.Join(where, "instance-lock") + lkf, err := syscall.Open(lk, syscall.O_RDWR|syscall.O_CREAT, 0600) + if err != nil { + return "", 0, err + } + defer syscall.Close(lkf) + if err := syscall.Flock(lkf, syscall.LOCK_EX); err != nil { + return "", 0, err + } + defer syscall.Flock(lkf, syscall.LOCK_UN) + + for i := 0; i < 1e3; i++ { path := filepath.Join(where, fmt.Sprintf("instance-%v", i)) pidfile := filepath.Join(path, ".pid") err := os.Mkdir(path, 0700) if os.IsExist(err) { // Try to clean up. data, err := ioutil.ReadFile(pidfile) - if err == nil { + if err == nil && len(data) > 0 { pid, err := strconv.Atoi(string(data)) if err == nil && pid > 1 { if err := syscall.Kill(pid, 0); err == syscall.ESRCH { -- cgit mrf-deployment