@@ -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