1 /* Palacios file interface
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>
15 #include "linux-exts.h"
17 #include <interfaces/vmm_file.h>
19 static struct list_head global_files;
21 #define isprint(a) ((a >= ' ') && (a <= '~'))
23 struct palacios_file {
31 struct v3_guest * guest;
34 struct list_head file_node;
38 // Currently this just holds the list of open files
39 struct vm_file_state {
40 struct list_head open_files;
45 static int palacios_file_mkdir(const char * pathname, unsigned short perms, int recurse);
47 static int mkdir_recursive(const char * path, unsigned short perms) {
48 char * tmp_str = NULL;
52 tmp_str = kmalloc(strlen(path) + 1, GFP_KERNEL);
53 memset(tmp_str, 0, strlen(path) + 1);
54 strncpy(tmp_str, path, strlen(path));
56 dirname_ptr = tmp_str;
59 // parse path string, call palacios_file_mkdir recursively.
62 while (dirname_ptr != NULL) {
65 while ((*tmp_iter != '/') &&
66 (*tmp_iter != '\0')) {
68 if ( (!isprint(*tmp_iter))) {
69 printk("Invalid character in path name (%d)\n", *tmp_iter);
76 if (*tmp_iter == '/') {
82 // Ignore empty directories
83 if ((tmp_iter - dirname_ptr) > 1) {
84 palacios_file_mkdir(tmp_str, perms, 0);
95 dirname_ptr = tmp_iter;
103 static int palacios_file_mkdir(const char * pathname, unsigned short perms, int recurse) {
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;
111 struct path * path_ptr = NULL;
112 struct dentry * dentry;
118 return mkdir_recursive(pathname, perms);
121 /* Before Linux 3.1 this was somewhat more difficult */
122 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)
125 ret = kern_path_parent(pathname, &nd);
128 printk("%s:%d - Error: kern_path_parent() returned error for (%s)\n", __FILE__, __LINE__,
133 dentry = lookup_create(&nd, 1);
134 path_ptr = &(nd.path);
138 dentry = kern_path_create(AT_FDCWD, pathname, &tmp_path, 1);
140 if (IS_ERR(dentry)) {
144 path_ptr = &tmp_path;
149 if (!IS_ERR(dentry)) {
150 ret = vfs_mkdir(path_ptr->dentry->d_inode, dentry, perms);
153 mutex_unlock(&(path_ptr->dentry->d_inode->i_mutex));
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;
165 vm_state = get_vm_ext_data(guest, "FILE_INTERFACE");
167 if (vm_state == NULL) {
168 printk("ERROR: Could not locate vm file state for extension FILE_INTERFACE\n");
173 pfile = kmalloc(sizeof(struct palacios_file), GFP_KERNEL);
174 memset(pfile, 0, sizeof(struct palacios_file));
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;
184 if (mode & FILE_OPEN_MODE_CREATE) {
185 pfile->mode |= O_CREAT;
189 pfile->filp = filp_open(path, pfile->mode, 0);
191 if (pfile->filp == NULL) {
192 printk("Cannot open file: %s\n", path);
196 pfile->path = kmalloc(strlen(path) + 1, GFP_KERNEL);
197 strncpy(pfile->path, path, strlen(path));
198 pfile->guest = guest;
200 spin_lock_init(&(pfile->lock));
203 list_add(&(pfile->file_node), &(global_files));
205 list_add(&(pfile->file_node), &(vm_state->open_files));
212 static int palacios_file_close(void * file_ptr) {
213 struct palacios_file * pfile = (struct palacios_file *)file_ptr;
215 filp_close(pfile->filp, NULL);
217 list_del(&(pfile->file_node));
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;
231 ret = vfs_getattr(filp->f_path.mnt, filp->f_path.dentry, &s);
234 printk("Failed to fstat file\n");
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;
250 ret = vfs_read(filp, buffer, length, &offset);
255 printk("sys_read of %p for %lld bytes failed\n", filp, length);
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;
271 ret = vfs_write(filp, buffer, length, &offset);
277 printk("sys_write failed\n");
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,
295 static int file_init( void ) {
296 INIT_LIST_HEAD(&(global_files));
298 V3_Init_File(&palacios_file_hooks);
304 static int file_deinit( void ) {
305 if (!list_empty(&(global_files))) {
306 printk("Error removing module with open files\n");
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);
315 INIT_LIST_HEAD(&(state->open_files));
323 static int guest_file_deinit(struct v3_guest * guest, void * vm_data) {
329 static struct linux_ext file_ext = {
330 .name = "FILE_INTERFACE",
332 .deinit = file_deinit,
333 .guest_init = guest_file_init,
334 .guest_deinit = guest_file_deinit
338 register_extension(&file_ext);