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.


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