Browse code

Plumb context through info endpoint

I was trying to find out why `docker info` was sometimes slow so
plumbing a context through to propagate trace data through.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2023/09/10 09:05:05
Showing 28 changed files
... ...
@@ -27,8 +27,8 @@ type DiskUsageOptions struct {
27 27
 // Backend is the methods that need to be implemented to provide
28 28
 // system specific functionality.
29 29
 type Backend interface {
30
-	SystemInfo() *system.Info
31
-	SystemVersion() types.Version
30
+	SystemInfo(context.Context) (*system.Info, error)
31
+	SystemVersion(context.Context) (types.Version, error)
32 32
 	SystemDiskUsage(ctx context.Context, opts DiskUsageOptions) (*types.DiskUsage, error)
33 33
 	SubscribeToEvents(since, until time.Time, ef filters.Args) ([]events.Message, chan interface{})
34 34
 	UnsubscribeFromEvents(chan interface{})
... ...
@@ -38,7 +38,7 @@ type Backend interface {
38 38
 // ClusterBackend is all the methods that need to be implemented
39 39
 // to provide cluster system specific functionality.
40 40
 type ClusterBackend interface {
41
-	Info() swarm.Info
41
+	Info(context.Context) swarm.Info
42 42
 }
43 43
 
44 44
 // StatusProvider provides methods to get the swarm status of the current node.
... ...
@@ -60,10 +60,13 @@ func (s *systemRouter) swarmStatus() string {
60 60
 func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
61 61
 	version := httputils.VersionFromContext(ctx)
62 62
 	info, _, _ := s.collectSystemInfo.Do(ctx, version, func(ctx context.Context) (*system.Info, error) {
63
-		info := s.backend.SystemInfo()
63
+		info, err := s.backend.SystemInfo(ctx)
64
+		if err != nil {
65
+			return nil, err
66
+		}
64 67
 
65 68
 		if s.cluster != nil {
66
-			info.Swarm = s.cluster.Info()
69
+			info.Swarm = s.cluster.Info(ctx)
67 70
 			info.Warnings = append(info.Warnings, info.Swarm.Warnings...)
68 71
 		}
69 72
 
... ...
@@ -97,7 +100,10 @@ func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *ht
97 97
 }
98 98
 
99 99
 func (s *systemRouter) getVersion(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
100
-	info := s.backend.SystemVersion()
100
+	info, err := s.backend.SystemVersion(ctx)
101
+	if err != nil {
102
+		return err
103
+	}
101 104
 
102 105
 	return httputils.WriteJSON(w, http.StatusOK, info)
103 106
 }
... ...
@@ -249,8 +249,8 @@ func (c *Cluster) newNodeRunner(conf nodeStartConfig) (*nodeRunner, error) {
249 249
 	return nr, nil
250 250
 }
251 251
 
252
-func (c *Cluster) getRequestContext() (context.Context, func()) { // TODO: not needed when requests don't block on qourum lost
253
-	return context.WithTimeout(context.Background(), swarmRequestTimeout)
252
+func (c *Cluster) getRequestContext(ctx context.Context) (context.Context, func()) { // TODO: not needed when requests don't block on qourum lost
253
+	return context.WithTimeout(ctx, swarmRequestTimeout)
254 254
 }
255 255
 
256 256
 // IsManager returns true if Cluster is participating as a manager.
... ...
@@ -443,7 +443,8 @@ func (c *Cluster) lockedManagerAction(fn func(ctx context.Context, state nodeSta
443 443
 		return c.errNoManager(state)
444 444
 	}
445 445
 
446
-	ctx, cancel := c.getRequestContext()
446
+	ctx := context.TODO()
447
+	ctx, cancel := c.getRequestContext(ctx)
447 448
 	defer cancel()
448 449
 
449 450
 	return fn(ctx, state)
... ...
@@ -41,7 +41,9 @@ func (c *Cluster) GetConfigs(options apitypes.ConfigListOptions) ([]types.Config
41 41
 	if err != nil {
42 42
 		return nil, err
43 43
 	}
44
-	ctx, cancel := c.getRequestContext()
44
+
45
+	ctx := context.TODO()
46
+	ctx, cancel := c.getRequestContext(ctx)
45 47
 	defer cancel()
46 48
 
47 49
 	r, err := state.controlClient.ListConfigs(ctx,
... ...
@@ -53,7 +53,7 @@ type Backend interface {
53 53
 	SetContainerDependencyStore(name string, store exec.DependencyGetter) error
54 54
 	SetContainerSecretReferences(name string, refs []*swarm.SecretReference) error
55 55
 	SetContainerConfigReferences(name string, refs []*swarm.ConfigReference) error
56
-	SystemInfo() *system.Info
56
+	SystemInfo(context.Context) (*system.Info, error)
57 57
 	Containers(ctx context.Context, config *container.ListOptions) ([]*types.Container, error)
58 58
 	SetNetworkBootstrapKeys([]*networktypes.EncryptionKey) error
59 59
 	DaemonJoinsCluster(provider cluster.Provider)
... ...
@@ -58,7 +58,10 @@ func NewExecutor(b executorpkg.Backend, p plugin.Backend, i executorpkg.ImageBac
58 58
 
59 59
 // Describe returns the underlying node description from the docker client.
60 60
 func (e *executor) Describe(ctx context.Context) (*api.NodeDescription, error) {
61
-	info := e.backend.SystemInfo()
61
+	info, err := e.backend.SystemInfo(ctx)
62
+	if err != nil {
63
+		return nil, err
64
+	}
62 65
 
63 66
 	plugins := map[api.PluginDescription]struct{}{}
64 67
 	addPlugins := func(typ string, names []string) {
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"github.com/docker/docker/daemon/cluster/convert"
13 13
 	internalnetwork "github.com/docker/docker/daemon/network"
14 14
 	"github.com/docker/docker/errdefs"
15
+	"github.com/docker/docker/internal/compatcontext"
15 16
 	"github.com/docker/docker/runconfig"
16 17
 	swarmapi "github.com/moby/swarmkit/v2/api"
17 18
 	"github.com/pkg/errors"
... ...
@@ -68,7 +69,8 @@ func (c *Cluster) getNetworks(filters *swarmapi.ListNetworksRequest_Filters) ([]
68 68
 		return nil, c.errNoManager(state)
69 69
 	}
70 70
 
71
-	ctx, cancel := c.getRequestContext()
71
+	ctx := context.TODO()
72
+	ctx, cancel := c.getRequestContext(ctx)
72 73
 	defer cancel()
73 74
 
74 75
 	r, err := state.controlClient.ListNetworks(ctx, &swarmapi.ListNetworksRequest{Filters: filters})
... ...
@@ -203,7 +205,8 @@ func (c *Cluster) AttachNetwork(target string, containerID string, addresses []s
203 203
 	}
204 204
 	c.mu.Unlock()
205 205
 
206
-	ctx, cancel := c.getRequestContext()
206
+	ctx := context.TODO()
207
+	ctx, cancel := c.getRequestContext(ctx)
207 208
 	defer cancel()
208 209
 
209 210
 	taskID, err := agent.ResourceAllocator().AttachNetwork(ctx, containerID, target, addresses)
... ...
@@ -222,7 +225,8 @@ func (c *Cluster) AttachNetwork(target string, containerID string, addresses []s
222 222
 	log.G(ctx).Debugf("Successfully attached to network %s with task id %s", target, taskID)
223 223
 
224 224
 	release := func() {
225
-		ctx, cancel := c.getRequestContext()
225
+		ctx := compatcontext.WithoutCancel(ctx)
226
+		ctx, cancel := c.getRequestContext(ctx)
226 227
 		defer cancel()
227 228
 		if err := agent.ResourceAllocator().DetachNetwork(ctx, taskID); err != nil {
228 229
 			log.G(ctx).Errorf("Failed remove network attachment %s to network %s on allocation failure: %v",
... ...
@@ -26,7 +26,8 @@ func (c *Cluster) GetNodes(options apitypes.NodeListOptions) ([]types.Node, erro
26 26
 		return nil, err
27 27
 	}
28 28
 
29
-	ctx, cancel := c.getRequestContext()
29
+	ctx := context.TODO()
30
+	ctx, cancel := c.getRequestContext(ctx)
30 31
 	defer cancel()
31 32
 
32 33
 	r, err := state.controlClient.ListNodes(
... ...
@@ -72,7 +73,8 @@ func (c *Cluster) UpdateNode(input string, version uint64, spec types.NodeSpec)
72 72
 			return errdefs.InvalidParameter(err)
73 73
 		}
74 74
 
75
-		ctx, cancel := c.getRequestContext()
75
+		ctx := context.TODO()
76
+		ctx, cancel := c.getRequestContext(ctx)
76 77
 		defer cancel()
77 78
 
78 79
 		currentNode, err := getNode(ctx, state.controlClient, input)
... ...
@@ -41,7 +41,9 @@ func (c *Cluster) GetSecrets(options apitypes.SecretListOptions) ([]types.Secret
41 41
 	if err != nil {
42 42
 		return nil, err
43 43
 	}
44
-	ctx, cancel := c.getRequestContext()
44
+
45
+	ctx := context.TODO()
46
+	ctx, cancel := c.getRequestContext(ctx)
45 47
 	defer cancel()
46 48
 
47 49
 	r, err := state.controlClient.ListSecrets(ctx,
... ...
@@ -21,6 +21,7 @@ import (
21 21
 	timetypes "github.com/docker/docker/api/types/time"
22 22
 	"github.com/docker/docker/daemon/cluster/convert"
23 23
 	"github.com/docker/docker/errdefs"
24
+	"github.com/docker/docker/internal/compatcontext"
24 25
 	runconfigopts "github.com/docker/docker/runconfig/opts"
25 26
 	gogotypes "github.com/gogo/protobuf/types"
26 27
 	swarmapi "github.com/moby/swarmkit/v2/api"
... ...
@@ -65,7 +66,8 @@ func (c *Cluster) GetServices(options types.ServiceListOptions) ([]swarm.Service
65 65
 		Runtimes:     options.Filters.Get("runtime"),
66 66
 	}
67 67
 
68
-	ctx, cancel := c.getRequestContext()
68
+	ctx := context.TODO()
69
+	ctx, cancel := c.getRequestContext(ctx)
69 70
 	defer cancel()
70 71
 
71 72
 	r, err := state.controlClient.ListServices(
... ...
@@ -263,7 +265,8 @@ func (c *Cluster) CreateService(s swarm.ServiceSpec, encodedAuth string, queryRe
263 263
 				// "ctx" could make it impossible to create a service
264 264
 				// if the registry is slow or unresponsive.
265 265
 				var cancel func()
266
-				ctx, cancel = c.getRequestContext()
266
+				ctx = compatcontext.WithoutCancel(ctx)
267
+				ctx, cancel = c.getRequestContext(ctx)
267 268
 				defer cancel()
268 269
 			}
269 270
 
... ...
@@ -378,7 +381,8 @@ func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec swa
378 378
 				// "ctx" could make it impossible to update a service
379 379
 				// if the registry is slow or unresponsive.
380 380
 				var cancel func()
381
-				ctx, cancel = c.getRequestContext()
381
+				ctx = compatcontext.WithoutCancel(ctx)
382
+				ctx, cancel = c.getRequestContext(ctx)
382 383
 				defer cancel()
383 384
 			}
384 385
 		}
... ...
@@ -429,7 +429,7 @@ func (c *Cluster) Leave(ctx context.Context, force bool) error {
429 429
 }
430 430
 
431 431
 // Info returns information about the current cluster state.
432
-func (c *Cluster) Info() types.Info {
432
+func (c *Cluster) Info(ctx context.Context) types.Info {
433 433
 	info := types.Info{
434 434
 		NodeAddr: c.GetAdvertiseAddress(),
435 435
 	}
... ...
@@ -442,7 +442,7 @@ func (c *Cluster) Info() types.Info {
442 442
 		info.Error = state.err.Error()
443 443
 	}
444 444
 
445
-	ctx, cancel := c.getRequestContext()
445
+	ctx, cancel := c.getRequestContext(ctx)
446 446
 	defer cancel()
447 447
 
448 448
 	if state.IsActiveManager() {
... ...
@@ -76,8 +76,8 @@ func (i *ImageService) DistributionServices() images.DistributionServices {
76 76
 
77 77
 // CountImages returns the number of images stored by ImageService
78 78
 // called from info.go
79
-func (i *ImageService) CountImages() int {
80
-	imgs, err := i.client.ListImages(context.TODO())
79
+func (i *ImageService) CountImages(ctx context.Context) int {
80
+	imgs, err := i.client.ListImages(ctx)
81 81
 	if err != nil {
82 82
 		return 0
83 83
 	}
... ...
@@ -1175,7 +1175,10 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
1175 1175
 	}
1176 1176
 	close(d.startupDone)
1177 1177
 
1178
-	info := d.SystemInfo()
1178
+	info, err := d.SystemInfo(ctx)
1179
+	if err != nil {
1180
+		return nil, err
1181
+	}
1179 1182
 	for _, w := range info.Warnings {
1180 1183
 		log.G(ctx).Warn(w)
1181 1184
 	}
... ...
@@ -1349,7 +1352,7 @@ func (daemon *Daemon) Subnets() ([]net.IPNet, []net.IPNet) {
1349 1349
 	var v4Subnets []net.IPNet
1350 1350
 	var v6Subnets []net.IPNet
1351 1351
 
1352
-	for _, managedNetwork := range daemon.netController.Networks() {
1352
+	for _, managedNetwork := range daemon.netController.Networks(context.TODO()) {
1353 1353
 		v4infos, v6infos := managedNetwork.IpamInfo()
1354 1354
 		for _, info := range v4infos {
1355 1355
 			if info.IPAMData.Pool != nil {
... ...
@@ -247,8 +247,10 @@ func (daemon *Daemon) initNetworkController(daemonCfg *config.Config, activeSand
247 247
 		return err
248 248
 	}
249 249
 
250
+	ctx := context.TODO()
251
+
250 252
 	// Remove networks not present in HNS
251
-	for _, v := range daemon.netController.Networks() {
253
+	for _, v := range daemon.netController.Networks(ctx) {
252 254
 		hnsid := v.DriverOptions()[winlibnetwork.HNSID]
253 255
 		found := false
254 256
 
... ...
@@ -68,7 +68,7 @@ func (daemon *Daemon) LogNetworkEventWithAttributes(nw *libnetwork.Network, acti
68 68
 // LogDaemonEventWithAttributes generates an event related to the daemon itself with specific given attributes.
69 69
 func (daemon *Daemon) LogDaemonEventWithAttributes(action events.Action, attributes map[string]string) {
70 70
 	if daemon.EventsService != nil {
71
-		if name := hostName(); name != "" {
71
+		if name := hostName(context.TODO()); name != "" {
72 72
 			attributes["name"] = name
73 73
 		}
74 74
 		daemon.EventsService.Log(action, events.DaemonEventType, events.Actor{
... ...
@@ -36,7 +36,7 @@ type ImageService interface {
36 36
 	LoadImage(ctx context.Context, inTar io.ReadCloser, outStream io.Writer, quiet bool) error
37 37
 	Images(ctx context.Context, opts types.ImageListOptions) ([]*imagetype.Summary, error)
38 38
 	LogImageEvent(imageID, refName string, action events.Action)
39
-	CountImages() int
39
+	CountImages(ctx context.Context) int
40 40
 	ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error)
41 41
 	ImportImage(ctx context.Context, ref reference.Named, platform *ocispec.Platform, msg string, layerReader io.Reader, changes []string) (image.ID, error)
42 42
 	TagImage(ctx context.Context, imageID image.ID, newTag reference.Named) error
... ...
@@ -102,7 +102,7 @@ func (i *ImageService) DistributionServices() DistributionServices {
102 102
 
103 103
 // CountImages returns the number of images stored by ImageService
104 104
 // called from info.go
105
-func (i *ImageService) CountImages() int {
105
+func (i *ImageService) CountImages(ctx context.Context) int {
106 106
 	return i.imageStore.Len()
107 107
 }
108 108
 
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"strings"
9 9
 	"time"
10 10
 
11
+	"github.com/containerd/containerd/tracing"
11 12
 	"github.com/containerd/log"
12 13
 	"github.com/docker/docker/api"
13 14
 	"github.com/docker/docker/api/types"
... ...
@@ -27,8 +28,19 @@ import (
27 27
 	"github.com/opencontainers/selinux/go-selinux"
28 28
 )
29 29
 
30
+func doWithTrace[T any](ctx context.Context, name string, f func() T) T {
31
+	_, span := tracing.StartSpan(ctx, name)
32
+	defer span.End()
33
+	return f()
34
+}
35
+
30 36
 // SystemInfo returns information about the host server the daemon is running on.
31
-func (daemon *Daemon) SystemInfo() *system.Info {
37
+//
38
+// The only error this should return is due to context cancellation/deadline.
39
+// Anything else should be logged and ignored because this is looking up
40
+// multiple things and is often used for debugging.
41
+// The only case valid early return is when the caller doesn't want the result anymore (ie context cancelled).
42
+func (daemon *Daemon) SystemInfo(ctx context.Context) (*system.Info, error) {
32 43
 	defer metrics.StartTimer(hostInfoFunctions.WithValues("system_info"))()
33 44
 
34 45
 	sysInfo := daemon.RawSysInfo()
... ...
@@ -36,22 +48,22 @@ func (daemon *Daemon) SystemInfo() *system.Info {
36 36
 
37 37
 	v := &system.Info{
38 38
 		ID:                 daemon.id,
39
-		Images:             daemon.imageService.CountImages(),
39
+		Images:             daemon.imageService.CountImages(ctx),
40 40
 		IPv4Forwarding:     !sysInfo.IPv4ForwardingDisabled,
41 41
 		BridgeNfIptables:   !sysInfo.BridgeNFCallIPTablesDisabled,
42 42
 		BridgeNfIP6tables:  !sysInfo.BridgeNFCallIP6TablesDisabled,
43
-		Name:               hostName(),
43
+		Name:               hostName(ctx),
44 44
 		SystemTime:         time.Now().Format(time.RFC3339Nano),
45 45
 		LoggingDriver:      daemon.defaultLogConfig.Type,
46
-		KernelVersion:      kernelVersion(),
47
-		OperatingSystem:    operatingSystem(),
48
-		OSVersion:          osVersion(),
46
+		KernelVersion:      kernelVersion(ctx),
47
+		OperatingSystem:    operatingSystem(ctx),
48
+		OSVersion:          osVersion(ctx),
49 49
 		IndexServerAddress: registry.IndexServer,
50 50
 		OSType:             runtime.GOOS,
51 51
 		Architecture:       platform.Architecture,
52
-		RegistryConfig:     daemon.registryService.ServiceConfig(),
53
-		NCPU:               sysinfo.NumCPU(),
54
-		MemTotal:           memInfo().MemTotal,
52
+		RegistryConfig:     doWithTrace(ctx, "registry.ServiceConfig", daemon.registryService.ServiceConfig),
53
+		NCPU:               doWithTrace(ctx, "sysinfo.NumCPU", sysinfo.NumCPU),
54
+		MemTotal:           memInfo(ctx).MemTotal,
55 55
 		GenericResources:   daemon.genericResources,
56 56
 		DockerRootDir:      cfg.Root,
57 57
 		Labels:             cfg.Labels,
... ...
@@ -66,24 +78,31 @@ func (daemon *Daemon) SystemInfo() *system.Info {
66 66
 	}
67 67
 
68 68
 	daemon.fillContainerStates(v)
69
-	daemon.fillDebugInfo(v)
69
+	daemon.fillDebugInfo(ctx, v)
70 70
 	daemon.fillAPIInfo(v, &cfg.Config)
71 71
 	// Retrieve platform specific info
72
-	daemon.fillPlatformInfo(v, sysInfo, cfg)
72
+	if err := daemon.fillPlatformInfo(ctx, v, sysInfo, cfg); err != nil {
73
+		return nil, err
74
+	}
73 75
 	daemon.fillDriverInfo(v)
74
-	daemon.fillPluginsInfo(v, &cfg.Config)
76
+	daemon.fillPluginsInfo(ctx, v, &cfg.Config)
75 77
 	daemon.fillSecurityOptions(v, sysInfo, &cfg.Config)
76 78
 	daemon.fillLicense(v)
77
-	daemon.fillDefaultAddressPools(v, &cfg.Config)
79
+	daemon.fillDefaultAddressPools(ctx, v, &cfg.Config)
78 80
 
79
-	return v
81
+	return v, nil
80 82
 }
81 83
 
82 84
 // SystemVersion returns version information about the daemon.
83
-func (daemon *Daemon) SystemVersion() types.Version {
85
+//
86
+// The only error this should return is due to context cancellation/deadline.
87
+// Anything else should be logged and ignored because this is looking up
88
+// multiple things and is often used for debugging.
89
+// The only case valid early return is when the caller doesn't want the result anymore (ie context cancelled).
90
+func (daemon *Daemon) SystemVersion(ctx context.Context) (types.Version, error) {
84 91
 	defer metrics.StartTimer(hostInfoFunctions.WithValues("system_version"))()
85 92
 
86
-	kernelVersion := kernelVersion()
93
+	kernelVersion := kernelVersion(ctx)
87 94
 	cfg := daemon.config()
88 95
 
89 96
 	v := types.Version{
... ...
@@ -120,8 +139,10 @@ func (daemon *Daemon) SystemVersion() types.Version {
120 120
 
121 121
 	v.Platform.Name = dockerversion.PlatformName
122 122
 
123
-	daemon.fillPlatformVersion(&v, cfg)
124
-	return v
123
+	if err := daemon.fillPlatformVersion(ctx, &v, cfg); err != nil {
124
+		return v, err
125
+	}
126
+	return v, nil
125 127
 }
126 128
 
127 129
 func (daemon *Daemon) fillDriverInfo(v *system.Info) {
... ...
@@ -140,10 +161,10 @@ WARNING: The %s storage-driver is deprecated, and will be removed in a future re
140 140
 	fillDriverWarnings(v)
141 141
 }
142 142
 
143
-func (daemon *Daemon) fillPluginsInfo(v *system.Info, cfg *config.Config) {
143
+func (daemon *Daemon) fillPluginsInfo(ctx context.Context, v *system.Info, cfg *config.Config) {
144 144
 	v.Plugins = system.PluginsInfo{
145 145
 		Volume:  daemon.volumes.GetDriverList(),
146
-		Network: daemon.GetNetworkDriverList(),
146
+		Network: daemon.GetNetworkDriverList(ctx),
147 147
 
148 148
 		// The authorization plugins are returned in the order they are
149 149
 		// used as they constitute a request/response modification chain.
... ...
@@ -198,9 +219,9 @@ func (daemon *Daemon) fillContainerStates(v *system.Info) {
198 198
 // this information optional (cli to request "with debugging information"), or
199 199
 // only collect it if the daemon has debug enabled. For the CLI code, see
200 200
 // https://github.com/docker/cli/blob/v20.10.12/cli/command/system/info.go#L239-L244
201
-func (daemon *Daemon) fillDebugInfo(v *system.Info) {
201
+func (daemon *Daemon) fillDebugInfo(ctx context.Context, v *system.Info) {
202 202
 	v.Debug = debug.IsEnabled()
203
-	v.NFd = fileutils.GetTotalUsedFds()
203
+	v.NFd = fileutils.GetTotalUsedFds(ctx)
204 204
 	v.NGoroutines = runtime.NumGoroutine()
205 205
 	v.NEventsListener = daemon.EventsService.SubscribersCount()
206 206
 }
... ...
@@ -228,7 +249,9 @@ func (daemon *Daemon) fillAPIInfo(v *system.Info, cfg *config.Config) {
228 228
 	}
229 229
 }
230 230
 
231
-func (daemon *Daemon) fillDefaultAddressPools(v *system.Info, cfg *config.Config) {
231
+func (daemon *Daemon) fillDefaultAddressPools(ctx context.Context, v *system.Info, cfg *config.Config) {
232
+	_, span := tracing.StartSpan(ctx, "fillDefaultAddressPools")
233
+	defer span.End()
232 234
 	for _, pool := range cfg.DefaultAddressPools.Value() {
233 235
 		v.DefaultAddressPools = append(v.DefaultAddressPools, system.NetworkAddressPool{
234 236
 			Base: pool.Base,
... ...
@@ -237,45 +260,56 @@ func (daemon *Daemon) fillDefaultAddressPools(v *system.Info, cfg *config.Config
237 237
 	}
238 238
 }
239 239
 
240
-func hostName() string {
240
+func hostName(ctx context.Context) string {
241
+	ctx, span := tracing.StartSpan(ctx, "hostName")
242
+	defer span.End()
241 243
 	hostname := ""
242 244
 	if hn, err := os.Hostname(); err != nil {
243
-		log.G(context.TODO()).Warnf("Could not get hostname: %v", err)
245
+		log.G(ctx).Warnf("Could not get hostname: %v", err)
244 246
 	} else {
245 247
 		hostname = hn
246 248
 	}
247 249
 	return hostname
248 250
 }
249 251
 
250
-func kernelVersion() string {
252
+func kernelVersion(ctx context.Context) string {
253
+	ctx, span := tracing.StartSpan(ctx, "kernelVersion")
254
+	defer span.End()
255
+
251 256
 	var kernelVersion string
252 257
 	if kv, err := kernel.GetKernelVersion(); err != nil {
253
-		log.G(context.TODO()).Warnf("Could not get kernel version: %v", err)
258
+		log.G(ctx).Warnf("Could not get kernel version: %v", err)
254 259
 	} else {
255 260
 		kernelVersion = kv.String()
256 261
 	}
257 262
 	return kernelVersion
258 263
 }
259 264
 
260
-func memInfo() *meminfo.Memory {
265
+func memInfo(ctx context.Context) *meminfo.Memory {
266
+	ctx, span := tracing.StartSpan(ctx, "memInfo")
267
+	defer span.End()
268
+
261 269
 	memInfo, err := meminfo.Read()
262 270
 	if err != nil {
263
-		log.G(context.TODO()).Errorf("Could not read system memory info: %v", err)
271
+		log.G(ctx).Errorf("Could not read system memory info: %v", err)
264 272
 		memInfo = &meminfo.Memory{}
265 273
 	}
266 274
 	return memInfo
267 275
 }
268 276
 
269
-func operatingSystem() (operatingSystem string) {
277
+func operatingSystem(ctx context.Context) (operatingSystem string) {
278
+	ctx, span := tracing.StartSpan(ctx, "operatingSystem")
279
+	defer span.End()
280
+
270 281
 	defer metrics.StartTimer(hostInfoFunctions.WithValues("operating_system"))()
271 282
 
272 283
 	if s, err := operatingsystem.GetOperatingSystem(); err != nil {
273
-		log.G(context.TODO()).Warnf("Could not get operating system name: %v", err)
284
+		log.G(ctx).Warnf("Could not get operating system name: %v", err)
274 285
 	} else {
275 286
 		operatingSystem = s
276 287
 	}
277 288
 	if inContainer, err := operatingsystem.IsContainerized(); err != nil {
278
-		log.G(context.TODO()).Errorf("Could not determine if daemon is containerized: %v", err)
289
+		log.G(ctx).Errorf("Could not determine if daemon is containerized: %v", err)
279 290
 		operatingSystem += " (error determining if containerized)"
280 291
 	} else if inContainer {
281 292
 		operatingSystem += " (containerized)"
... ...
@@ -284,12 +318,15 @@ func operatingSystem() (operatingSystem string) {
284 284
 	return operatingSystem
285 285
 }
286 286
 
287
-func osVersion() (version string) {
287
+func osVersion(ctx context.Context) (version string) {
288
+	ctx, span := tracing.StartSpan(ctx, "osVersion")
289
+	defer span.End()
290
+
288 291
 	defer metrics.StartTimer(hostInfoFunctions.WithValues("os_version"))()
289 292
 
290 293
 	version, err := operatingsystem.GetOperatingSystemVersion()
291 294
 	if err != nil {
292
-		log.G(context.TODO()).Warnf("Could not get operating system version: %v", err)
295
+		log.G(ctx).Warnf("Could not get operating system version: %v", err)
293 296
 	}
294 297
 
295 298
 	return version
... ...
@@ -16,6 +16,7 @@ import (
16 16
 	containertypes "github.com/docker/docker/api/types/container"
17 17
 	"github.com/docker/docker/api/types/system"
18 18
 	"github.com/docker/docker/daemon/config"
19
+	"github.com/docker/docker/errdefs"
19 20
 	"github.com/docker/docker/pkg/rootless"
20 21
 	"github.com/docker/docker/pkg/sysinfo"
21 22
 	"github.com/pkg/errors"
... ...
@@ -23,7 +24,7 @@ import (
23 23
 )
24 24
 
25 25
 // fillPlatformInfo fills the platform related info.
26
-func (daemon *Daemon) fillPlatformInfo(v *system.Info, sysInfo *sysinfo.SysInfo, cfg *configStore) {
26
+func (daemon *Daemon) fillPlatformInfo(ctx context.Context, v *system.Info, sysInfo *sysinfo.SysInfo, cfg *configStore) error {
27 27
 	v.CgroupDriver = cgroupDriver(&cfg.Config)
28 28
 	v.CgroupVersion = "1"
29 29
 	if sysInfo.CgroupUnified {
... ...
@@ -57,36 +58,20 @@ func (daemon *Daemon) fillPlatformInfo(v *system.Info, sysInfo *sysinfo.SysInfo,
57 57
 	v.ContainerdCommit.ID = "N/A"
58 58
 	v.InitCommit.ID = "N/A"
59 59
 
60
-	if _, _, commit, err := parseDefaultRuntimeVersion(&cfg.Runtimes); err != nil {
61
-		log.G(context.TODO()).Warnf(err.Error())
62
-	} else {
63
-		v.RuncCommit.ID = commit
60
+	if err := populateRuncCommit(&v.RuncCommit, cfg); err != nil {
61
+		log.G(ctx).WithError(err).Warn("Failed to retrieve default runtime version")
64 62
 	}
65 63
 
66
-	if rv, err := daemon.containerd.Version(context.Background()); err == nil {
67
-		v.ContainerdCommit.ID = rv.Revision
68
-	} else {
69
-		log.G(context.TODO()).Warnf("failed to retrieve containerd version: %v", err)
64
+	if err := daemon.populateContainerdCommit(ctx, &v.ContainerdCommit); err != nil {
65
+		return err
70 66
 	}
71 67
 
72
-	v.InitBinary = cfg.GetInitPath()
73
-	if initBinary, err := cfg.LookupInitPath(); err != nil {
74
-		log.G(context.TODO()).Warnf("failed to find docker-init: %s", err)
75
-	} else if rv, err := exec.Command(initBinary, "--version").Output(); err == nil {
76
-		if _, commit, err := parseInitVersion(string(rv)); err != nil {
77
-			log.G(context.TODO()).Warnf("failed to parse %s version: %s", initBinary, err)
78
-		} else {
79
-			v.InitCommit.ID = commit
80
-		}
81
-	} else {
82
-		log.G(context.TODO()).Warnf("failed to retrieve %s version: %s", initBinary, err)
68
+	if err := daemon.populateInitCommit(ctx, v, cfg); err != nil {
69
+		return err
83 70
 	}
84 71
 
85 72
 	// Set expected and actual commits to the same value to prevent the client
86 73
 	// showing that the version does not match the "expected" version/commit.
87
-	v.RuncCommit.Expected = v.RuncCommit.ID
88
-	v.ContainerdCommit.Expected = v.ContainerdCommit.ID
89
-	v.InitCommit.Expected = v.InitCommit.ID
90 74
 
91 75
 	if v.CgroupDriver == cgroupNoneDriver {
92 76
 		if v.CgroupVersion == "2" {
... ...
@@ -171,65 +156,79 @@ func (daemon *Daemon) fillPlatformInfo(v *system.Info, sysInfo *sysinfo.SysInfo,
171 171
 	if !v.BridgeNfIP6tables {
172 172
 		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-ip6tables is disabled")
173 173
 	}
174
+	return nil
174 175
 }
175 176
 
176
-func (daemon *Daemon) fillPlatformVersion(v *types.Version, cfg *configStore) {
177
-	if rv, err := daemon.containerd.Version(context.Background()); err == nil {
178
-		v.Components = append(v.Components, types.ComponentVersion{
179
-			Name:    "containerd",
180
-			Version: rv.Version,
181
-			Details: map[string]string{
182
-				"GitCommit": rv.Revision,
183
-			},
184
-		})
177
+func (daemon *Daemon) fillPlatformVersion(ctx context.Context, v *types.Version, cfg *configStore) error {
178
+	if err := daemon.populateContainerdVersion(ctx, v); err != nil {
179
+		return err
185 180
 	}
186 181
 
187
-	if _, ver, commit, err := parseDefaultRuntimeVersion(&cfg.Runtimes); err != nil {
188
-		log.G(context.TODO()).Warnf(err.Error())
189
-	} else {
190
-		v.Components = append(v.Components, types.ComponentVersion{
191
-			Name:    cfg.Runtimes.Default,
192
-			Version: ver,
193
-			Details: map[string]string{
194
-				"GitCommit": commit,
195
-			},
196
-		})
197
-	}
198
-
199
-	if initBinary, err := cfg.LookupInitPath(); err != nil {
200
-		log.G(context.TODO()).Warnf("failed to find docker-init: %s", err)
201
-	} else if rv, err := exec.Command(initBinary, "--version").Output(); err == nil {
202
-		if ver, commit, err := parseInitVersion(string(rv)); err != nil {
203
-			log.G(context.TODO()).Warnf("failed to parse %s version: %s", initBinary, err)
204
-		} else {
205
-			v.Components = append(v.Components, types.ComponentVersion{
206
-				Name:    filepath.Base(initBinary),
207
-				Version: ver,
208
-				Details: map[string]string{
209
-					"GitCommit": commit,
210
-				},
211
-			})
182
+	if err := populateRuncVersion(cfg, v); err != nil {
183
+		log.G(ctx).WithError(err).Warn("Failed to retrieve default runtime version")
184
+	}
185
+
186
+	if err := populateInitVersion(ctx, cfg, v); err != nil {
187
+		return err
188
+	}
189
+
190
+	if err := daemon.fillRootlessVersion(ctx, v); err != nil {
191
+		if errdefs.IsContext(err) {
192
+			return err
212 193
 		}
213
-	} else {
214
-		log.G(context.TODO()).Warnf("failed to retrieve %s version: %s", initBinary, err)
194
+		log.G(ctx).WithError(err).Warn("Failed to fill rootless version")
215 195
 	}
196
+	return nil
197
+}
216 198
 
217
-	daemon.fillRootlessVersion(v)
199
+func populateRuncCommit(v *system.Commit, cfg *configStore) error {
200
+	_, _, commit, err := parseDefaultRuntimeVersion(&cfg.Runtimes)
201
+	if err != nil {
202
+		return err
203
+	}
204
+	v.ID = commit
205
+	v.Expected = commit
206
+	return nil
218 207
 }
219 208
 
220
-func (daemon *Daemon) fillRootlessVersion(v *types.Version) {
209
+func (daemon *Daemon) populateInitCommit(ctx context.Context, v *system.Info, cfg *configStore) error {
210
+	v.InitBinary = cfg.GetInitPath()
211
+	initBinary, err := cfg.LookupInitPath()
212
+	if err != nil {
213
+		log.G(ctx).WithError(err).Warnf("Failed to find docker-init")
214
+		return nil
215
+	}
216
+
217
+	rv, err := exec.CommandContext(ctx, initBinary, "--version").Output()
218
+	if err != nil {
219
+		if errdefs.IsContext(err) {
220
+			return err
221
+		}
222
+		log.G(ctx).WithError(err).Warnf("Failed to retrieve %s version", initBinary)
223
+		return nil
224
+	}
225
+
226
+	_, commit, err := parseInitVersion(string(rv))
227
+	if err != nil {
228
+		log.G(ctx).WithError(err).Warnf("failed to parse %s version", initBinary)
229
+		return nil
230
+	}
231
+	v.InitCommit.ID = commit
232
+	v.InitCommit.Expected = v.InitCommit.ID
233
+	return nil
234
+}
235
+
236
+func (daemon *Daemon) fillRootlessVersion(ctx context.Context, v *types.Version) error {
221 237
 	if !rootless.RunningWithRootlessKit() {
222
-		return
238
+		return nil
223 239
 	}
224 240
 	rlc, err := getRootlessKitClient()
225 241
 	if err != nil {
226
-		log.G(context.TODO()).Warnf("failed to create RootlessKit client: %v", err)
227
-		return
242
+		return errors.Wrap(err, "failed to create RootlessKit client")
228 243
 	}
229
-	rlInfo, err := rlc.Info(context.TODO())
244
+	rlInfo, err := rlc.Info(ctx)
230 245
 	if err != nil {
231
-		log.G(context.TODO()).Warnf("failed to retrieve RootlessKit version: %v", err)
232
-		return
246
+		return errors.Wrap(err, "failed to retrieve RootlessKit version")
233 247
 	}
234 248
 	v.Components = append(v.Components, types.ComponentVersion{
235 249
 		Name:    "rootlesskit",
... ...
@@ -244,31 +243,54 @@ func (daemon *Daemon) fillRootlessVersion(v *types.Version) {
244 244
 
245 245
 	switch rlInfo.NetworkDriver.Driver {
246 246
 	case "slirp4netns":
247
-		if rv, err := exec.Command("slirp4netns", "--version").Output(); err == nil {
248
-			if _, ver, commit, err := parseRuntimeVersion(string(rv)); err != nil {
249
-				log.G(context.TODO()).Warnf("failed to parse slirp4netns version: %v", err)
250
-			} else {
251
-				v.Components = append(v.Components, types.ComponentVersion{
252
-					Name:    "slirp4netns",
253
-					Version: ver,
254
-					Details: map[string]string{
255
-						"GitCommit": commit,
256
-					},
257
-				})
247
+		err = func() error {
248
+			rv, err := exec.CommandContext(ctx, "slirp4netns", "--version").Output()
249
+			if err != nil {
250
+				if errdefs.IsContext(err) {
251
+					return err
252
+				}
253
+				log.G(ctx).WithError(err).Warn("Failed to retrieve slirp4netns version")
254
+				return nil
258 255
 			}
259
-		} else {
260
-			log.G(context.TODO()).Warnf("failed to retrieve slirp4netns version: %v", err)
256
+
257
+			_, ver, commit, err := parseRuntimeVersion(string(rv))
258
+			if err != nil {
259
+				log.G(ctx).WithError(err).Warn("Failed to parse slirp4netns version")
260
+				return nil
261
+			}
262
+			v.Components = append(v.Components, types.ComponentVersion{
263
+				Name:    "slirp4netns",
264
+				Version: ver,
265
+				Details: map[string]string{
266
+					"GitCommit": commit,
267
+				},
268
+			})
269
+			return nil
270
+		}()
271
+		if err != nil {
272
+			return err
261 273
 		}
262 274
 	case "vpnkit":
263
-		if rv, err := exec.Command("vpnkit", "--version").Output(); err == nil {
275
+		err = func() error {
276
+			out, err := exec.CommandContext(ctx, "vpnkit", "--version").Output()
277
+			if err != nil {
278
+				if errdefs.IsContext(err) {
279
+					return err
280
+				}
281
+				log.G(ctx).WithError(err).Warn("Failed to retrieve vpnkit version")
282
+				return nil
283
+			}
264 284
 			v.Components = append(v.Components, types.ComponentVersion{
265 285
 				Name:    "vpnkit",
266
-				Version: strings.TrimSpace(string(rv)),
286
+				Version: strings.TrimSpace(strings.TrimSpace(string(out))),
267 287
 			})
268
-		} else {
269
-			log.G(context.TODO()).Warnf("failed to retrieve vpnkit version: %v", err)
288
+			return nil
289
+		}()
290
+		if err != nil {
291
+			return err
270 292
 		}
271 293
 	}
294
+	return nil
272 295
 }
273 296
 
274 297
 // getRootlessKitClient returns RootlessKit client
... ...
@@ -384,3 +406,83 @@ func Rootless(cfg *config.Config) bool {
384 384
 func noNewPrivileges(cfg *config.Config) bool {
385 385
 	return cfg.NoNewPrivileges
386 386
 }
387
+
388
+func (daemon *Daemon) populateContainerdCommit(ctx context.Context, v *system.Commit) error {
389
+	rv, err := daemon.containerd.Version(ctx)
390
+	if err != nil {
391
+		if errdefs.IsContext(err) {
392
+			return err
393
+		}
394
+		log.G(ctx).WithError(err).Warnf("Failed to retrieve containerd version")
395
+		return nil
396
+	}
397
+	v.ID = rv.Revision
398
+	v.Expected = rv.Revision
399
+	return nil
400
+}
401
+
402
+func (daemon *Daemon) populateContainerdVersion(ctx context.Context, v *types.Version) error {
403
+	rv, err := daemon.containerd.Version(ctx)
404
+	if err != nil {
405
+		if errdefs.IsContext(err) {
406
+			return err
407
+		}
408
+		log.G(ctx).WithError(err).Warn("Failed to retrieve containerd version")
409
+		return nil
410
+	}
411
+
412
+	v.Components = append(v.Components, types.ComponentVersion{
413
+		Name:    "containerd",
414
+		Version: rv.Version,
415
+		Details: map[string]string{
416
+			"GitCommit": rv.Revision,
417
+		},
418
+	})
419
+	return nil
420
+}
421
+
422
+func populateRuncVersion(cfg *configStore, v *types.Version) error {
423
+	_, ver, commit, err := parseDefaultRuntimeVersion(&cfg.Runtimes)
424
+	if err != nil {
425
+		return err
426
+	}
427
+	v.Components = append(v.Components, types.ComponentVersion{
428
+		Name:    cfg.Runtimes.Default,
429
+		Version: ver,
430
+		Details: map[string]string{
431
+			"GitCommit": commit,
432
+		},
433
+	})
434
+	return nil
435
+}
436
+
437
+func populateInitVersion(ctx context.Context, cfg *configStore, v *types.Version) error {
438
+	initBinary, err := cfg.LookupInitPath()
439
+	if err != nil {
440
+		log.G(ctx).WithError(err).Warn("Failed to find docker-init")
441
+		return nil
442
+	}
443
+
444
+	rv, err := exec.CommandContext(ctx, initBinary, "--version").Output()
445
+	if err != nil {
446
+		if errdefs.IsContext(err) {
447
+			return err
448
+		}
449
+		log.G(ctx).WithError(err).Warnf("Failed to retrieve %s version", initBinary)
450
+		return nil
451
+	}
452
+
453
+	ver, commit, err := parseInitVersion(string(rv))
454
+	if err != nil {
455
+		log.G(ctx).WithError(err).Warnf("failed to parse %s version", initBinary)
456
+		return nil
457
+	}
458
+	v.Components = append(v.Components, types.ComponentVersion{
459
+		Name:    filepath.Base(initBinary),
460
+		Version: ver,
461
+		Details: map[string]string{
462
+			"GitCommit": commit,
463
+		},
464
+	})
465
+	return nil
466
+}
... ...
@@ -1,6 +1,8 @@
1 1
 package daemon // import "github.com/docker/docker/daemon"
2 2
 
3 3
 import (
4
+	"context"
5
+
4 6
 	"github.com/docker/docker/api/types"
5 7
 	"github.com/docker/docker/api/types/system"
6 8
 	"github.com/docker/docker/daemon/config"
... ...
@@ -8,10 +10,13 @@ import (
8 8
 )
9 9
 
10 10
 // fillPlatformInfo fills the platform related info.
11
-func (daemon *Daemon) fillPlatformInfo(v *system.Info, sysInfo *sysinfo.SysInfo, cfg *configStore) {
11
+func (daemon *Daemon) fillPlatformInfo(ctx context.Context, v *system.Info, sysInfo *sysinfo.SysInfo, cfg *configStore) error {
12
+	return nil
12 13
 }
13 14
 
14
-func (daemon *Daemon) fillPlatformVersion(v *types.Version, cfg *configStore) {}
15
+func (daemon *Daemon) fillPlatformVersion(ctx context.Context, v *types.Version, cfg *configStore) error {
16
+	return nil
17
+}
15 18
 
16 19
 func fillDriverWarnings(v *system.Info) {
17 20
 }
... ...
@@ -139,7 +139,8 @@ func (daemon *Daemon) getAllNetworks() []*libnetwork.Network {
139 139
 	if c == nil {
140 140
 		return nil
141 141
 	}
142
-	return c.Networks()
142
+	ctx := context.TODO()
143
+	return c.Networks(ctx)
143 144
 }
144 145
 
145 146
 type ingressJob struct {
... ...
@@ -465,7 +466,7 @@ func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, netwo
465 465
 
466 466
 // GetNetworkDriverList returns the list of plugins drivers
467 467
 // registered for network.
468
-func (daemon *Daemon) GetNetworkDriverList() []string {
468
+func (daemon *Daemon) GetNetworkDriverList(ctx context.Context) []string {
469 469
 	if !daemon.NetworkControllerEnabled() {
470 470
 		return nil
471 471
 	}
... ...
@@ -483,7 +484,7 @@ func (daemon *Daemon) GetNetworkDriverList() []string {
483 483
 		pluginMap[plugin] = true
484 484
 	}
485 485
 
486
-	networks := daemon.netController.Networks()
486
+	networks := daemon.netController.Networks(ctx)
487 487
 
488 488
 	for _, nw := range networks {
489 489
 		if !pluginMap[nw.Type()] {
... ...
@@ -1,5 +1,10 @@
1 1
 package errdefs
2 2
 
3
+import (
4
+	"context"
5
+	"errors"
6
+)
7
+
3 8
 type causer interface {
4 9
 	Cause() error
5 10
 }
... ...
@@ -105,3 +110,8 @@ func IsDataLoss(err error) bool {
105 105
 	_, ok := getImplementer(err).(ErrDataLoss)
106 106
 	return ok
107 107
 }
108
+
109
+// IsContext returns if the passed in error is due to context cancellation or deadline exceeded.
110
+func IsContext(err error) bool {
111
+	return errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)
112
+}
... ...
@@ -820,10 +820,10 @@ func (c *Controller) addNetwork(n *Network) error {
820 820
 }
821 821
 
822 822
 // Networks returns the list of Network(s) managed by this controller.
823
-func (c *Controller) Networks() []*Network {
823
+func (c *Controller) Networks(ctx context.Context) []*Network {
824 824
 	var list []*Network
825 825
 
826
-	for _, n := range c.getNetworksFromStore() {
826
+	for _, n := range c.getNetworksFromStore(ctx) {
827 827
 		if n.inDelete {
828 828
 			continue
829 829
 		}
... ...
@@ -835,7 +835,7 @@ func (c *Controller) Networks() []*Network {
835 835
 
836 836
 // WalkNetworks uses the provided function to walk the Network(s) managed by this controller.
837 837
 func (c *Controller) WalkNetworks(walker NetworkWalker) {
838
-	for _, n := range c.Networks() {
838
+	for _, n := range c.Networks(context.TODO()) {
839 839
 		if walker(n) {
840 840
 			return
841 841
 		}
... ...
@@ -538,7 +538,8 @@ func TestNetworkEndpointsWalkers(t *testing.T) {
538 538
 		t.Fatal(err)
539 539
 	}
540 540
 
541
-	current := len(controller.Networks())
541
+	ctx := context.TODO()
542
+	current := len(controller.Networks(ctx))
542 543
 
543 544
 	// Create network 2
544 545
 	netOption = options.Generic{
... ...
@@ -558,7 +559,7 @@ func TestNetworkEndpointsWalkers(t *testing.T) {
558 558
 	}()
559 559
 
560 560
 	// Test Networks method
561
-	if len(controller.Networks()) != current+1 {
561
+	if len(controller.Networks(ctx)) != current+1 {
562 562
 		t.Fatalf("Did not find the expected number of networks")
563 563
 	}
564 564
 
... ...
@@ -34,7 +34,7 @@ func (c *Controller) getStore() *datastore.Store {
34 34
 }
35 35
 
36 36
 func (c *Controller) getNetworkFromStore(nid string) (*Network, error) {
37
-	for _, n := range c.getNetworksFromStore() {
37
+	for _, n := range c.getNetworksFromStore(context.TODO()) {
38 38
 		if n.id == nid {
39 39
 			return n, nil
40 40
 		}
... ...
@@ -77,21 +77,21 @@ func (c *Controller) getNetworks() ([]*Network, error) {
77 77
 	return nl, nil
78 78
 }
79 79
 
80
-func (c *Controller) getNetworksFromStore() []*Network { // FIXME: unify with c.getNetworks()
80
+func (c *Controller) getNetworksFromStore(ctx context.Context) []*Network { // FIXME: unify with c.getNetworks()
81 81
 	var nl []*Network
82 82
 
83 83
 	store := c.getStore()
84 84
 	kvol, err := store.List(datastore.Key(datastore.NetworkKeyPrefix), &Network{ctrlr: c})
85 85
 	if err != nil {
86 86
 		if err != datastore.ErrKeyNotFound {
87
-			log.G(context.TODO()).Debugf("failed to get networks from store: %v", err)
87
+			log.G(ctx).Debugf("failed to get networks from store: %v", err)
88 88
 		}
89 89
 		return nil
90 90
 	}
91 91
 
92 92
 	kvep, err := store.Map(datastore.Key(epCntKeyPrefix), &endpointCnt{})
93 93
 	if err != nil && err != datastore.ErrKeyNotFound {
94
-		log.G(context.TODO()).Warnf("failed to get endpoint_count map from store: %v", err)
94
+		log.G(ctx).Warnf("failed to get endpoint_count map from store: %v", err)
95 95
 	}
96 96
 
97 97
 	for _, kvo := range kvol {
... ...
@@ -185,7 +185,7 @@ retry:
185 185
 }
186 186
 
187 187
 func (c *Controller) networkCleanup() {
188
-	for _, n := range c.getNetworksFromStore() {
188
+	for _, n := range c.getNetworksFromStore(context.TODO()) {
189 189
 		if n.inDelete {
190 190
 			log.G(context.TODO()).Infof("Removing stale network %s (%s)", n.Name(), n.ID())
191 191
 			if err := n.delete(true, true); err != nil {
... ...
@@ -6,13 +6,17 @@ import (
6 6
 	"io"
7 7
 	"os"
8 8
 
9
+	"github.com/containerd/containerd/tracing"
9 10
 	"github.com/containerd/log"
10 11
 	"golang.org/x/sys/unix"
11 12
 )
12 13
 
13 14
 // GetTotalUsedFds Returns the number of used File Descriptors by
14 15
 // reading it via /proc filesystem.
15
-func GetTotalUsedFds() int {
16
+func GetTotalUsedFds(ctx context.Context) int {
17
+	ctx, span := tracing.StartSpan(ctx, "GetTotalUsedFds")
18
+	defer span.End()
19
+
16 20
 	name := fmt.Sprintf("/proc/%d/fd", os.Getpid())
17 21
 
18 22
 	// Fast-path for Linux 6.2 (since [f1f1f2569901ec5b9d425f2e91c09a0e320768f3]).
... ...
@@ -30,19 +34,26 @@ func GetTotalUsedFds() int {
30 30
 
31 31
 	f, err := os.Open(name)
32 32
 	if err != nil {
33
-		log.G(context.TODO()).WithError(err).Error("Error listing file descriptors")
33
+		log.G(ctx).WithError(err).Error("Error listing file descriptors")
34 34
 		return -1
35 35
 	}
36 36
 	defer f.Close()
37 37
 
38 38
 	var fdCount int
39 39
 	for {
40
+		select {
41
+		case <-ctx.Done():
42
+			log.G(ctx).WithError(ctx.Err()).Error("Context cancelled while counting file descriptors")
43
+			return -1
44
+		default:
45
+		}
46
+
40 47
 		names, err := f.Readdirnames(100)
41 48
 		fdCount += len(names)
42 49
 		if err == io.EOF {
43 50
 			break
44 51
 		} else if err != nil {
45
-			log.G(context.TODO()).WithError(err).Error("Error listing file descriptors")
52
+			log.G(ctx).WithError(err).Error("Error listing file descriptors")
46 53
 			return -1
47 54
 		}
48 55
 	}
... ...
@@ -1,6 +1,7 @@
1 1
 package fileutils // import "github.com/docker/docker/pkg/fileutils"
2 2
 
3 3
 import (
4
+	"context"
4 5
 	"errors"
5 6
 	"os"
6 7
 	"path"
... ...
@@ -242,8 +243,9 @@ func TestCreateIfNotExistsFile(t *testing.T) {
242 242
 }
243 243
 
244 244
 func BenchmarkGetTotalUsedFds(b *testing.B) {
245
+	ctx := context.Background()
245 246
 	b.ReportAllocs()
246 247
 	for i := 0; i < b.N; i++ {
247
-		_ = GetTotalUsedFds()
248
+		_ = GetTotalUsedFds(ctx)
248 249
 	}
249 250
 }
... ...
@@ -1,7 +1,9 @@
1 1
 package fileutils // import "github.com/docker/docker/pkg/fileutils"
2 2
 
3
+import "context"
4
+
3 5
 // GetTotalUsedFds Returns the number of used File Descriptors. Not supported
4 6
 // on Windows.
5
-func GetTotalUsedFds() int {
7
+func GetTotalUsedFds(ctx context.Context) int {
6 8
 	return -1
7 9
 }