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.


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