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.


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