@@ -65,3 +65,134 @@ impl InodeStore {
65
65
self . by_handle . get ( handle)
66
66
}
67
67
}
68
+
69
+ #[ cfg( test) ]
70
+ mod test {
71
+ use super :: super :: * ;
72
+ use super :: * ;
73
+
74
+ use std:: ffi:: CStr ;
75
+ use std:: os:: unix:: io:: { AsRawFd , RawFd } ;
76
+ use std:: sync:: atomic:: Ordering ;
77
+ use vmm_sys_util:: tempfile:: TempFile ;
78
+
79
+ impl PartialEq for InodeData {
80
+ fn eq ( & self , other : & Self ) -> bool {
81
+ if self . inode != other. inode
82
+ || self . altkey != other. altkey
83
+ || self . mode != other. mode
84
+ || self . refcount . load ( Ordering :: Relaxed ) != other. refcount . load ( Ordering :: Relaxed )
85
+ {
86
+ return false ;
87
+ }
88
+
89
+ match ( & self . file_or_handle , & other. file_or_handle ) {
90
+ ( FileOrHandle :: File ( f1) , FileOrHandle :: File ( f2) ) => {
91
+ f1. as_raw_fd ( ) == f2. as_raw_fd ( )
92
+ }
93
+ ( FileOrHandle :: Handle ( h1) , FileOrHandle :: Handle ( h2) ) => h1 == h2,
94
+ _ => false ,
95
+ }
96
+ }
97
+ }
98
+
99
+ fn stat_fd ( fd : RawFd ) -> io:: Result < libc:: stat64 > {
100
+ let mut st = MaybeUninit :: < libc:: stat64 > :: zeroed ( ) ;
101
+ let null_path = unsafe { CStr :: from_bytes_with_nul_unchecked ( b"\0 " ) } ;
102
+
103
+ // Safe because the kernel will only write data in `st` and we check the return value.
104
+ let res = unsafe {
105
+ libc:: fstatat64 (
106
+ fd,
107
+ null_path. as_ptr ( ) ,
108
+ st. as_mut_ptr ( ) ,
109
+ libc:: AT_EMPTY_PATH | libc:: AT_SYMLINK_NOFOLLOW ,
110
+ )
111
+ } ;
112
+ if res >= 0 {
113
+ // Safe because the kernel guarantees that the struct is now fully initialized.
114
+ Ok ( unsafe { st. assume_init ( ) } )
115
+ } else {
116
+ Err ( io:: Error :: last_os_error ( ) )
117
+ }
118
+ }
119
+
120
+ #[ test]
121
+ fn test_inode_store ( ) {
122
+ let mut m = InodeStore :: default ( ) ;
123
+ let tmpfile1 = TempFile :: new ( ) . unwrap ( ) ;
124
+ let tmpfile2 = TempFile :: new ( ) . unwrap ( ) ;
125
+
126
+ let inode1: Inode = 3 ;
127
+ let inode2: Inode = 4 ;
128
+ let inode_stat1 = InodeStat {
129
+ stat : stat_fd ( tmpfile1. as_file ( ) . as_raw_fd ( ) ) . unwrap ( ) ,
130
+ mnt_id : 0 ,
131
+ } ;
132
+ let inode_stat2 = InodeStat {
133
+ stat : stat_fd ( tmpfile2. as_file ( ) . as_raw_fd ( ) ) . unwrap ( ) ,
134
+ mnt_id : 0 ,
135
+ } ;
136
+ let ids1 = InodeAltKey :: ids_from_stat ( & inode_stat1) ;
137
+ let ids2 = InodeAltKey :: ids_from_stat ( & inode_stat2) ;
138
+ let file_or_handle1 = FileOrHandle :: File ( tmpfile1. into_file ( ) ) ;
139
+ let file_or_handle2 = FileOrHandle :: File ( tmpfile2. into_file ( ) ) ;
140
+ let data1 = InodeData :: new (
141
+ inode1,
142
+ file_or_handle1,
143
+ 2 ,
144
+ ids1,
145
+ inode_stat1. get_stat ( ) . st_mode ,
146
+ ) ;
147
+ let data2 = InodeData :: new (
148
+ inode2,
149
+ file_or_handle2,
150
+ 2 ,
151
+ ids2,
152
+ inode_stat2. get_stat ( ) . st_mode ,
153
+ ) ;
154
+ let data1 = Arc :: new ( data1) ;
155
+ let data2 = Arc :: new ( data2) ;
156
+
157
+ m. insert ( data1. clone ( ) ) ;
158
+
159
+ // get not present key, expect none
160
+ assert ! ( m. get( & 1 ) . is_none( ) ) ;
161
+
162
+ // get just inserted value by key, by id, by handle
163
+ assert ! ( m. get_by_ids( & InodeAltKey :: default ( ) ) . is_none( ) ) ;
164
+ assert ! ( m. get_by_handle( & FileHandle :: default ( ) ) . is_none( ) ) ;
165
+ assert_eq ! ( m. get( & inode1) . unwrap( ) , & data1) ;
166
+ assert_eq ! ( m. get_by_ids( & ids1) . unwrap( ) , & data1) ;
167
+
168
+ // insert another value, and check again
169
+ m. insert ( data2. clone ( ) ) ;
170
+ assert ! ( m. get( & 1 ) . is_none( ) ) ;
171
+ assert ! ( m. get_by_ids( & InodeAltKey :: default ( ) ) . is_none( ) ) ;
172
+ assert ! ( m. get_by_handle( & FileHandle :: default ( ) ) . is_none( ) ) ;
173
+ assert_eq ! ( m. get( & inode1) . unwrap( ) , & data1) ;
174
+ assert_eq ! ( m. get_by_ids( & ids1) . unwrap( ) , & data1) ;
175
+ assert_eq ! ( m. get( & inode2) . unwrap( ) , & data2) ;
176
+ assert_eq ! ( m. get_by_ids( & ids2) . unwrap( ) , & data2) ;
177
+
178
+ // remove non-present key
179
+ assert ! ( m. remove( & 1 ) . is_none( ) ) ;
180
+
181
+ // remove present key, return its value
182
+ assert_eq ! ( m. remove( & inode1) . unwrap( ) , data1. clone( ) ) ;
183
+ assert ! ( m. get( & inode1) . is_none( ) ) ;
184
+ assert ! ( m. get_by_ids( & ids1) . is_none( ) ) ;
185
+ assert_eq ! ( m. get( & inode2) . unwrap( ) , & data2) ;
186
+ assert_eq ! ( m. get_by_ids( & ids2) . unwrap( ) , & data2) ;
187
+
188
+ // clear the map
189
+ m. clear ( ) ;
190
+ assert ! ( m. get( & 1 ) . is_none( ) ) ;
191
+ assert ! ( m. get_by_ids( & InodeAltKey :: default ( ) ) . is_none( ) ) ;
192
+ assert ! ( m. get_by_handle( & FileHandle :: default ( ) ) . is_none( ) ) ;
193
+ assert ! ( m. get( & inode1) . is_none( ) ) ;
194
+ assert ! ( m. get_by_ids( & ids1) . is_none( ) ) ;
195
+ assert ! ( m. get( & inode2) . is_none( ) ) ;
196
+ assert ! ( m. get_by_ids( & ids2) . is_none( ) ) ;
197
+ }
198
+ }
0 commit comments