master
go 114 lines 2.49 KB
Raw
1 package util
2
3 import (
4 "fmt"
5 "os"
6 "strconv"
7 "syscall"
8
9 logging "github.com/ipfs/go-log/v2"
10 )
11
12 var log = logging.Logger("ulimit")
13
14 var (
15 supportsFDManagement = false
16
17 // getlimit returns the soft and hard limits of file descriptors counts.
18 getLimit func() (uint64, uint64, error)
19 // set limit sets the soft and hard limits of file descriptors counts.
20 setLimit func(uint64, uint64) error
21 )
22
23 // minimum file descriptor limit before we complain.
24 const minFds = 2048
25
26 // default max file descriptor limit.
27 const maxFds = 8192
28
29 // userMaxFDs returns the value of IPFS_FD_MAX.
30 func userMaxFDs() uint64 {
31 // check if the IPFS_FD_MAX is set up and if it does
32 // not have a valid fds number notify the user
33 if val := os.Getenv("IPFS_FD_MAX"); val != "" {
34 fds, err := strconv.ParseUint(val, 10, 64)
35 if err != nil {
36 log.Errorf("bad value for IPFS_FD_MAX: %s", err)
37 return 0
38 }
39 return fds
40 }
41 return 0
42 }
43
44 // ManageFdLimit raise the current max file descriptor count
45 // of the process based on the IPFS_FD_MAX value.
46 func ManageFdLimit() (changed bool, newLimit uint64, err error) {
47 if !supportsFDManagement {
48 return false, 0, nil
49 }
50
51 targetLimit := uint64(maxFds)
52 userLimit := userMaxFDs()
53 if userLimit > 0 {
54 targetLimit = userLimit
55 }
56
57 soft, hard, err := getLimit()
58 if err != nil {
59 return false, 0, err
60 }
61
62 if targetLimit <= soft {
63 return false, 0, nil
64 }
65
66 // the soft limit is the value that the kernel enforces for the
67 // corresponding resource
68 // the hard limit acts as a ceiling for the soft limit
69 // an unprivileged process may only set its soft limit to a
70 // value in the range from 0 up to the hard limit
71 err = setLimit(targetLimit, targetLimit)
72 switch err {
73 case nil:
74 newLimit = targetLimit
75 case syscall.EPERM:
76 // lower limit if necessary.
77 if targetLimit > hard {
78 targetLimit = hard
79 }
80
81 // the process does not have permission so we should only
82 // set the soft value
83 err = setLimit(targetLimit, hard)
84 if err != nil {
85 err = fmt.Errorf("error setting ulimit without hard limit: %w", err)
86 break
87 }
88 newLimit = targetLimit
89
90 // Warn on lowered limit.
91
92 if newLimit < userLimit {
93 err = fmt.Errorf(
94 "failed to raise ulimit to IPFS_FD_MAX (%d): set to %d",
95 userLimit,
96 newLimit,
97 )
98 break
99 }
100
101 if userLimit == 0 && newLimit < minFds {
102 err = fmt.Errorf(
103 "failed to raise ulimit to minimum %d: set to %d",
104 minFds,
105 newLimit,
106 )
107 break
108 }
109 default:
110 err = fmt.Errorf("error setting: ulimit: %w", err)
111 }
112
113 return newLimit > 0, newLimit, err
114 }