| // +build linux |
| |
| package overlay2 // import "github.com/docker/docker/daemon/graphdriver/overlay2" |
| |
| import ( |
| "crypto/rand" |
| "encoding/base32" |
| "fmt" |
| "io" |
| "os" |
| "syscall" |
| "time" |
| |
| "golang.org/x/sys/unix" |
| ) |
| |
| // generateID creates a new random string identifier with the given length |
| func generateID(l int) string { |
| const ( |
| // ensures we backoff for less than 450ms total. Use the following to |
| // select new value, in units of 10ms: |
| // n*(n+1)/2 = d -> n^2 + n - 2d -> n = (sqrt(8d + 1) - 1)/2 |
| maxretries = 9 |
| backoff = time.Millisecond * 10 |
| ) |
| |
| var ( |
| totalBackoff time.Duration |
| count int |
| retries int |
| size = (l*5 + 7) / 8 |
| u = make([]byte, size) |
| ) |
| // TODO: Include time component, counter component, random component |
| |
| for { |
| // This should never block but the read may fail. Because of this, |
| // we just try to read the random number generator until we get |
| // something. This is a very rare condition but may happen. |
| b := time.Duration(retries) * backoff |
| time.Sleep(b) |
| totalBackoff += b |
| |
| n, err := io.ReadFull(rand.Reader, u[count:]) |
| if err != nil { |
| if retryOnError(err) && retries < maxretries { |
| count += n |
| retries++ |
| logger.Errorf("error generating version 4 uuid, retrying: %v", err) |
| continue |
| } |
| |
| // Any other errors represent a system problem. What did someone |
| // do to /dev/urandom? |
| panic(fmt.Errorf("error reading random number generator, retried for %v: %v", totalBackoff.String(), err)) |
| } |
| |
| break |
| } |
| |
| s := base32.StdEncoding.EncodeToString(u) |
| |
| return s[:l] |
| } |
| |
| // retryOnError tries to detect whether or not retrying would be fruitful. |
| func retryOnError(err error) bool { |
| switch err := err.(type) { |
| case *os.PathError: |
| return retryOnError(err.Err) // unpack the target error |
| case syscall.Errno: |
| if err == unix.EPERM { |
| // EPERM represents an entropy pool exhaustion, a condition under |
| // which we backoff and retry. |
| return true |
| } |
| } |
| |
| return false |
| } |