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.


e826296e1339bb890f95c8d83c2b3a599e30d71e
[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 (!dentry || IS_ERR(dentry)) {
165             return 0;
166         }
167         
168         path_ptr = &tmp_path;
169     }
170 #endif    
171
172
173     if (!(!dentry || 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, 0600);  // rw------- to start
222     
223     if (!pfile->filp || 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     if (!pfile) {
256         return -1;
257     }
258
259     filp_close(pfile->filp, NULL);
260     
261     list_del(&(pfile->file_node));
262
263     palacios_spinlock_deinit(&(pfile->lock));
264
265     palacios_free(pfile->path);    
266     palacios_free(pfile);
267
268     return 0;
269 }
270
271 static unsigned long long palacios_file_size(void * file_ptr) {
272     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
273     struct file * filp = pfile->filp;
274     struct kstat s;
275     int ret;
276     
277     ret = vfs_getattr(filp->f_path.mnt, filp->f_path.dentry, &s);
278
279     if (ret != 0) {
280         ERROR("Failed to fstat file\n");
281         return -1;
282     }
283
284     return s.size;
285 }
286
287 static unsigned long long palacios_file_read(void * file_ptr, void * buffer, unsigned long long length, unsigned long long offset){
288     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
289     struct file * filp = pfile->filp;
290     ssize_t ret;
291     mm_segment_t old_fs;
292         
293     old_fs = get_fs();
294     set_fs(get_ds());
295         
296     ret = vfs_read(filp, buffer, length, &offset);
297         
298     set_fs(old_fs);
299         
300     if (ret <= 0) {
301         ERROR("sys_read of %p for %lld bytes at offset %llu failed (ret=%ld)\n", filp, length, offset, ret);
302     }
303         
304     return ret;
305 }
306
307
308 static unsigned long long palacios_file_write(void * file_ptr, void * buffer, unsigned long long length, unsigned long long offset) {
309     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
310     struct file * filp = pfile->filp;
311     mm_segment_t old_fs;
312     ssize_t ret;
313
314     old_fs = get_fs();
315     set_fs(get_ds());
316
317     ret = vfs_write(filp, buffer, length, &offset);
318         
319     set_fs(old_fs);
320
321  
322     if (ret <= 0) {
323         ERROR("sys_write for %llu bytes at offset %llu failed (ret=%ld)\n", length, offset, ret);
324     }
325         
326     return ret;
327 }
328
329
330 static struct v3_file_hooks palacios_file_hooks = {
331         .open           = palacios_file_open,
332         .close          = palacios_file_close,
333         .read           = palacios_file_read,
334         .write          = palacios_file_write,
335         .size           = palacios_file_size,
336         .mkdir          = palacios_file_mkdir,
337 };
338
339
340
341 static int file_init( void ) {
342     INIT_LIST_HEAD(&(global_files));
343
344     V3_Init_File(&palacios_file_hooks);
345
346     return 0;
347 }
348
349
350 static int file_deinit( void ) {
351     struct palacios_file * pfile = NULL;
352     struct palacios_file * tmp = NULL;
353     
354     list_for_each_entry_safe(pfile, tmp, &(global_files), file_node) { 
355         filp_close(pfile->filp, NULL);
356         list_del(&(pfile->file_node));
357         palacios_free(pfile->path);    
358         palacios_free(pfile);
359     }
360
361     return 0;
362 }
363
364 static int guest_file_init(struct v3_guest * guest, void ** vm_data) {
365     struct vm_file_state * state = palacios_alloc(sizeof(struct vm_file_state));
366
367     if (!state) {
368         ERROR("Cannot allocate when intializing file services for guest\n");
369         return -1;
370     }
371         
372     
373     INIT_LIST_HEAD(&(state->open_files));
374
375     *vm_data = state;
376
377
378     return 0;
379 }
380
381
382 static int guest_file_deinit(struct v3_guest * guest, void * vm_data) {
383     struct vm_file_state * state = (struct vm_file_state *)vm_data;
384     struct palacios_file * pfile = NULL;
385     struct palacios_file * tmp = NULL;
386     
387     list_for_each_entry_safe(pfile, tmp, &(state->open_files), file_node) { 
388         filp_close(pfile->filp, NULL);
389         list_del(&(pfile->file_node));
390         palacios_free(pfile->path);    
391         palacios_free(pfile);
392     }
393
394     palacios_free(state);
395     return 0;
396 }
397
398
399 static struct linux_ext file_ext = {
400     .name = "FILE_INTERFACE",
401     .init = file_init, 
402     .deinit = file_deinit,
403     .guest_init = guest_file_init,
404     .guest_deinit = guest_file_deinit
405 };
406
407
408 register_extension(&file_ext);