Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Lock bugfixes - missing lock deinits This also adds deinit calls in the linux_module...
[palacios.git] / linux_module / iface-file.c
1 /* Palacios file interface 
2  * (c) Jack Lange, 2010
3  */
4
5
6 #include <linux/fs.h>
7 #include <linux/namei.h>
8 #include <linux/version.h>
9 #include <linux/file.h>
10 #include <linux/spinlock.h>
11 #include <linux/uaccess.h>
12 #include <linux/module.h>
13
14 #include "palacios.h"
15 #include "linux-exts.h"
16
17 #include <interfaces/vmm_file.h>
18
19 static struct list_head global_files;
20
21 #define isprint(a) ((a >= ' ') && (a <= '~'))
22
23 struct palacios_file {
24     struct file * filp;
25
26     char * path;
27     int mode;
28     
29     spinlock_t lock;
30
31     struct v3_guest * guest;
32     
33
34     struct list_head file_node;
35 };
36
37
38 // Currently this just holds the list of open files
39 struct vm_file_state {
40     struct list_head open_files;
41 };
42
43
44
45 static int palacios_file_mkdir(const char * pathname, unsigned short perms, int recurse);
46
47 static int mkdir_recursive(const char * path, unsigned short perms) {
48     char * tmp_str = NULL;
49     char * dirname_ptr;
50     char * tmp_iter;
51
52     tmp_str = palacios_alloc(strlen(path) + 1);
53     if (!tmp_str) { 
54         ERROR("Cannot allocate in mkdir recursive\n");
55         return -1;
56     }
57
58     memset(tmp_str, 0, strlen(path) + 1);
59     strncpy(tmp_str, path, strlen(path));
60
61     dirname_ptr = tmp_str;
62     tmp_iter = tmp_str;
63
64     // parse path string, call palacios_file_mkdir recursively.
65
66
67     while (dirname_ptr != NULL) {
68         int done = 0;
69
70         while ((*tmp_iter != '/') && 
71                (*tmp_iter != '\0')) {
72
73             if ( (!isprint(*tmp_iter))) {
74                 ERROR("Invalid character in path name (%d)\n", *tmp_iter);
75                 palacios_free(tmp_str);
76                 return -1;
77             } else {
78                 tmp_iter++;
79             }
80         }
81
82         if (*tmp_iter == '/') {
83             *tmp_iter = '\0';
84         } else {
85             done = 1;
86         }
87
88         // Ignore empty directories
89         if ((tmp_iter - dirname_ptr) > 1) {
90             if (palacios_file_mkdir(tmp_str, perms, 0) != 0) {
91                 ERROR("Could not create directory (%s)\n", tmp_str);
92                 palacios_free(tmp_str);
93                 return -1;
94             }
95         }
96
97         if (done) {
98             break;
99         } else {
100             *tmp_iter = '/';
101         }
102         
103         tmp_iter++;
104
105         dirname_ptr = tmp_iter;
106     }
107     
108     palacios_free(tmp_str);
109
110     return 0;
111 }
112
113 static int palacios_file_mkdir(const char * pathname, unsigned short perms, int recurse) {
114     /* Welcome to the jungle... */
115
116 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,41)
117     /* DO NOT REFERENCE THIS VARIABLE */
118     /* It only exists to provide version compatibility */
119     struct path tmp_path; 
120 #endif
121
122     struct path * path_ptr = NULL;
123     struct dentry * dentry;
124     int ret = 0;
125
126
127
128     if (recurse != 0) {
129         return mkdir_recursive(pathname, perms);
130     } 
131
132     /* Before Linux 3.1 this was somewhat more difficult */
133 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,41)
134     {
135         struct nameidata nd;
136
137         // I'm not 100% sure about the version here, but it was around this time that the API changed
138 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,38) 
139         ret = kern_path_parent(pathname, &nd);
140 #else 
141
142         if (path_lookup(pathname, LOOKUP_DIRECTORY | LOOKUP_FOLLOW, &nd) == 0) {
143             return 0;
144         }
145
146         if (path_lookup(pathname, LOOKUP_PARENT | LOOKUP_FOLLOW, &nd) != 0) {
147             return -1;
148         }
149 #endif
150
151         if (ret != 0) {
152             ERROR("%s:%d - Error: kern_path_parent() returned error for (%s)\n", __FILE__, __LINE__, 
153                    pathname);
154             return -1;
155         }
156         
157         dentry = lookup_create(&nd, 1);
158         path_ptr = &(nd.path);
159     }
160 #else 
161     {
162         dentry = kern_path_create(AT_FDCWD, pathname, &tmp_path, 1);
163         
164         if (IS_ERR(dentry)) {
165             return 0;
166         }
167         
168         path_ptr = &tmp_path;
169     }
170 #endif    
171
172
173     if (!IS_ERR(dentry)) {
174         ret = vfs_mkdir(path_ptr->dentry->d_inode, dentry, perms);
175     }
176
177     mutex_unlock(&(path_ptr->dentry->d_inode->i_mutex));
178     path_put(path_ptr);
179
180     return ret;
181 }
182
183
184 static void * palacios_file_open(const char * path, int mode, void * private_data) {
185     struct v3_guest * guest = (struct v3_guest *)private_data;
186     struct palacios_file * pfile = NULL;        
187     struct vm_file_state * vm_state = NULL;
188
189     if (guest != NULL) {
190         vm_state = get_vm_ext_data(guest, "FILE_INTERFACE");
191         
192         if (vm_state == NULL) {
193             ERROR("ERROR: Could not locate vm file state for extension FILE_INTERFACE\n");
194             return NULL;
195         }
196     }
197     
198     pfile = palacios_alloc(sizeof(struct palacios_file));
199     if (!pfile) { 
200         ERROR("Cannot allocate in file open\n");
201         return NULL;
202     }
203     memset(pfile, 0, sizeof(struct palacios_file));
204
205     if ((mode & FILE_OPEN_MODE_READ) && (mode & FILE_OPEN_MODE_WRITE)) { 
206         pfile->mode = O_RDWR;
207     } else if (mode & FILE_OPEN_MODE_READ) { 
208         pfile->mode = O_RDONLY;
209     } else if (mode & FILE_OPEN_MODE_WRITE) { 
210         pfile->mode = O_WRONLY;
211     } 
212     
213     if (mode & FILE_OPEN_MODE_CREATE) {
214         pfile->mode |= O_CREAT;
215     }
216
217
218     pfile->mode |= O_LARGEFILE;
219
220
221     pfile->filp = filp_open(path, pfile->mode, 0);
222     
223     if (IS_ERR(pfile->filp)) {
224         ERROR("Cannot open file: %s\n", path);
225         palacios_free(pfile);
226         return NULL;
227     }
228
229     pfile->path = palacios_alloc(strlen(path));
230     
231     if (!pfile->path) { 
232         ERROR("Cannot allocate in file open\n");
233         filp_close(pfile->filp,NULL);
234         palacios_free(pfile);
235         return NULL;
236     }
237     strncpy(pfile->path, path, strlen(path));
238     pfile->guest = guest;
239     
240     palacios_spinlock_init(&(pfile->lock));
241
242     if (guest == NULL) {
243         list_add(&(pfile->file_node), &(global_files));
244     } else {
245         list_add(&(pfile->file_node), &(vm_state->open_files));
246     } 
247
248
249     return pfile;
250 }
251
252 static int palacios_file_close(void * file_ptr) {
253     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
254
255     filp_close(pfile->filp, NULL);
256     
257     list_del(&(pfile->file_node));
258
259     palacios_spinlock_deinit(&(pfile->lock));
260
261     palacios_free(pfile->path);    
262     palacios_free(pfile);
263
264     return 0;
265 }
266
267 static unsigned long long palacios_file_size(void * file_ptr) {
268     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
269     struct file * filp = pfile->filp;
270     struct kstat s;
271     int ret;
272     
273     ret = vfs_getattr(filp->f_path.mnt, filp->f_path.dentry, &s);
274
275     if (ret != 0) {
276         ERROR("Failed to fstat file\n");
277         return -1;
278     }
279
280     return s.size;
281 }
282
283 static unsigned long long palacios_file_read(void * file_ptr, void * buffer, unsigned long long length, unsigned long long offset){
284     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
285     struct file * filp = pfile->filp;
286     ssize_t ret;
287     mm_segment_t old_fs;
288         
289     old_fs = get_fs();
290     set_fs(get_ds());
291         
292     ret = vfs_read(filp, buffer, length, &offset);
293         
294     set_fs(old_fs);
295         
296     if (ret <= 0) {
297         ERROR("sys_read of %p for %lld bytes at offset %llu failed (ret=%ld)\n", filp, length, offset, ret);
298     }
299         
300     return ret;
301 }
302
303
304 static unsigned long long palacios_file_write(void * file_ptr, void * buffer, unsigned long long length, unsigned long long offset) {
305     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
306     struct file * filp = pfile->filp;
307     mm_segment_t old_fs;
308     ssize_t ret;
309
310     old_fs = get_fs();
311     set_fs(get_ds());
312
313     ret = vfs_write(filp, buffer, length, &offset);
314         
315     set_fs(old_fs);
316
317  
318     if (ret <= 0) {
319         ERROR("sys_write for %llu bytes at offset %llu failed (ret=%ld)\n", length, offset, ret);
320     }
321         
322     return ret;
323 }
324
325
326 static struct v3_file_hooks palacios_file_hooks = {
327         .open           = palacios_file_open,
328         .close          = palacios_file_close,
329         .read           = palacios_file_read,
330         .write          = palacios_file_write,
331         .size           = palacios_file_size,
332         .mkdir          = palacios_file_mkdir,
333 };
334
335
336
337 static int file_init( void ) {
338     INIT_LIST_HEAD(&(global_files));
339
340     V3_Init_File(&palacios_file_hooks);
341
342     return 0;
343 }
344
345
346 static int file_deinit( void ) {
347     struct palacios_file * pfile = NULL;
348     struct palacios_file * tmp = NULL;
349     
350     list_for_each_entry_safe(pfile, tmp, &(global_files), file_node) { 
351         filp_close(pfile->filp, NULL);
352         list_del(&(pfile->file_node));
353         palacios_free(pfile->path);    
354         palacios_free(pfile);
355     }
356
357     return 0;
358 }
359
360 static int guest_file_init(struct v3_guest * guest, void ** vm_data) {
361     struct vm_file_state * state = palacios_alloc(sizeof(struct vm_file_state));
362
363     if (!state) {
364         ERROR("Cannot allocate when intializing file services for guest\n");
365         return -1;
366     }
367         
368     
369     INIT_LIST_HEAD(&(state->open_files));
370
371     *vm_data = state;
372
373
374     return 0;
375 }
376
377
378 static int guest_file_deinit(struct v3_guest * guest, void * vm_data) {
379     struct vm_file_state * state = (struct vm_file_state *)vm_data;
380     struct palacios_file * pfile = NULL;
381     struct palacios_file * tmp = NULL;
382     
383     list_for_each_entry_safe(pfile, tmp, &(state->open_files), file_node) { 
384         filp_close(pfile->filp, NULL);
385         list_del(&(pfile->file_node));
386         palacios_free(pfile->path);    
387         palacios_free(pfile);
388     }
389
390     palacios_free(state);
391     return 0;
392 }
393
394
395 static struct linux_ext file_ext = {
396     .name = "FILE_INTERFACE",
397     .init = file_init, 
398     .deinit = file_deinit,
399     .guest_init = guest_file_init,
400     .guest_deinit = guest_file_deinit
401 };
402
403
404 register_extension(&file_ext);