@@ -19,6 +19,7 @@ package cdi
1919import (
2020 "fmt"
2121 "os"
22+ "path/filepath"
2223 "strconv"
2324 "strings"
2425 "syscall"
@@ -48,6 +49,100 @@ func TestTooManyOpenFiles(t *testing.T) {
4849 _ , _ = cache .InjectDevices (& oci.Spec {}, "vendor1.com/device=dev1" )
4950}
5051
52+ func TestRecoveryAfterTooManyOpenFiles (t * testing.T ) {
53+ var (
54+ etcDir = map [string ]string {
55+ "vendor1.yaml" : `
56+ cdiVersion: "0.3.0"
57+ kind: "vendor1.com/device"
58+ containerEdits:
59+ env:
60+ - VENDOR1_SPEC_VAR1=VAL1
61+ devices:
62+ - name: "dev1"
63+ containerEdits:
64+ env:
65+ - "VENDOR1_VAR1=VAL1"
66+ deviceNodes:
67+ - path: "/dev/vendor1-dev1"
68+ type: b
69+ major: 10
70+ minor: 1
71+ ` ,
72+ }
73+
74+ devices = []string {
75+ "vendor1.com/device=dev1" ,
76+ }
77+
78+ ociSpec = & oci.Spec {}
79+
80+ resultingSpec = & oci.Spec {
81+ Process : & oci.Process {
82+ Env : []string {
83+ "VENDOR1_SPEC_VAR1=VAL1" ,
84+ "VENDOR1_VAR1=VAL1" ,
85+ },
86+ },
87+ Linux : & oci.Linux {
88+ Devices : []oci.LinuxDevice {
89+ {
90+ Path : "/dev/vendor1-dev1" ,
91+ Type : "b" ,
92+ Major : 10 ,
93+ Minor : 1 ,
94+ },
95+ },
96+ Resources : & oci.LinuxResources {
97+ Devices : []oci.LinuxDeviceCgroup {
98+ {
99+ Allow : true ,
100+ Type : "b" ,
101+ Major : int64ptr (10 ),
102+ Minor : int64ptr (1 ),
103+ Access : "rwm" ,
104+ },
105+ },
106+ },
107+ },
108+ }
109+ )
110+
111+ dir , err := createSpecDirs (t , etcDir , nil )
112+ require .NoError (t , err , "failed to create test directory" )
113+
114+ // trigger EMFILE for fd creation: exhaust our file descriptor table
115+ em , err := triggerEmfile ()
116+ require .NoError (t , err )
117+ require .NotNil (t , em )
118+ defer func () {
119+ require .NoError (t , em .undo ())
120+ }()
121+
122+ _ , err = syscall .Socket (syscall .AF_INET , syscall .SOCK_DGRAM , 0 )
123+ require .Equal (t , syscall .EMFILE , err )
124+
125+ cache := newCache (
126+ WithSpecDirs (
127+ filepath .Join (dir , "etc" ),
128+ ),
129+ WithAutoRefresh (true ),
130+ )
131+ require .NotNil (t , cache )
132+
133+ // try to trigger original crash with a nil fsnotify.Watcher
134+ _ , _ = cache .InjectDevices (& oci.Spec {}, devices ... )
135+
136+ // undo EMFILE for fd creation
137+ require .NoError (t , em .undo ())
138+
139+ // verify that injection works again
140+ unresolved , err := cache .InjectDevices (ociSpec , devices ... )
141+ require .NoError (t , err )
142+ require .Nil (t , unresolved )
143+ require .Equal (t , resultingSpec , ociSpec )
144+ }
145+
51146type emfile struct {
52147 limit syscall.Rlimit
53148 fds []int
0 commit comments