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 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)
24 #define PAL_VFS_GETATTR(path, kstat) vfs_getattr((path)->mnt, (path)->dentry, kstat)
26 #define PAL_VFS_GETATTR(path, kstat) vfs_getattr(path, kstat)
29 struct palacios_file {
37 struct v3_guest * guest;
40 struct list_head file_node;
44 // Currently this just holds the list of open files
45 struct vm_file_state {
46 struct list_head open_files;
51 static int palacios_file_mkdir(const char * pathname, unsigned short perms, int recurse);
53 static int mkdir_recursive(const char * path, unsigned short perms) {
54 char * tmp_str = NULL;
58 tmp_str = palacios_alloc(strlen(path) + 1);
60 ERROR("Cannot allocate in mkdir recursive\n");
64 memset(tmp_str, 0, strlen(path) + 1);
65 // will terminate tmp_str
66 strncpy(tmp_str, path, strlen(path));
68 dirname_ptr = tmp_str;
71 // parse path string, call palacios_file_mkdir recursively.
74 while (dirname_ptr != NULL) {
77 while ((*tmp_iter != '/') &&
78 (*tmp_iter != '\0')) {
80 if ( (!isprint(*tmp_iter))) {
81 ERROR("Invalid character in path name (%d)\n", *tmp_iter);
82 palacios_free(tmp_str);
89 if (*tmp_iter == '/') {
95 // Ignore empty directories
96 if ((tmp_iter - dirname_ptr) > 1) {
97 if (palacios_file_mkdir(tmp_str, perms, 0) != 0) {
98 ERROR("Could not create directory (%s)\n", tmp_str);
99 palacios_free(tmp_str);
112 dirname_ptr = tmp_iter;
115 palacios_free(tmp_str);
120 static int palacios_file_mkdir(const char * pathname, unsigned short perms, int recurse) {
121 /* Welcome to the jungle... */
123 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,41)
124 /* DO NOT REFERENCE THIS VARIABLE */
125 /* It only exists to provide version compatibility */
126 struct path tmp_path;
128 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,41)
132 struct path * path_ptr = NULL;
133 struct dentry * dentry;
139 return mkdir_recursive(pathname, perms);
142 /* Before Linux 3.1 this was somewhat more difficult */
143 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,41)
145 // I'm not 100% sure about the version here, but it was around this time that the API changed
146 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,38)
147 ret = kern_path_parent(pathname, &nd);
150 if (path_lookup(pathname, LOOKUP_DIRECTORY | LOOKUP_FOLLOW, &nd) == 0) {
154 if (path_lookup(pathname, LOOKUP_PARENT | LOOKUP_FOLLOW, &nd) != 0) {
160 ERROR("%s:%d - Error: kern_path_parent() returned error for (%s)\n", __FILE__, __LINE__,
165 dentry = lookup_create(&nd, 1);
166 path_ptr = &(nd.path);
170 dentry = kern_path_create(AT_FDCWD, pathname, &tmp_path, 1);
172 if (!dentry || IS_ERR(dentry)) {
176 path_ptr = &tmp_path;
181 if (!(!dentry || IS_ERR(dentry))) {
182 ret = vfs_mkdir(path_ptr->dentry->d_inode, dentry, perms);
185 mutex_unlock(&(path_ptr->dentry->d_inode->i_mutex));
192 static void * palacios_file_open(const char * path, int mode, void * private_data) {
193 struct v3_guest * guest = (struct v3_guest *)private_data;
194 struct palacios_file * pfile = NULL;
195 struct vm_file_state * vm_state = NULL;
198 vm_state = get_vm_ext_data(guest, "FILE_INTERFACE");
200 if (vm_state == NULL) {
201 ERROR("ERROR: Could not locate vm file state for extension FILE_INTERFACE\n");
206 pfile = palacios_alloc(sizeof(struct palacios_file));
208 ERROR("Cannot allocate in file open\n");
211 memset(pfile, 0, sizeof(struct palacios_file));
213 if ((mode & FILE_OPEN_MODE_READ) && (mode & FILE_OPEN_MODE_WRITE)) {
214 pfile->mode = O_RDWR;
215 } else if (mode & FILE_OPEN_MODE_READ) {
216 pfile->mode = O_RDONLY;
217 } else if (mode & FILE_OPEN_MODE_WRITE) {
218 pfile->mode = O_WRONLY;
221 if (mode & FILE_OPEN_MODE_CREATE) {
222 pfile->mode |= O_CREAT;
226 pfile->mode |= O_LARGEFILE;
229 pfile->filp = filp_open(path, pfile->mode, 0600); // rw------- to start
231 if (!pfile->filp || IS_ERR(pfile->filp)) {
232 ERROR("Cannot open file: %s\n", path);
233 palacios_free(pfile);
237 pfile->path = palacios_alloc(strlen(path) + 1);
240 ERROR("Cannot allocate in file open\n");
241 filp_close(pfile->filp,NULL);
242 palacios_free(pfile);
245 strncpy(pfile->path, path, strlen(path)); // will terminate pfile->path
246 pfile->guest = guest;
248 palacios_spinlock_init(&(pfile->lock));
251 list_add(&(pfile->file_node), &(global_files));
253 list_add(&(pfile->file_node), &(vm_state->open_files));
260 static int palacios_file_close(void * file_ptr) {
261 struct palacios_file * pfile = (struct palacios_file *)file_ptr;
267 filp_close(pfile->filp, NULL);
269 list_del(&(pfile->file_node));
271 palacios_spinlock_deinit(&(pfile->lock));
273 palacios_free(pfile->path);
274 palacios_free(pfile);
279 static unsigned long long palacios_file_size(void * file_ptr) {
280 struct palacios_file * pfile = (struct palacios_file *)file_ptr;
281 struct file * filp = pfile->filp;
285 ret = PAL_VFS_GETATTR(&(filp->f_path), &s);
288 ERROR("Failed to fstat file\n");
295 static unsigned long long palacios_file_read(void * file_ptr, void * buffer, unsigned long long length, unsigned long long offset){
296 struct palacios_file * pfile = (struct palacios_file *)file_ptr;
297 struct file * filp = pfile->filp;
304 ret = vfs_read(filp, buffer, length, &offset);
309 ERROR("sys_read of %p for %lld bytes at offset %llu failed (ret=%ld)\n", filp, length, offset, ret);
316 static unsigned long long palacios_file_write(void * file_ptr, void * buffer, unsigned long long length, unsigned long long offset) {
317 struct palacios_file * pfile = (struct palacios_file *)file_ptr;
318 struct file * filp = pfile->filp;
325 ret = vfs_write(filp, buffer, length, &offset);
331 ERROR("sys_write for %llu bytes at offset %llu failed (ret=%ld)\n", length, offset, ret);
338 static struct v3_file_hooks palacios_file_hooks = {
339 .open = palacios_file_open,
340 .close = palacios_file_close,
341 .read = palacios_file_read,
342 .write = palacios_file_write,
343 .size = palacios_file_size,
344 .mkdir = palacios_file_mkdir,
349 static int file_init( void ) {
350 INIT_LIST_HEAD(&(global_files));
352 V3_Init_File(&palacios_file_hooks);
358 static int file_deinit( void ) {
359 struct palacios_file * pfile = NULL;
360 struct palacios_file * tmp = NULL;
362 list_for_each_entry_safe(pfile, tmp, &(global_files), file_node) {
363 filp_close(pfile->filp, NULL);
364 list_del(&(pfile->file_node));
365 palacios_free(pfile->path);
366 palacios_free(pfile);
372 static int guest_file_init(struct v3_guest * guest, void ** vm_data) {
373 struct vm_file_state * state = palacios_alloc(sizeof(struct vm_file_state));
376 ERROR("Cannot allocate when intializing file services for guest\n");
381 INIT_LIST_HEAD(&(state->open_files));
390 static int guest_file_deinit(struct v3_guest * guest, void * vm_data) {
391 struct vm_file_state * state = (struct vm_file_state *)vm_data;
392 struct palacios_file * pfile = NULL;
393 struct palacios_file * tmp = NULL;
395 list_for_each_entry_safe(pfile, tmp, &(state->open_files), file_node) {
396 filp_close(pfile->filp, NULL);
397 list_del(&(pfile->file_node));
398 palacios_free(pfile->path);
399 palacios_free(pfile);
402 palacios_free(state);
407 static struct linux_ext file_ext = {
408 .name = "FILE_INTERFACE",
410 .deinit = file_deinit,
411 .guest_init = guest_file_init,
412 .guest_deinit = guest_file_deinit
416 register_extension(&file_ext);