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.


96a247765c6fd65311ca786c22d44986c4491c32
[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->filp = filp_open(path, pfile->mode, 0);
208     
209     if (pfile->filp == NULL) {
210         printk("Cannot open file: %s\n", path);
211         return NULL;
212     }
213
214     pfile->path = kmalloc(strlen(path) + 1, GFP_KERNEL);
215     strncpy(pfile->path, path, strlen(path));
216     pfile->guest = guest;
217     
218     spin_lock_init(&(pfile->lock));
219
220     if (guest == NULL) {
221         list_add(&(pfile->file_node), &(global_files));
222     } else {
223         list_add(&(pfile->file_node), &(vm_state->open_files));
224     } 
225
226
227     return pfile;
228 }
229
230 static int palacios_file_close(void * file_ptr) {
231     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
232
233     filp_close(pfile->filp, NULL);
234     
235     list_del(&(pfile->file_node));
236
237     kfree(pfile->path);    
238     kfree(pfile);
239
240     return 0;
241 }
242
243 static long long palacios_file_size(void * file_ptr) {
244     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
245     struct file * filp = pfile->filp;
246     struct kstat s;
247     int ret;
248     
249     ret = vfs_getattr(filp->f_path.mnt, filp->f_path.dentry, &s);
250
251     if (ret != 0) {
252         printk("Failed to fstat file\n");
253         return -1;
254     }
255
256     return s.size;
257 }
258
259 static long long palacios_file_read(void * file_ptr, void * buffer, long long length, long long offset){
260     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
261     struct file * filp = pfile->filp;
262     ssize_t ret;
263     mm_segment_t old_fs;
264         
265     old_fs = get_fs();
266     set_fs(get_ds());
267         
268     ret = vfs_read(filp, buffer, length, &offset);
269         
270     set_fs(old_fs);
271         
272     if (ret <= 0) {
273         printk("sys_read of %p for %lld bytes failed\n", filp, length);         
274     }
275         
276     return ret;
277 }
278
279
280 static long long palacios_file_write(void * file_ptr, void * buffer, long long length, long long offset) {
281     struct palacios_file * pfile = (struct palacios_file *)file_ptr;
282     struct file * filp = pfile->filp;
283     mm_segment_t old_fs;
284     ssize_t ret;
285
286     old_fs = get_fs();
287     set_fs(get_ds());
288
289     ret = vfs_write(filp, buffer, length, &offset);
290         
291     set_fs(old_fs);
292
293  
294     if (ret <= 0) {
295         printk("sys_write failed\n");           
296     }
297         
298     return ret;
299 }
300
301
302 static struct v3_file_hooks palacios_file_hooks = {
303         .open           = palacios_file_open,
304         .close          = palacios_file_close,
305         .read           = palacios_file_read,
306         .write          = palacios_file_write,
307         .size           = palacios_file_size,
308         .mkdir          = palacios_file_mkdir,
309 };
310
311
312
313 static int file_init( void ) {
314     INIT_LIST_HEAD(&(global_files));
315
316     V3_Init_File(&palacios_file_hooks);
317
318     return 0;
319 }
320
321
322 static int file_deinit( void ) {
323     if (!list_empty(&(global_files))) {
324         printk("Error removing module with open files\n");
325     }
326
327     return 0;
328 }
329
330 static int guest_file_init(struct v3_guest * guest, void ** vm_data) {
331     struct vm_file_state * state = kmalloc(sizeof(struct vm_file_state), GFP_KERNEL);
332     
333     INIT_LIST_HEAD(&(state->open_files));
334
335     *vm_data = state;
336
337
338     return 0;
339 }
340
341
342 static int guest_file_deinit(struct v3_guest * guest, void * vm_data) {
343     
344     return 0;
345 }
346
347
348 static struct linux_ext file_ext = {
349     .name = "FILE_INTERFACE",
350     .init = file_init, 
351     .deinit = file_deinit,
352     .guest_init = guest_file_init,
353     .guest_deinit = guest_file_deinit
354 };
355
356
357 register_extension(&file_ext);