@@ -65,3 +65,134 @@ impl InodeStore {
6565 self . by_handle . get ( handle)
6666 }
6767}
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