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.


Extensive, Pedantic Error Checking in Linux module, especially for memory
[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     spin_lock_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_free(pfile->path);    
260     palacios_free(pfile);
261
262     return 0;
263 }
264
265 static unsigned long long palacios_file_size(void * file_ptr) {
266     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
267     struct file * filp = pfile->filp;
268     struct kstat s;
269     int ret;
270     
271     ret = vfs_getattr(filp->f_path.mnt, filp->f_path.dentry, &s);
272
273     if (ret != 0) {
274         ERROR("Failed to fstat file\n");
275         return -1;
276     }
277
278     return s.size;
279 }
280
281 static unsigned long long palacios_file_read(void * file_ptr, void * buffer, unsigned long long length, unsigned long long offset){
282     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
283     struct file * filp = pfile->filp;
284     ssize_t ret;
285     mm_segment_t old_fs;
286         
287     old_fs = get_fs();
288     set_fs(get_ds());
289         
290     ret = vfs_read(filp, buffer, length, &offset);
291         
292     set_fs(old_fs);
293         
294     if (ret <= 0) {
295         ERROR("sys_read of %p for %lld bytes at offset %llu failed (ret=%ld)\n", filp, length, offset, ret);
296     }
297         
298     return ret;
299 }
300
301
302 static unsigned long long palacios_file_write(void * file_ptr, void * buffer, unsigned long long length, unsigned long long offset) {
303     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
304     struct file * filp = pfile->filp;
305     mm_segment_t old_fs;
306     ssize_t ret;
307
308     old_fs = get_fs();
309     set_fs(get_ds());
310
311     ret = vfs_write(filp, buffer, length, &offset);
312         
313     set_fs(old_fs);
314
315  
316     if (ret <= 0) {
317         ERROR("sys_write for %llu bytes at offset %llu failed (ret=%ld)\n", length, offset, ret);
318     }
319         
320     return ret;
321 }
322
323
324 static struct v3_file_hooks palacios_file_hooks = {
325         .open           = palacios_file_open,
326         .close          = palacios_file_close,
327         .read           = palacios_file_read,
328         .write          = palacios_file_write,
329         .size           = palacios_file_size,
330         .mkdir          = palacios_file_mkdir,
331 };
332
333
334
335 static int file_init( void ) {
336     INIT_LIST_HEAD(&(global_files));
337
338     V3_Init_File(&palacios_file_hooks);
339
340     return 0;
341 }
342
343
344 static int file_deinit( void ) {
345     if (!list_empty(&(global_files))) {
346         ERROR("Error removing module with open files\n");
347     }
348
349     return 0;
350 }
351
352 static int guest_file_init(struct v3_guest * guest, void ** vm_data) {
353     struct vm_file_state * state = palacios_alloc(sizeof(struct vm_file_state));
354
355     if (!state) {
356         ERROR("Cannot allocate when intializing file services for guest\n");
357         return -1;
358     }
359         
360     
361     INIT_LIST_HEAD(&(state->open_files));
362
363     *vm_data = state;
364
365
366     return 0;
367 }
368
369
370 static int guest_file_deinit(struct v3_guest * guest, void * vm_data) {
371     
372     palacios_free(vm_data);
373
374     return 0;
375 }
376
377
378 static struct linux_ext file_ext = {
379     .name = "FILE_INTERFACE",
380     .init = file_init, 
381     .deinit = file_deinit,
382     .guest_init = guest_file_init,
383     .guest_deinit = guest_file_deinit
384 };
385
386
387 register_extension(&file_ext);