diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dd9bb55 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* ident diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1b112e1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Ignore all generated files +*.o +*.ko +*.cmd +*.a +*.d +*.mod +*.mod.c +*.order +*.so* +*~ + +# Generated demo executables +examples/console-read +examples/drums +examples/drums2 +examples/drums3 +examples/echo +examples/helloworld +examples/ioctl +examples/logring +examples/pager +examples/uid-filter diff --git a/Makefile b/Makefile index 0948a0d..a21543c 100644 --- a/Makefile +++ b/Makefile @@ -6,10 +6,10 @@ PREFIX = /usr/local LIBDIR = $(PREFIX)/lib INCDIR = $(PREFIX)/include -CC = gcc -LD = gcc +CC = $(CROSS_COMPILE)gcc +LD = $(CROSS_COMPILE)gcc INSTALL = install -STRIP = strip +STRIP = $(CROSS_COMPILE)strip PREFIX = /usr/local BINDIR = $(PREFIX)/bin ETCDIR = /etc/$(TARGET) diff --git a/include/kfusd.h b/include/kfusd.h index 9c01d89..12253c3 100755 --- a/include/kfusd.h +++ b/include/kfusd.h @@ -88,7 +88,7 @@ struct fusd_transaction struct fusd_dev_t_s; typedef struct fusd_dev_t_s fusd_dev_t; struct CLASS; -struct class_device; +struct device; /* state kept per opened file (i.e., an instance of a device) */ typedef struct { @@ -125,7 +125,7 @@ struct fusd_dev_t_s { char *dev_name; struct CLASS *clazz; int owns_class; - struct class_device *class_device; + struct device *device; void *private_data; /* User's private data */ struct cdev* handle; diff --git a/kfusd/kfusd.c b/kfusd/kfusd.c index 4b5ff70..a82fcd8 100755 --- a/kfusd/kfusd.c +++ b/kfusd/kfusd.c @@ -27,7 +27,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ - + /* * FUSD: the Framework for User-Space Devices @@ -51,11 +51,11 @@ */ #ifndef __KERNEL__ -#define __KERNEL__ +# define __KERNEL__ #endif #ifdef MODVERSIONS -#include +# include #endif //#include @@ -91,7 +91,7 @@ /* Default debug level for FUSD messages. Has no effect unless * CONFIG_FUSD_DEBUG is defined. */ #ifndef CONFIG_FUSD_DEBUGLEVEL -#define CONFIG_FUSD_DEBUGLEVEL 3 +# define CONFIG_FUSD_DEBUGLEVEL 4 #endif /* Define this to check for memory leaks */ @@ -106,38 +106,122 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) -#define CLASS class_simple -#define class_create class_simple_create -#define class_destroy class_simple_destroy -#define CLASS_DEVICE_CREATE(a, b, c, d, e) class_simple_device_add(a, c, d, e) -#define class_device_destroy(a, b) class_simple_device_remove(b) +# define CLASS class_simple +# define class_create class_simple_create +# define class_destroy class_simple_destroy +# define CLASS_DEVICE_CREATE(a, b, c, d, e) class_simple_device_add(a, c, d, e) +# define CLASS_DEVICE_DESTROY(a, b) class_simple_device_remove(b) #else -#define CLASS class +# define CLASS class -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) -#define CLASS_DEVICE_CREATE(a, b, c, d, e) class_device_create(a, c, d, e) +# define CLASS_DEVICE_CREATE(a, b, c, d, e) device_create(a, c, d, e) + +# else + +# if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30) + +# define CLASS_DEVICE_CREATE(a, b, c, d, e) device_create(a, b, c, d, e) + +# else + +# define CLASS_DEVICE_CREATE(a, b, c, d, e) device_create(a, b, c, d, e) + +# endif + +# endif + +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30) + +# define CLASS_DEVICE_DESTROY(a, b) device_destroy(a, b) #else -#define CLASS_DEVICE_CREATE(a, b, c, d, e) class_device_create(a, b, c, d, e) +# define CLASS_DEVICE_DESTROY(a, b) device_destroy(a, b) #endif -#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19) -static inline struct kobject * to_kobj(struct dentry * dentry) +struct sysfs_elem_dir { - struct sysfs_dirent * sd = dentry->d_fsdata; - if(sd) - return ((struct kobject *) sd->s_element); - else - return NULL; + struct kobject *kobj; + /* children list starts here and goes through sd->s_sibling */ + struct sysfs_dirent *children; +}; + +struct sysfs_elem_symlink +{ + struct sysfs_dirent *target_sd; +}; + +struct sysfs_elem_attr +{ + struct attribute *attr; + struct sysfs_open_dirent *open; +}; + +struct sysfs_elem_bin_attr +{ + struct bin_attribute *bin_attr; + struct hlist_head buffers; +}; + +struct sysfs_dirent +{ + atomic_t s_count; + atomic_t s_active; + struct sysfs_dirent *s_parent; + struct sysfs_dirent *s_sibling; + const char *s_name; + + union + { + struct sysfs_elem_dir s_dir; + struct sysfs_elem_symlink s_symlink; + struct sysfs_elem_attr s_attr; + struct sysfs_elem_bin_attr s_bin_attr; + }; + + unsigned int s_flags; + ino_t s_ino; + umode_t s_mode; + struct sysfs_inode_attrs *s_iattr; +}; + +struct class_private { + struct kset class_subsys; + struct klist class_devices; + struct list_head class_interfaces; + struct kset class_dirs; + struct mutex class_mutex; + struct class *class; +}; + +#define to_class(obj) \ + container_of(obj, struct class_private, class_subsys.kobj) + +#endif + +static inline struct kobject * to_kobj (struct dentry * dentry) +{ + struct sysfs_dirent * sd = dentry->d_fsdata; + if ( sd ) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + return ((struct kobject *) sd->s_element ); +#else + return ((struct kobject *) sd->s_dir.kobj ); +#endif + else + return NULL; } -#define to_class(obj) container_of(obj, struct class, subsys.kset.kobj) +//#define to_class(obj) container_of(obj, struct class, subsys.kset.kobj) /**************************************************************************/ @@ -146,19 +230,19 @@ static inline struct kobject * to_kobj(struct dentry * dentry) #include "kfusd.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) -# error "***FUSD doesn't work before Linux Kernel v2.6.13" +# error "***FUSD doesn't work before Linux Kernel v2.6.13" #endif -STATIC struct cdev* fusd_control_device; -STATIC struct cdev* fusd_status_device; +STATIC struct cdev* fusd_control_cdev; +STATIC struct cdev* fusd_status_cdev; STATIC dev_t control_id; STATIC dev_t status_id; static struct CLASS *fusd_class; -static struct class_device *fusd_control_class_device; -static struct class_device *fusd_status_class_device; +static struct device *fusd_control_device; +static struct device *fusd_status_device; extern struct CLASS *sound_class; @@ -169,15 +253,15 @@ STATIC int last_version = 1; STATIC int last_transid = 1; /* wait queue that is awakened when new devices are registered */ -STATIC DECLARE_WAIT_QUEUE_HEAD(new_device_wait); +STATIC DECLARE_WAIT_QUEUE_HEAD (new_device_wait); /* the list of valid devices, and sem to protect it */ -LIST_HEAD(fusd_devlist_head); -DECLARE_MUTEX(fusd_devlist_sem); +LIST_HEAD (fusd_devlist_head); +DECLARE_MUTEX (fusd_devlist_sem); //#ifdef MODULE_LICENSE -MODULE_AUTHOR("Jeremy Elson (c)2001"); -MODULE_LICENSE("GPL"); +MODULE_AUTHOR ("Jeremy Elson (c)2001"); +MODULE_LICENSE ("GPL"); //#endif /***************************Debugging Support*****************************/ @@ -185,42 +269,45 @@ MODULE_LICENSE("GPL"); #ifdef CONFIG_FUSD_DEBUG STATIC int fusd_debug_level = CONFIG_FUSD_DEBUGLEVEL; -module_param(fusd_debug_level, int, S_IRUGO); +module_param (fusd_debug_level, int, S_IRUGO); -#define BUFSIZE 1000 /* kernel's kmalloc pool has a 1012-sized bucket */ +# define BUFSIZE 1000 /* kernel's kmalloc pool has a 1012-sized bucket */ static int debug_throttle = 0; /* emit a maximum number of debug messages, else it's possible to take out the machine accidentally if a daemon disappears with open files */ -STATIC void rdebug_real(char *fmt, ...) +STATIC void rdebug_real (char *fmt, ...) { - va_list ap; - int len; - char *message; + va_list ap; + int len; + char *message; - if(debug_throttle > 100) return; - debug_throttle++; + if ( debug_throttle > 100 ) return; + debug_throttle++; - /* I'm kmallocing since you don't really want 1k on the stack. I've - * had stack overflow problems before; the kernel stack is quite - * small... */ - if ((message = KMALLOC(BUFSIZE, GFP_KERNEL)) == NULL) - return; + /* I'm kmallocing since you don't really want 1k on the stack. I've + * had stack overflow problems before; the kernel stack is quite + * small... */ + if ( ( message = KMALLOC(BUFSIZE, GFP_KERNEL) ) == NULL ) + return; - va_start(ap, fmt); - len = vsnprintf(message, BUFSIZE-1, fmt, ap); - va_end(ap); + va_start(ap, fmt); + len = vsnprintf(message, BUFSIZE - 1, fmt, ap); + va_end(ap); - if (len >= BUFSIZE) { - printk("WARNING: POSSIBLE KERNEL CORRUPTION; MESSAGE TOO LONG\n"); - } else { - printk("fusd: %.975s\n", message); /* note msgs are truncated at + if ( len >= BUFSIZE ) + { + printk("WARNING: POSSIBLE KERNEL CORRUPTION; MESSAGE TOO LONG\n"); + } + else + { + printk("fusd: %.975s\n", message); /* note msgs are truncated at * ~1000 chars to fit inside the 1024 printk * limit imposed by the kernel */ - } + } - KFREE(message); + KFREE(message); } #endif /* CONFIG_FUSD_DEBUG */ @@ -229,115 +316,121 @@ STATIC void rdebug_real(char *fmt, ...) #ifdef CONFIG_FUSD_MEMDEBUG -#define MAX_MEM_DEBUG 10000 +# define MAX_MEM_DEBUG 10000 -DECLARE_MUTEX(fusd_memdebug_sem); +DECLARE_MUTEX (fusd_memdebug_sem); -typedef struct { - void *ptr; - int line; - int size; +typedef struct +{ + void *ptr; + int line; + int size; } mem_debug_t; mem_debug_t *mem_debug; -STATIC int fusd_mem_init(void) +STATIC int fusd_mem_init (void) { - int i; + int i; - mem_debug = kmalloc(sizeof(mem_debug_t) * MAX_MEM_DEBUG, GFP_KERNEL); + mem_debug = kmalloc(sizeof (mem_debug_t ) * MAX_MEM_DEBUG, GFP_KERNEL); - if (mem_debug == NULL) { - RDEBUG(2, "argh - memdebug malloc failed!"); - return -ENOMEM; - } + if ( mem_debug == NULL ) + { + RDEBUG(2, "argh - memdebug malloc failed!"); + return -ENOMEM; + } - /* initialize */ - for (i = 0; i < MAX_MEM_DEBUG; i++) - mem_debug[i].ptr = NULL; - - RDEBUG(2, "FUSD memory debugger activated"); - return 0; -} - -STATIC void fusd_mem_cleanup(void) -{ - int i; - int count=0; - for (i = 0; i < MAX_MEM_DEBUG; i++) - if (mem_debug[i].ptr != NULL) { - RDEBUG(0, "memdebug: failed to free memory allocated at line %d (%d b)", - mem_debug[i].line, mem_debug[i].size); - count++; - } - if (!count) - RDEBUG(2, "congratulations - memory debugger is happy!"); - kfree(mem_debug); -} - -STATIC void fusd_mem_add(void *ptr, int line, int size) -{ - int i; - - if (ptr==NULL) - return; - - for (i = 0; i < MAX_MEM_DEBUG; i++) { - if (mem_debug[i].ptr == NULL) { - mem_debug[i].ptr = ptr; - mem_debug[i].line = line; - mem_debug[i].size = size; - return; - } - } - RDEBUG(1, "WARNING - memdebug out of space!!!!"); -} - -STATIC void fusd_mem_del(void *ptr) -{ - int i; - for (i = 0; i < MAX_MEM_DEBUG; i++) { - if (mem_debug[i].ptr == ptr) { + /* initialize */ + for ( i = 0; i < MAX_MEM_DEBUG; i++ ) mem_debug[i].ptr = NULL; + + RDEBUG(2, "FUSD memory debugger activated"); + return 0; +} + +STATIC void fusd_mem_cleanup (void) +{ + int i; + int count = 0; + for ( i = 0; i < MAX_MEM_DEBUG; i++ ) + if ( mem_debug[i].ptr != NULL ) + { + RDEBUG(0, "memdebug: failed to free memory allocated at line %d (%d b)", + mem_debug[i].line, mem_debug[i].size); + count++; + } + if ( !count ) + RDEBUG(2, "congratulations - memory debugger is happy!"); + kfree(mem_debug); +} + +STATIC void fusd_mem_add (void *ptr, int line, int size) +{ + int i; + + if ( ptr == NULL ) return; - } - } - RDEBUG(2, "WARNING - memdebug is confused!!!!"); + + for ( i = 0; i < MAX_MEM_DEBUG; i++ ) + { + if ( mem_debug[i].ptr == NULL ) + { + mem_debug[i].ptr = ptr; + mem_debug[i].line = line; + mem_debug[i].size = size; + return; + } + } + RDEBUG(1, "WARNING - memdebug out of space!!!!"); } - -STATIC void *fusd_kmalloc(size_t size, int type, int line) +STATIC void fusd_mem_del (void *ptr) { - void *ptr = kmalloc(size, type); - down(&fusd_memdebug_sem); - fusd_mem_add(ptr, line, size); - up(&fusd_memdebug_sem); - return ptr; + int i; + for ( i = 0; i < MAX_MEM_DEBUG; i++ ) + { + if ( mem_debug[i].ptr == ptr ) + { + mem_debug[i].ptr = NULL; + return; + } + } + RDEBUG(2, "WARNING - memdebug is confused!!!!"); } -STATIC void fusd_kfree(void *ptr) +STATIC void *fusd_kmalloc (size_t size, int type, int line) { - down(&fusd_memdebug_sem); - fusd_mem_del(ptr); - kfree(ptr); - up(&fusd_memdebug_sem); + void *ptr = kmalloc(size, type); + down(&fusd_memdebug_sem); + fusd_mem_add(ptr, line, size); + up(&fusd_memdebug_sem); + return ptr; } -STATIC void *fusd_vmalloc(size_t size, int line) +STATIC void fusd_kfree (void *ptr) { - void *ptr = vmalloc(size); - down(&fusd_memdebug_sem); - fusd_mem_add(ptr, line, size); - up(&fusd_memdebug_sem); - return ptr; + down(&fusd_memdebug_sem); + fusd_mem_del(ptr); + kfree(ptr); + up(&fusd_memdebug_sem); } -STATIC void fusd_vfree(void *ptr) +STATIC void *fusd_vmalloc (size_t size, int line) { - down(&fusd_memdebug_sem); - fusd_mem_del(ptr); - vfree(ptr); - up(&fusd_memdebug_sem); + void *ptr = vmalloc(size); + down(&fusd_memdebug_sem); + fusd_mem_add(ptr, line, size); + up(&fusd_memdebug_sem); + return ptr; +} + +STATIC void fusd_vfree (void *ptr) +{ + down(&fusd_memdebug_sem); + fusd_mem_del(ptr); + vfree(ptr); + up(&fusd_memdebug_sem); } #endif /* CONFIG_FUSD_MEMDEBUG */ @@ -351,33 +444,33 @@ STATIC void fusd_vfree(void *ptr) /************** STATE MANAGEMENT AND BOOKKEEPING UTILITIES ***************/ /*************************************************************************/ -STATIC inline void init_fusd_msg(fusd_msg_t *fusd_msg) +STATIC inline void init_fusd_msg (fusd_msg_t *fusd_msg) { - if (fusd_msg == NULL) - return; + if ( fusd_msg == NULL ) + return; - memset(fusd_msg, 0, sizeof(fusd_msg_t)); - fusd_msg->magic = FUSD_MSG_MAGIC; - fusd_msg->cmd = FUSD_FOPS_CALL; /* typical, but can be overwritten */ + memset(fusd_msg, 0, sizeof (fusd_msg_t )); + fusd_msg->magic = FUSD_MSG_MAGIC; + fusd_msg->cmd = FUSD_FOPS_CALL; /* typical, but can be overwritten */ } /* * free a fusd_msg, and NULL out the pointer that points to that fusd_msg. */ -STATIC inline void free_fusd_msg(fusd_msg_t **fusd_msg) +STATIC inline void free_fusd_msg (fusd_msg_t **fusd_msg) { - if (fusd_msg == NULL || *fusd_msg == NULL) - return; + if ( fusd_msg == NULL || *fusd_msg == NULL ) + return; - if ((*fusd_msg)->data != NULL) { - VFREE((*fusd_msg)->data); - (*fusd_msg)->data = NULL; - } - KFREE(*fusd_msg); - *fusd_msg = NULL; + if ( ( *fusd_msg )->data != NULL ) + { + VFREE(( *fusd_msg )->data); + ( *fusd_msg )->data = NULL; + } + KFREE(*fusd_msg); + *fusd_msg = NULL; } - /* adjust the size of the 'files' array attached to the device to * better match the number of files. In all cases, size must be at * least MIN_ARRAY_SIZE. Subject to that constraint: if @@ -385,53 +478,56 @@ STATIC inline void free_fusd_msg(fusd_msg_t **fusd_msg) * num_filesfiles; - old_size = fusd_dev->array_size; + old_array = fusd_dev->files; + old_size = fusd_dev->array_size; - /* compute the new size of the array */ - if (fusd_dev->array_size > 4*fusd_dev->num_files) - fusd_dev->array_size /= 2; - else if (fusd_dev->array_size == fusd_dev->num_files) - fusd_dev->array_size *= 2; + /* compute the new size of the array */ + if ( fusd_dev->array_size > 4 * fusd_dev->num_files ) + fusd_dev->array_size /= 2; + else if ( fusd_dev->array_size == fusd_dev->num_files ) + fusd_dev->array_size *= 2; - /* respect the minimums and maximums (policy) */ - if (fusd_dev->array_size < MIN_FILEARRAY_SIZE) - fusd_dev->array_size = MIN_FILEARRAY_SIZE; - if (fusd_dev->array_size > MAX_FILEARRAY_SIZE) - fusd_dev->array_size = MAX_FILEARRAY_SIZE; + /* respect the minimums and maximums (policy) */ + if ( fusd_dev->array_size < MIN_FILEARRAY_SIZE ) + fusd_dev->array_size = MIN_FILEARRAY_SIZE; + if ( fusd_dev->array_size > MAX_FILEARRAY_SIZE ) + fusd_dev->array_size = MAX_FILEARRAY_SIZE; - /* make sure it's sane */ - if (fusd_dev->array_size < fusd_dev->num_files) { - RDEBUG(0, "fusd_dev_adjsize is royally screwed up!!!!!"); - return fusd_dev->files; - } + /* make sure it's sane */ + if ( fusd_dev->array_size < fusd_dev->num_files ) + { + RDEBUG(0, "fusd_dev_adjsize is royally screwed up!!!!!"); + return fusd_dev->files; + } - /* create a new array. if successful, copy the contents of the old - * one. if not, revert back to the old. */ - fusd_dev->files = KMALLOC(fusd_dev->array_size * sizeof(fusd_file_t *), - GFP_KERNEL); - if (fusd_dev->files == NULL) { - RDEBUG(1, "malloc failed in fusd_dev_adjsize!"); - fusd_dev->files = old_array; - fusd_dev->array_size = old_size; - } else { - RDEBUG(10, "/dev/%s now has space for %d files (had %d)", NAME(fusd_dev), - fusd_dev->array_size, old_size); - memset(fusd_dev->files, 0, fusd_dev->array_size * sizeof(fusd_file_t *)); - memcpy(fusd_dev->files, old_array, - fusd_dev->num_files * sizeof(fusd_file_t *)); - KFREE(old_array); - } + /* create a new array. if successful, copy the contents of the old + * one. if not, revert back to the old. */ + fusd_dev->files = KMALLOC(fusd_dev->array_size * sizeof (fusd_file_t * ), + GFP_KERNEL); + if ( fusd_dev->files == NULL ) + { + RDEBUG(1, "malloc failed in fusd_dev_adjsize!"); + fusd_dev->files = old_array; + fusd_dev->array_size = old_size; + } + else + { + RDEBUG(10, "/dev/%s now has space for %d files (had %d)", NAME(fusd_dev), + fusd_dev->array_size, old_size); + memset(fusd_dev->files, 0, fusd_dev->array_size * sizeof (fusd_file_t * )); + memcpy(fusd_dev->files, old_array, + fusd_dev->num_files * sizeof (fusd_file_t * )); + KFREE(old_array); + } - return fusd_dev->files; + return fusd_dev->files; } - /* * DEVICE LOCK MUST BE HELD TO CALL THIS FUNCTION * @@ -450,71 +546,76 @@ STATIC fusd_file_t **fusd_dev_adjsize(fusd_dev_t *fusd_dev) * * Returns: 1 if the device was freed * 0 if the device still exists (and can be unlocked) */ -STATIC int maybe_free_fusd_dev(fusd_dev_t *fusd_dev) +STATIC int maybe_free_fusd_dev (fusd_dev_t *fusd_dev) { - fusd_msgC_t *ptr, *next; + fusd_msgC_t *ptr, *next; - down(&fusd_devlist_sem); + down(&fusd_devlist_sem); - /* DON'T free the device under conditions listed above */ - if (!fusd_dev->zombie || fusd_dev->num_files || fusd_dev->open_in_progress) { - up(&fusd_devlist_sem); - return 0; - } + /* DON'T free the device under conditions listed above */ + if ( !fusd_dev->zombie || fusd_dev->num_files || fusd_dev->open_in_progress ) + { + up(&fusd_devlist_sem); + return 0; + } - /* OK - bombs away! This fusd_dev_t is on its way out the door! */ + /* OK - bombs away! This fusd_dev_t is on its way out the door! */ - RDEBUG(8, "freeing state associated with /dev/%s", NAME(fusd_dev)); + RDEBUG(8, "freeing state associated with /dev/%s", NAME(fusd_dev)); - /* delete it off the list of valid devices, and unlock */ - list_del(&fusd_dev->devlist); - up(&fusd_devlist_sem); + /* delete it off the list of valid devices, and unlock */ + list_del(&fusd_dev->devlist); + up(&fusd_devlist_sem); - /* free any outgoing messages that the device might have waiting */ - for (ptr = fusd_dev->msg_head; ptr != NULL; ptr = next) { - next = ptr->next; - FREE_FUSD_MSGC(ptr); - } - - /* free the device's dev name */ - if (fusd_dev->dev_name != NULL) { - KFREE(fusd_dev->dev_name); - fusd_dev->dev_name = NULL; - } - - /* free the device's class name */ - if (fusd_dev->class_name != NULL) { - KFREE(fusd_dev->class_name); - fusd_dev->class_name = NULL; - } + /* free any outgoing messages that the device might have waiting */ + for ( ptr = fusd_dev->msg_head; ptr != NULL; ptr = next ) + { + next = ptr->next; + FREE_FUSD_MSGC(ptr); + } - /* free the device's name */ - if (fusd_dev->name != NULL) { - KFREE(fusd_dev->name); - fusd_dev->name = NULL; - } - + /* free the device's dev name */ + if ( fusd_dev->dev_name != NULL ) + { + KFREE(fusd_dev->dev_name); + fusd_dev->dev_name = NULL; + } - /* free the array used to store pointers to fusd_file_t's */ - if (fusd_dev->files != NULL) { - KFREE(fusd_dev->files); - fusd_dev->files = NULL; - } + /* free the device's class name */ + if ( fusd_dev->class_name != NULL ) + { + KFREE(fusd_dev->class_name); + fusd_dev->class_name = NULL; + } - /* clear the structure and free it! */ - memset(fusd_dev, 0, sizeof(fusd_dev_t)); - KFREE(fusd_dev); + /* free the device's name */ + if ( fusd_dev->name != NULL ) + { + KFREE(fusd_dev->name); + fusd_dev->name = NULL; + } - /* notify fusd_status readers that there has been a change in the - * list of registered devices */ - atomic_inc_and_ret(&last_version); - wake_up_interruptible(&new_device_wait); - //MOD_DEC_USE_COUNT; - return 1; + /* free the array used to store pointers to fusd_file_t's */ + if ( fusd_dev->files != NULL ) + { + KFREE(fusd_dev->files); + fusd_dev->files = NULL; + } + + /* clear the structure and free it! */ + memset(fusd_dev, 0, sizeof (fusd_dev_t )); + KFREE(fusd_dev); + + /* notify fusd_status readers that there has been a change in the + * list of registered devices */ + atomic_inc_and_ret(&last_version); + wake_up_interruptible(&new_device_wait); + + //MOD_DEC_USE_COUNT; + return 1; } - /* * * DO NOT CALL THIS FUNCTION UNLESS THE DEVICE IS ALREADY LOCKED @@ -525,46 +626,45 @@ STATIC int maybe_free_fusd_dev(fusd_dev_t *fusd_dev) * device state itself is freed. * */ -STATIC void zombify_dev(fusd_dev_t *fusd_dev) +STATIC void zombify_dev (fusd_dev_t *fusd_dev) { - int i; + int i; - if (fusd_dev->zombie) { - RDEBUG(1, "zombify_device called on a zombie!!"); - return; - } + if ( fusd_dev->zombie ) + { + RDEBUG(1, "zombify_device called on a zombie!!"); + return; + } - fusd_dev->zombie = 1; + fusd_dev->zombie = 1; - RDEBUG(3, "/dev/%s turning into a zombie (%d open files)", NAME(fusd_dev), - fusd_dev->num_files); + RDEBUG(3, "/dev/%s turning into a zombie (%d open files)", NAME(fusd_dev), + fusd_dev->num_files); - /* If there are files holding this device open, wake them up. */ - for (i = 0; i < fusd_dev->num_files; i++) { - wake_up_interruptible(&fusd_dev->files[i]->file_wait); - wake_up_interruptible(&fusd_dev->files[i]->poll_wait); - } + /* If there are files holding this device open, wake them up. */ + for ( i = 0; i < fusd_dev->num_files; i++ ) + { + wake_up_interruptible(&fusd_dev->files[i]->file_wait); + wake_up_interruptible(&fusd_dev->files[i]->poll_wait); + } } - - /* utility function to find the index of a fusd_file in a fusd_dev. * returns index if found, -1 if not found. ASSUMES WE HAVE A VALID * fusd_dev. fusd_file may be NULL if we are searching for an empty * slot. */ -STATIC int find_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file) +STATIC int find_fusd_file (fusd_dev_t *fusd_dev, fusd_file_t *fusd_file) { - int i, num_files = fusd_dev->num_files; - fusd_file_t **files = fusd_dev->files; + int i, num_files = fusd_dev->num_files; + fusd_file_t **files = fusd_dev->files; - for (i = 0; i < num_files; i++) - if (files[i] == fusd_file) - return i; + for ( i = 0; i < num_files; i++ ) + if ( files[i] == fusd_file ) + return i; - return -1; + return -1; } - /* * DEVICE LOCK MUST BE HELD BEFORE THIS IS CALLED * @@ -572,50 +672,50 @@ STATIC int find_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file) * freed. If the device is freed, then do not try to unlock it! * (Callers: Check the return value before unlocking!) */ -STATIC int free_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file) +STATIC int free_fusd_file (fusd_dev_t *fusd_dev, fusd_file_t *fusd_file) { - int i; - struct list_head *tmp, *it; - - /* find the index of the file in the device's file-list... */ - if ((i = find_fusd_file(fusd_dev, fusd_file)) < 0) - panic("corrupted fusd_dev: releasing a file that we think is closed"); - - /* ...and remove it (by putting the last entry into its place) */ - fusd_dev->files[i] = fusd_dev->files[--(fusd_dev->num_files)]; + int i; + struct list_head *tmp, *it; - /* there might be an incoming message waiting for a restarted system - * call. free it -- after possibly forging a close (see - * fusd_forge_close). */ - - - list_for_each_safe(it, tmp, &fusd_file->transactions) - { - struct fusd_transaction* transaction = list_entry(it, struct fusd_transaction, list); - if(transaction->msg_in) - { - if (transaction->msg_in->subcmd == FUSD_OPEN && transaction->msg_in->parm.fops_msg.retval == 0) - fusd_forge_close(transaction->msg_in, fusd_dev); - free_fusd_msg(&transaction->msg_in); - } - KFREE(transaction); - } - - /* free state associated with this file */ - memset(fusd_file, 0, sizeof(fusd_file_t)); - KFREE(fusd_file); + /* find the index of the file in the device's file-list... */ + if ( ( i = find_fusd_file(fusd_dev, fusd_file) ) < 0 ) + panic("corrupted fusd_dev: releasing a file that we think is closed"); - /* reduce the size of the file array if necessary */ - if (fusd_dev->array_size > MIN_FILEARRAY_SIZE && - fusd_dev->array_size > 4*fusd_dev->num_files) - fusd_dev_adjsize(fusd_dev); + /* ...and remove it (by putting the last entry into its place) */ + fusd_dev->files[i] = fusd_dev->files[--( fusd_dev->num_files )]; - /* renumber the array */ - for (i = 0; i < fusd_dev->num_files; i++) - fusd_dev->files[i]->index = i; + /* there might be an incoming message waiting for a restarted system + * call. free it -- after possibly forging a close (see + * fusd_forge_close). */ - /* try to free the device -- this may have been its last file */ - return maybe_free_fusd_dev(fusd_dev); + + list_for_each_safe(it, tmp, &fusd_file->transactions) + { + struct fusd_transaction* transaction = list_entry(it, struct fusd_transaction, list); + if ( transaction->msg_in ) + { + if ( transaction->msg_in->subcmd == FUSD_OPEN && transaction->msg_in->parm.fops_msg.retval == 0 ) + fusd_forge_close(transaction->msg_in, fusd_dev); + free_fusd_msg(&transaction->msg_in); + } + KFREE(transaction); + } + + /* free state associated with this file */ + memset(fusd_file, 0, sizeof (fusd_file_t )); + KFREE(fusd_file); + + /* reduce the size of the file array if necessary */ + if ( fusd_dev->array_size > MIN_FILEARRAY_SIZE && + fusd_dev->array_size > 4 * fusd_dev->num_files ) + fusd_dev_adjsize(fusd_dev); + + /* renumber the array */ + for ( i = 0; i < fusd_dev->num_files; i++ ) + fusd_dev->files[i]->index = i; + + /* try to free the device -- this may have been its last file */ + return maybe_free_fusd_dev(fusd_dev); } @@ -623,7 +723,6 @@ STATIC int free_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file) /********************** CLIENT CALLBACK FUNCTIONS ***************************/ /****************************************************************************/ - /* todo * fusd_restart_check: Called from the beginning of most system calls * to see if we are restarting a system call. @@ -639,63 +738,64 @@ STATIC int free_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file) * call on that file descriptor -- well, we lose. Clear state of that * old syscall out and continue as usual. */ -STATIC struct fusd_transaction* fusd_find_incomplete_transaction(fusd_file_t *fusd_file, int subcmd) +STATIC struct fusd_transaction* fusd_find_incomplete_transaction (fusd_file_t *fusd_file, int subcmd) { - struct fusd_transaction* transaction = fusd_find_transaction_by_pid(fusd_file, current->pid); - if(transaction == NULL) - return NULL; + struct fusd_transaction* transaction = fusd_find_transaction_by_pid(fusd_file, current->pid); + if ( transaction == NULL ) + return NULL; - if (transaction->subcmd != subcmd) - { - RDEBUG(2, "Incomplete transaction %ld thrown out, was expecting subcmd %d but received %d", - transaction->transid, transaction->subcmd, subcmd); - fusd_cleanup_transaction(fusd_file, transaction); - return NULL; - } - - RDEBUG(4, "pid %d restarting system call with transid %ld", current->pid, - transaction->transid); - return transaction; + if ( transaction->subcmd != subcmd ) + { + RDEBUG(2, "Incomplete transaction %ld thrown out, was expecting subcmd %d but received %d", + transaction->transid, transaction->subcmd, subcmd); + fusd_cleanup_transaction(fusd_file, transaction); + return NULL; + } + + RDEBUG(4, "pid %d restarting system call with transid %ld", current->pid, + transaction->transid); + return transaction; } - -STATIC int send_to_dev(fusd_dev_t *fusd_dev, fusd_msg_t *fusd_msg, int locked) +STATIC int send_to_dev (fusd_dev_t *fusd_dev, fusd_msg_t *fusd_msg, int locked) { - fusd_msgC_t *fusd_msgC; + fusd_msgC_t *fusd_msgC; - /* allocate a container for the message */ - if ((fusd_msgC = KMALLOC(sizeof(fusd_msgC_t), GFP_KERNEL)) == NULL) - return -ENOMEM; + /* allocate a container for the message */ + if ( ( fusd_msgC = KMALLOC(sizeof (fusd_msgC_t ), GFP_KERNEL) ) == NULL ) + return -ENOMEM; - memset(fusd_msgC, 0, sizeof(fusd_msgC_t)); - memcpy(&fusd_msgC->fusd_msg, fusd_msg, sizeof(fusd_msg_t)); + memset(fusd_msgC, 0, sizeof (fusd_msgC_t )); + memcpy(&fusd_msgC->fusd_msg, fusd_msg, sizeof (fusd_msg_t )); - if (!locked) - LOCK_FUSD_DEV(fusd_dev); + if ( !locked ) + LOCK_FUSD_DEV(fusd_dev); - /* put the message in the device's outgoing queue. */ - if (fusd_dev->msg_head == NULL) { - fusd_dev->msg_head = fusd_dev->msg_tail = fusd_msgC; - } else { - fusd_dev->msg_tail->next = fusd_msgC; - fusd_dev->msg_tail = fusd_msgC; - } + /* put the message in the device's outgoing queue. */ + if ( fusd_dev->msg_head == NULL ) + { + fusd_dev->msg_head = fusd_dev->msg_tail = fusd_msgC; + } + else + { + fusd_dev->msg_tail->next = fusd_msgC; + fusd_dev->msg_tail = fusd_msgC; + } - if (!locked) - UNLOCK_FUSD_DEV(fusd_dev); + if ( !locked ) + UNLOCK_FUSD_DEV(fusd_dev); - /* wake up the driver, which now has a message waiting in its queue */ - WAKE_UP_INTERRUPTIBLE_SYNC(&fusd_dev->dev_wait); + /* wake up the driver, which now has a message waiting in its queue */ + WAKE_UP_INTERRUPTIBLE_SYNC(&fusd_dev->dev_wait); - return 0; + return 0; - zombie_dev: - KFREE(fusd_msgC); - return -EPIPE; +zombie_dev: + KFREE(fusd_msgC); + return -EPIPE; } - /* * special case: if the driver sent back a successful "open", but * there is no file that is actually open, we forge a "close" so that @@ -704,211 +804,215 @@ STATIC int send_to_dev(fusd_dev_t *fusd_dev, fusd_msg_t *fusd_msg, int locked) * free_fusd_file, when we throw away a reply that had been * pending for a restart. */ -STATIC void fusd_forge_close(fusd_msg_t *msg, fusd_dev_t *fusd_dev) +STATIC void fusd_forge_close (fusd_msg_t *msg, fusd_dev_t *fusd_dev) { - RDEBUG(2, "/dev/%s tried to complete an open for transid %ld, " - "forging a close", NAME(fusd_dev), msg->parm.fops_msg.transid); - msg->cmd = FUSD_FOPS_CALL_DROPREPLY; - msg->subcmd = FUSD_CLOSE; - msg->parm.fops_msg.transid = atomic_inc_and_ret(&last_transid); - send_to_dev(fusd_dev, msg, 1); + RDEBUG(2, "/dev/%s tried to complete an open for transid %ld, " + "forging a close", NAME(fusd_dev), msg->parm.fops_msg.transid); + msg->cmd = FUSD_FOPS_CALL_DROPREPLY; + msg->subcmd = FUSD_CLOSE; + msg->parm.fops_msg.transid = atomic_inc_and_ret(&last_transid); + send_to_dev(fusd_dev, msg, 1); } - - /* * fusd_fops_call_send: send a fusd_msg into userspace. * * NOTE - we are already holding the lock on fusd_file_arg when this * function is called, but NOT the lock on the fusd_dev */ -STATIC int fusd_fops_call_send(fusd_file_t *fusd_file_arg, - fusd_msg_t *fusd_msg, struct fusd_transaction** transaction) +STATIC int fusd_fops_call_send (fusd_file_t *fusd_file_arg, + fusd_msg_t *fusd_msg, struct fusd_transaction** transaction) { - fusd_dev_t *fusd_dev; - fusd_file_t *fusd_file; + fusd_dev_t *fusd_dev; + fusd_file_t *fusd_file; - /* I check this just in case, shouldn't be necessary. */ - GET_FUSD_FILE_AND_DEV(fusd_file_arg, fusd_file, fusd_dev); + /* I check this just in case, shouldn't be necessary. */ + GET_FUSD_FILE_AND_DEV(fusd_file_arg, fusd_file, fusd_dev); - /* make sure message is sane */ - if ((fusd_msg->data == NULL) != (fusd_msg->datalen == 0)) { - RDEBUG(2, "fusd_fops_call: data pointer and datalen mismatch"); - return -EINVAL; - } + /* make sure message is sane */ + if ( ( fusd_msg->data == NULL ) != ( fusd_msg->datalen == 0 ) ) + { + RDEBUG(2, "fusd_fops_call: data pointer and datalen mismatch"); + return -EINVAL; + } - /* fill the rest of the structure */ - fusd_msg->parm.fops_msg.pid = current->pid; - fusd_msg->parm.fops_msg.uid = current->uid; - fusd_msg->parm.fops_msg.gid = current->gid; - fusd_msg->parm.fops_msg.flags = fusd_file->file->f_flags; - fusd_msg->parm.fops_msg.offset = fusd_file->file->f_pos; - fusd_msg->parm.fops_msg.device_info = fusd_dev->private_data; - fusd_msg->parm.fops_msg.private_info = fusd_file->private_data; - fusd_msg->parm.fops_msg.fusd_file = fusd_file; - fusd_msg->parm.fops_msg.transid = atomic_inc_and_ret(&last_transid); + /* fill the rest of the structure */ + fusd_msg->parm.fops_msg.pid = current->pid; + // fusd_msg->parm.fops_msg.uid = current_uid(); + // fusd_msg->parm.fops_msg.gid = current_gid(); + fusd_msg->parm.fops_msg.flags = fusd_file->file->f_flags; + fusd_msg->parm.fops_msg.offset = fusd_file->file->f_pos; + fusd_msg->parm.fops_msg.device_info = fusd_dev->private_data; + fusd_msg->parm.fops_msg.private_info = fusd_file->private_data; + fusd_msg->parm.fops_msg.fusd_file = fusd_file; + fusd_msg->parm.fops_msg.transid = atomic_inc_and_ret(&last_transid); - /* set up certain state depending on if we expect a reply */ - switch (fusd_msg->cmd) { + /* set up certain state depending on if we expect a reply */ + switch ( fusd_msg->cmd ) + { - case FUSD_FOPS_CALL: /* common case */ - fusd_msg->parm.fops_msg.hint = fusd_file->index; - - break; + case FUSD_FOPS_CALL: /* common case */ + fusd_msg->parm.fops_msg.hint = fusd_file->index; - case FUSD_FOPS_CALL_DROPREPLY: - /* nothing needed */ - break; + break; - case FUSD_FOPS_NONBLOCK: - fusd_msg->parm.fops_msg.hint = fusd_file->index; - break; + case FUSD_FOPS_CALL_DROPREPLY: + /* nothing needed */ + break; - default: - RDEBUG(0, "whoa - fusd_fops_call_send got msg with unknown cmd!"); - break; - } - - if(transaction != NULL) - { - int retval; - retval = fusd_add_transaction(fusd_file, fusd_msg->parm.fops_msg.transid, fusd_msg->subcmd, - fusd_msg->parm.fops_msg.length, transaction); - if(retval < 0) - return retval; - } - - /* now add the message to the device's outgoing queue! */ - return send_to_dev(fusd_dev, fusd_msg, 0); + case FUSD_FOPS_NONBLOCK: + fusd_msg->parm.fops_msg.hint = fusd_file->index; + break; + + default: + RDEBUG(0, "whoa - fusd_fops_call_send got msg with unknown cmd!"); + break; + } + + if ( transaction != NULL ) + { + int retval; + retval = fusd_add_transaction(fusd_file, fusd_msg->parm.fops_msg.transid, fusd_msg->subcmd, + fusd_msg->parm.fops_msg.length, transaction); + if ( retval < 0 ) + return retval; + } + + /* now add the message to the device's outgoing queue! */ + return send_to_dev(fusd_dev, fusd_msg, 0); - /* bizarre errors go straight here */ - invalid_dev: - invalid_file: - RDEBUG(0, "fusd_fops_call: got invalid device or file!!!!"); - return -EPIPE; + /* bizarre errors go straight here */ +invalid_dev: + invalid_file : + RDEBUG(0, "fusd_fops_call: got invalid device or file!!!!"); + return -EPIPE; } - /* * fusd_fops_call_wait: wait for a driver to reply to a message * * NOTE - we are already holding the lock on fusd_file_arg when this * function is called, but NOT the lock on the fusd_dev */ -STATIC int fusd_fops_call_wait(fusd_file_t *fusd_file_arg, - fusd_msg_t **fusd_msg_reply, struct fusd_transaction* transaction) +STATIC int fusd_fops_call_wait (fusd_file_t *fusd_file_arg, + fusd_msg_t **fusd_msg_reply, struct fusd_transaction* transaction) { - fusd_dev_t *fusd_dev; - fusd_file_t *fusd_file; - int retval; + fusd_dev_t *fusd_dev; + fusd_file_t *fusd_file; + int retval; - /* I check this just in case, shouldn't be necessary. */ - GET_FUSD_FILE_AND_DEV(fusd_file_arg, fusd_file, fusd_dev); + /* I check this just in case, shouldn't be necessary. */ + GET_FUSD_FILE_AND_DEV(fusd_file_arg, fusd_file, fusd_dev); - /* initialize first to tell callers there is no reply (yet) */ - if (fusd_msg_reply != NULL) - *fusd_msg_reply = NULL; + /* initialize first to tell callers there is no reply (yet) */ + if ( fusd_msg_reply != NULL ) + *fusd_msg_reply = NULL; - /* - * Now, lock the device, check for an incoming message, and sleep if - * there is not a message already waiting for us. Note that we are - * unrolling the interruptible_sleep_on, as in the kernel's - * fs/pipe.c, to avoid race conditions between checking for the - * sleep condition and sleeping. - */ - LOCK_FUSD_DEV(fusd_dev); - while (transaction->msg_in == NULL) { - DECLARE_WAITQUEUE(wait, current); + /* + * Now, lock the device, check for an incoming message, and sleep if + * there is not a message already waiting for us. Note that we are + * unrolling the interruptible_sleep_on, as in the kernel's + * fs/pipe.c, to avoid race conditions between checking for the + * sleep condition and sleeping. + */ + LOCK_FUSD_DEV(fusd_dev); + while ( transaction->msg_in == NULL ) + { + DECLARE_WAITQUEUE(wait, current); - RDEBUG(10, "pid %d blocking on transid %ld", current->pid, transaction->transid); - current->state = TASK_INTERRUPTIBLE; - add_wait_queue(&fusd_file->file_wait, &wait); - UNLOCK_FUSD_DEV(fusd_dev); - UNLOCK_FUSD_FILE(fusd_file); + RDEBUG(10, "pid %d blocking on transid %ld", current->pid, transaction->transid); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&fusd_file->file_wait, &wait); + UNLOCK_FUSD_DEV(fusd_dev); + UNLOCK_FUSD_FILE(fusd_file); - schedule(); - remove_wait_queue(&fusd_file->file_wait, &wait); - current->state = TASK_RUNNING; + schedule(); + remove_wait_queue(&fusd_file->file_wait, &wait); + current->state = TASK_RUNNING; - /* - * If we woke up due to a signal -- and not due to a reply message - * coming in -- then we are in some trouble. The driver is already - * processing the request and might have changed some state that is - * hard to roll back. So, we'll tell the process to restart the - * system call, and come back to this point when the system call is - * restarted. We need to remember the PID to avoid confusion in - * case there is another process holding this file descriptor that - * is also trying to make a call. - */ - if (signal_pending(current)) { - RDEBUG(5, "blocked pid %d got a signal; sending -ERESTARTSYS", - current->pid); - LOCK_FUSD_FILE(fusd_file); - return -ERESTARTSYS; - } + /* + * If we woke up due to a signal -- and not due to a reply message + * coming in -- then we are in some trouble. The driver is already + * processing the request and might have changed some state that is + * hard to roll back. So, we'll tell the process to restart the + * system call, and come back to this point when the system call is + * restarted. We need to remember the PID to avoid confusion in + * case there is another process holding this file descriptor that + * is also trying to make a call. + */ + if ( signal_pending(current) ) + { + RDEBUG(5, "blocked pid %d got a signal; sending -ERESTARTSYS", + current->pid); + LOCK_FUSD_FILE(fusd_file); + return -ERESTARTSYS; + } - LOCK_FUSD_FILE(fusd_file); - /* re-lock the device, so we can do our msg_in check again */ - LOCK_FUSD_DEV(fusd_dev); - } - UNLOCK_FUSD_DEV(fusd_dev); + LOCK_FUSD_FILE(fusd_file); + /* re-lock the device, so we can do our msg_in check again */ + LOCK_FUSD_DEV(fusd_dev); + } + UNLOCK_FUSD_DEV(fusd_dev); - /* ok - at this point we are awake due to a message received. */ + /* ok - at this point we are awake due to a message received. */ - if (transaction->msg_in->cmd != FUSD_FOPS_REPLY || - transaction->msg_in->subcmd != transaction->subcmd || - transaction->msg_in->parm.fops_msg.transid != transaction->transid || - transaction->msg_in->parm.fops_msg.fusd_file != fusd_file) { - RDEBUG(2, "fusd_fops_call: invalid reply!"); - goto invalid_reply; - } + if ( transaction->msg_in->cmd != FUSD_FOPS_REPLY || + transaction->msg_in->subcmd != transaction->subcmd || + transaction->msg_in->parm.fops_msg.transid != transaction->transid || + transaction->msg_in->parm.fops_msg.fusd_file != fusd_file ) + { + RDEBUG(2, "fusd_fops_call: invalid reply!"); + goto invalid_reply; + } - /* copy metadata back from userspace */ - fusd_file->file->f_flags = transaction->msg_in->parm.fops_msg.flags; - fusd_file->private_data = transaction->msg_in->parm.fops_msg.private_info; - /* note, changes to device_info are NO LONGER honored here */ + /* copy metadata back from userspace */ + fusd_file->file->f_flags = transaction->msg_in->parm.fops_msg.flags; + fusd_file->private_data = transaction->msg_in->parm.fops_msg.private_info; + /* note, changes to device_info are NO LONGER honored here */ - /* if everything's okay, return the return value. if caller is - * willing to take responsibility for freeing the message itself, we - * return the message too. */ - retval = transaction->msg_in->parm.fops_msg.retval; - if (fusd_msg_reply != NULL) { - /* NOW TRANSFERRING RESPONSIBILITY FOR FREEING THIS DATA TO THE CALLER */ - *fusd_msg_reply = transaction->msg_in; - transaction->msg_in = NULL; - } else { - /* free the message ourselves */ - free_fusd_msg(&transaction->msg_in); - } - - /* success */ - fusd_cleanup_transaction(fusd_file, transaction); - return retval; + /* if everything's okay, return the return value. if caller is + * willing to take responsibility for freeing the message itself, we + * return the message too. */ + retval = transaction->msg_in->parm.fops_msg.retval; + if ( fusd_msg_reply != NULL ) + { + /* NOW TRANSFERRING RESPONSIBILITY FOR FREEING THIS DATA TO THE CALLER */ + *fusd_msg_reply = transaction->msg_in; + transaction->msg_in = NULL; + } + else + { + /* free the message ourselves */ + free_fusd_msg(&transaction->msg_in); + } - invalid_reply: - fusd_cleanup_transaction(fusd_file, transaction); - return -EPIPE; + /* success */ + fusd_cleanup_transaction(fusd_file, transaction); + return retval; - /* bizarre errors go straight here */ - invalid_dev: - invalid_file: - RDEBUG(0, "fusd_fops_call: got invalid device or file!!!!"); - return -EPIPE; +invalid_reply: + fusd_cleanup_transaction(fusd_file, transaction); + return -EPIPE; - zombie_dev: - RDEBUG(2, "fusd_fops_call: %s zombified while waiting for reply", - NAME(fusd_dev)); - return -EPIPE; + /* bizarre errors go straight here */ +invalid_dev: + invalid_file : + RDEBUG(0, "fusd_fops_call: got invalid device or file!!!!"); + return -EPIPE; + +zombie_dev: + RDEBUG(2, "fusd_fops_call: %s zombified while waiting for reply", + NAME(fusd_dev)); + return -EPIPE; } - /* fusd client system call handlers should call this after they call * fops_call, to destroy the message that was returned to them. */ -STATIC void fusd_transaction_done(struct fusd_transaction *transaction) +STATIC void fusd_transaction_done (struct fusd_transaction *transaction) { - transaction->transid = -1; - transaction->pid = 0; + transaction->transid = -1; + transaction->pid = 0; } @@ -948,759 +1052,778 @@ STATIC void fusd_transaction_done(struct fusd_transaction *transaction) * multiple sub-functions. */ - /* * fusd_dev_is_valid: If a fusd device is valid, returns 1, and will have * set the "open_in_progress" flag on the device. */ -int fusd_dev_is_valid(fusd_dev_t *fusd_dev) +int fusd_dev_is_valid (fusd_dev_t *fusd_dev) { - struct list_head *tmp; - int dev_found = 0; + struct list_head *tmp; + int dev_found = 0; - /* The first thing we must do is acquire the global lock on the - * device list, and make sure this device is valid; if so, mark it - * as being "in use". If we don't do this, there's a race: after we - * enter this function, the device may be unregistered. */ - down(&fusd_devlist_sem); - list_for_each(tmp, &fusd_devlist_head) { - fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist); + /* The first thing we must do is acquire the global lock on the + * device list, and make sure this device is valid; if so, mark it + * as being "in use". If we don't do this, there's a race: after we + * enter this function, the device may be unregistered. */ + down(&fusd_devlist_sem); - if (d == fusd_dev && d->magic == FUSD_DEV_MAGIC && !ZOMBIE(d)) { - dev_found = 1; - break; - } - } + list_for_each(tmp, &fusd_devlist_head) + { + fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist); - /* A device will not be deallocated when this counter is >0 */ - if (dev_found) - fusd_dev->open_in_progress++; + if ( d == fusd_dev && d->magic == FUSD_DEV_MAGIC && !ZOMBIE(d) ) + { + dev_found = 1; + break; + } + } - up(&fusd_devlist_sem); + /* A device will not be deallocated when this counter is >0 */ + if ( dev_found ) + fusd_dev->open_in_progress++; - return dev_found; + up(&fusd_devlist_sem); + + return dev_found; } - -int fusd_dev_add_file(struct file *file, fusd_dev_t *fusd_dev, fusd_file_t **fusd_file_ret) +int fusd_dev_add_file (struct file *file, fusd_dev_t *fusd_dev, fusd_file_t **fusd_file_ret) { - fusd_file_t *fusd_file; - int i; + fusd_file_t *fusd_file; + int i; - /* Make sure the device didn't become a zombie while we were waiting - * for the device lock */ - if (ZOMBIE(fusd_dev)) - return -ENOENT; + /* Make sure the device didn't become a zombie while we were waiting + * for the device lock */ + if ( ZOMBIE(fusd_dev) ) + return -ENOENT; - /* this shouldn't happen. maybe i'm insane, but i check anyway. */ - for (i = 0; i < fusd_dev->num_files; i++) - if (fusd_dev->files[i]->file == file) { - RDEBUG(1, "warning: fusd_client_open got open for already-open file!?"); - return -EIO; - } + /* this shouldn't happen. maybe i'm insane, but i check anyway. */ + for ( i = 0; i < fusd_dev->num_files; i++ ) + if ( fusd_dev->files[i]->file == file ) + { + RDEBUG(1, "warning: fusd_client_open got open for already-open file!?"); + return -EIO; + } - /* You can't open your own file! Return -EDEADLOCK if someone tries to. - * - * XXX - TODO - FIXME - This should eventually be more general - * deadlock detection of arbitrary length cycles */ - if (current->pid == fusd_dev->pid) { - RDEBUG(3, "pid %d tried to open its own device (/dev/%s)", - fusd_dev->pid, NAME(fusd_dev)); - return -EDEADLOCK; - } + /* You can't open your own file! Return -EDEADLOCK if someone tries to. + * + * XXX - TODO - FIXME - This should eventually be more general + * deadlock detection of arbitrary length cycles */ + if ( current->pid == fusd_dev->pid ) + { + RDEBUG(3, "pid %d tried to open its own device (/dev/%s)", + fusd_dev->pid, NAME(fusd_dev)); + return -EDEADLOCK; + } - /* make more space in the file array if we need it */ - if (fusd_dev->num_files == fusd_dev->array_size && - fusd_dev->array_size < MAX_FILEARRAY_SIZE) - fusd_dev_adjsize(fusd_dev); + /* make more space in the file array if we need it */ + if ( fusd_dev->num_files == fusd_dev->array_size && + fusd_dev->array_size < MAX_FILEARRAY_SIZE ) + fusd_dev_adjsize(fusd_dev); - /* make sure we have room... adjsize may have failed */ - if (fusd_dev->num_files >= fusd_dev->array_size) { - RDEBUG(1, "/dev/%s out of state space for open files!", NAME(fusd_dev)); - return -ENOMEM; - } + /* make sure we have room... adjsize may have failed */ + if ( fusd_dev->num_files >= fusd_dev->array_size ) + { + RDEBUG(1, "/dev/%s out of state space for open files!", NAME(fusd_dev)); + return -ENOMEM; + } - /* create state for this file */ - if ((fusd_file = KMALLOC(sizeof(fusd_file_t), GFP_KERNEL)) == NULL) { - RDEBUG(1, "yikes! kernel can't allocate memory"); - return -ENOMEM; - } - memset(fusd_file, 0, sizeof(fusd_file_t)); - init_waitqueue_head(&fusd_file->file_wait); - init_waitqueue_head(&fusd_file->poll_wait); - INIT_LIST_HEAD(&fusd_file->transactions); - init_MUTEX(&fusd_file->file_sem); - init_MUTEX(&fusd_file->transactions_sem); - fusd_file->last_poll_sent = -1; - fusd_file->magic = FUSD_FILE_MAGIC; - fusd_file->fusd_dev = fusd_dev; - fusd_file->fusd_dev_version = fusd_dev->version; - fusd_file->file = file; + /* create state for this file */ + if ( ( fusd_file = KMALLOC(sizeof (fusd_file_t ), GFP_KERNEL) ) == NULL ) + { + RDEBUG(1, "yikes! kernel can't allocate memory"); + return -ENOMEM; + } + memset(fusd_file, 0, sizeof (fusd_file_t )); + init_waitqueue_head(&fusd_file->file_wait); + init_waitqueue_head(&fusd_file->poll_wait); + INIT_LIST_HEAD(&fusd_file->transactions); + init_MUTEX(&fusd_file->file_sem); + init_MUTEX(&fusd_file->transactions_sem); + fusd_file->last_poll_sent = -1; + fusd_file->magic = FUSD_FILE_MAGIC; + fusd_file->fusd_dev = fusd_dev; + fusd_file->fusd_dev_version = fusd_dev->version; + fusd_file->file = file; - /* add this file to the list of files managed by the device */ - fusd_file->index = fusd_dev->num_files++; - fusd_dev->files[fusd_file->index] = fusd_file; + /* add this file to the list of files managed by the device */ + fusd_file->index = fusd_dev->num_files++; + fusd_dev->files[fusd_file->index] = fusd_file; - /* store the pointer to this file with the kernel */ - file->private_data = fusd_file; - *fusd_file_ret = fusd_file; + /* store the pointer to this file with the kernel */ + file->private_data = fusd_file; + *fusd_file_ret = fusd_file; - /* success! */ - return 0; + /* success! */ + return 0; } -STATIC struct fusd_dev_t_s* find_user_device(int dev_id) +STATIC struct fusd_dev_t_s* find_user_device (int dev_id) { - struct list_head* entry; - down(&fusd_devlist_sem); - list_for_each(entry, &fusd_devlist_head) - { - fusd_dev_t *d = list_entry(entry, fusd_dev_t, devlist); - if(d->dev_id == dev_id) - { - up(&fusd_devlist_sem); - return d; - } - } - up(&fusd_devlist_sem); - return NULL; + struct list_head* entry; + down(&fusd_devlist_sem); + + list_for_each(entry, &fusd_devlist_head) + { + fusd_dev_t *d = list_entry(entry, fusd_dev_t, devlist); + if ( d->dev_id == dev_id ) + { + up(&fusd_devlist_sem); + return d; + } + } + up(&fusd_devlist_sem); + return NULL; } /* * A client has called open() has been called on a registered device. * See comment higher up for detailed notes on this function. */ -STATIC int fusd_client_open(struct inode *inode, struct file *file) +STATIC int fusd_client_open (struct inode *inode, struct file *file) { - int retval; - int device_freed = 0; - fusd_dev_t *fusd_dev = find_user_device(inode->i_rdev); - fusd_file_t *fusd_file; - fusd_msg_t fusd_msg; - struct fusd_transaction* transaction; - - /* If the device wasn't on our valid list, stop here. */ - if (!fusd_dev_is_valid(fusd_dev)) - return -ENOENT; + int retval; + int device_freed = 0; + fusd_dev_t *fusd_dev = find_user_device(inode->i_rdev); + fusd_file_t *fusd_file; + fusd_msg_t fusd_msg; + struct fusd_transaction* transaction; - /* fusd_dev->open_in_progress now set */ + /* If the device wasn't on our valid list, stop here. */ + if ( !fusd_dev_is_valid(fusd_dev) ) + return -ENOENT; - /* Lock the fusd device. Note, when we finally do acquire the lock, - * the device might be a zombie (driver disappeared). */ - RAWLOCK_FUSD_DEV(fusd_dev); + /* fusd_dev->open_in_progress now set */ - RDEBUG(3, "got an open for /dev/%s (owned by pid %d) from pid %d", - NAME(fusd_dev), fusd_dev->pid, current->pid); + /* Lock the fusd device. Note, when we finally do acquire the lock, + * the device might be a zombie (driver disappeared). */ + RAWLOCK_FUSD_DEV(fusd_dev); - /* Try to add ourselves to the device's file list. If retval==0, we - are now part of the file array. */ - retval = fusd_dev_add_file(file, fusd_dev, &fusd_file); + RDEBUG(3, "got an open for /dev/%s (owned by pid %d) from pid %d", + NAME(fusd_dev), fusd_dev->pid, current->pid); - /* - * It is now safe to unset the open_in_progress flag. Either: - * 1) We are part of the file array, so dev won't be freed, or; - * 2) Something failed, so we are returning a failure now and no - * longer need the device. - * Note, open_in_progress must be protected by the global sem, not - * the device lock, due to the access of it in fusd_dev_is_valid(). - */ - down(&fusd_devlist_sem); - fusd_dev->open_in_progress--; - up(&fusd_devlist_sem); + /* Try to add ourselves to the device's file list. If retval==0, we + are now part of the file array. */ + retval = fusd_dev_add_file(file, fusd_dev, &fusd_file); - /* If adding ourselves to the device list failed, give up. Possibly - * free the device if it was a zombie and waiting for us to complete - * our open. */ - if (retval < 0) { - if (!maybe_free_fusd_dev(fusd_dev)) + /* + * It is now safe to unset the open_in_progress flag. Either: + * 1) We are part of the file array, so dev won't be freed, or; + * 2) Something failed, so we are returning a failure now and no + * longer need the device. + * Note, open_in_progress must be protected by the global sem, not + * the device lock, due to the access of it in fusd_dev_is_valid(). + */ + down(&fusd_devlist_sem); + fusd_dev->open_in_progress--; + up(&fusd_devlist_sem); + + /* If adding ourselves to the device list failed, give up. Possibly + * free the device if it was a zombie and waiting for us to complete + * our open. */ + if ( retval < 0 ) + { + if ( !maybe_free_fusd_dev(fusd_dev) ) + UNLOCK_FUSD_DEV(fusd_dev); + return retval; + } + + /* send message to userspace and get retval */ + init_fusd_msg(&fusd_msg); + fusd_msg.subcmd = FUSD_OPEN; + + /* send message to userspace and get the reply. Device can't be + * locked during that operation. */ + + UNLOCK_FUSD_DEV(fusd_dev); + retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction); + + if ( retval >= 0 ) + retval = fusd_fops_call_wait(fusd_file, NULL, transaction); + RAWLOCK_FUSD_DEV(fusd_dev); + + /* If the device zombified (while we were waiting to reacquire the + * lock)... consider that a failure */ + if ( ZOMBIE(fusd_dev) ) + retval = -ENOENT; + + /* if retval is negative, throw away state... the file open failed */ + if ( retval < 0 ) + { + RDEBUG(3, "...open failed for /dev/%s (owned by pid %d) from pid %d", + NAME(fusd_dev), fusd_dev->pid, current->pid); + + device_freed = free_fusd_file(fusd_dev, fusd_file); + } + + /* Now unlock the device, if it still exists. (It may have been + * freed if the open failed, and we were the last outstanding + * request for it.) */ + if ( !device_freed ) UNLOCK_FUSD_DEV(fusd_dev); - return retval; - } - /* send message to userspace and get retval */ - init_fusd_msg(&fusd_msg); - fusd_msg.subcmd = FUSD_OPEN; - - /* send message to userspace and get the reply. Device can't be - * locked during that operation. */ - - UNLOCK_FUSD_DEV(fusd_dev); - retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction); - - if (retval >= 0) - retval = fusd_fops_call_wait(fusd_file, NULL, transaction); - RAWLOCK_FUSD_DEV(fusd_dev); - - /* If the device zombified (while we were waiting to reacquire the - * lock)... consider that a failure */ - if (ZOMBIE(fusd_dev)) - retval = -ENOENT; - - /* if retval is negative, throw away state... the file open failed */ - if (retval < 0) { - RDEBUG(3, "...open failed for /dev/%s (owned by pid %d) from pid %d", - NAME(fusd_dev), fusd_dev->pid, current->pid); - - device_freed = free_fusd_file(fusd_dev, fusd_file); - } - - /* Now unlock the device, if it still exists. (It may have been - * freed if the open failed, and we were the last outstanding - * request for it.) */ - if (!device_freed) - UNLOCK_FUSD_DEV(fusd_dev); - - return retval; + return retval; } - /* close() has been called on a registered device. like * fusd_client_open, we must lock the entire device. */ -STATIC int fusd_client_release(struct inode *inode, struct file *file) +STATIC int fusd_client_release (struct inode *inode, struct file *file) { - int retval; - fusd_file_t *fusd_file; - fusd_dev_t *fusd_dev; - fusd_msg_t fusd_msg; - struct fusd_transaction* transaction; - - GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); - LOCK_FUSD_FILE(fusd_file); + int retval; + fusd_file_t *fusd_file; + fusd_dev_t *fusd_dev; + fusd_msg_t fusd_msg; + struct fusd_transaction* transaction; - RDEBUG(3, "got a close on /dev/%s (owned by pid %d) from pid %d", - NAME(fusd_dev), fusd_dev->pid, current->pid); + GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); + LOCK_FUSD_FILE(fusd_file); - /* Tell the driver that the file closed, if it still exists. */ - init_fusd_msg(&fusd_msg); - fusd_msg.subcmd = FUSD_CLOSE; - retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction); - RDEBUG(5, "fusd_client_release: send returned %d", retval); - if (retval >= 0) - retval = fusd_fops_call_wait(fusd_file, NULL, transaction); - - RDEBUG(5, "fusd_client_release: call_wait %d", retval); - /* delete the file off the device's file-list, and free it. note - * that device may be a zombie right now and may be freed when we - * come back from free_fusd_file. we only release the lock if the - * device still exists. */ - RAWLOCK_FUSD_DEV(fusd_dev); - if (!free_fusd_file(fusd_dev, fusd_file)) { - UNLOCK_FUSD_DEV(fusd_dev); - } + RDEBUG(3, "got a close on /dev/%s (owned by pid %d) from pid %d", + NAME(fusd_dev), fusd_dev->pid, current->pid); - return retval; + /* Tell the driver that the file closed, if it still exists. */ + init_fusd_msg(&fusd_msg); + fusd_msg.subcmd = FUSD_CLOSE; + retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction); + RDEBUG(5, "fusd_client_release: send returned %d", retval); + if ( retval >= 0 ) + retval = fusd_fops_call_wait(fusd_file, NULL, transaction); - invalid_dev: - invalid_file: - RDEBUG(1, "got a close on client file from pid %d, INVALID DEVICE!", - current->pid); - return -EPIPE; + RDEBUG(5, "fusd_client_release: call_wait %d", retval); + /* delete the file off the device's file-list, and free it. note + * that device may be a zombie right now and may be freed when we + * come back from free_fusd_file. we only release the lock if the + * device still exists. */ + RAWLOCK_FUSD_DEV(fusd_dev); + if ( !free_fusd_file(fusd_dev, fusd_file) ) + { + UNLOCK_FUSD_DEV(fusd_dev); + } + + return retval; + +invalid_dev: + invalid_file : + RDEBUG(1, "got a close on client file from pid %d, INVALID DEVICE!", + current->pid); + return -EPIPE; } - - -STATIC ssize_t fusd_client_read(struct file *file , char *buf, - size_t count, loff_t *offset) +STATIC ssize_t fusd_client_read (struct file *file, char *buf, + size_t count, loff_t *offset) { - fusd_dev_t *fusd_dev; - fusd_file_t *fusd_file; - struct fusd_transaction* transaction; - fusd_msg_t fusd_msg, *reply = NULL; - int retval = -EPIPE; + fusd_dev_t *fusd_dev; + fusd_file_t *fusd_file; + struct fusd_transaction* transaction; + fusd_msg_t fusd_msg, *reply = NULL; + int retval = -EPIPE; - GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); + GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); - if(ZOMBIE(fusd_dev)) - goto zombie_dev; + if ( ZOMBIE(fusd_dev) ) + goto zombie_dev; - LOCK_FUSD_FILE(fusd_file); + LOCK_FUSD_FILE(fusd_file); - RDEBUG(3, "got a read on /dev/%s (owned by pid %d) from pid %d", - NAME(fusd_dev), fusd_dev->pid, current->pid); + RDEBUG(3, "got a read on /dev/%s (owned by pid %d) from pid %d", + NAME(fusd_dev), fusd_dev->pid, current->pid); - transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_READ); - if (transaction && transaction->size > count) - { - RDEBUG(2, "Incomplete I/O transaction %ld thrown out, as the transaction's size of %d bytes was greater than " - "the retry's size of %d bytes", transaction->transid, transaction->size, (int)count); + transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_READ); + if ( transaction && transaction->size > count ) + { + RDEBUG(2, "Incomplete I/O transaction %ld thrown out, as the transaction's size of %d bytes was greater than " + "the retry's size of %d bytes", transaction->transid, transaction->size, (int) count); - fusd_cleanup_transaction(fusd_file, transaction); - transaction = NULL; - } + fusd_cleanup_transaction(fusd_file, transaction); + transaction = NULL; + } - if(transaction == NULL) - { - /* make sure we aren't trying to read too big of a buffer */ - if (count > MAX_RW_SIZE) - count = MAX_RW_SIZE; - - /* send the message */ - init_fusd_msg(&fusd_msg); - fusd_msg.subcmd = FUSD_READ; - fusd_msg.parm.fops_msg.length = count; - - /* send message to userspace */ - if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0) + if ( transaction == NULL ) + { + /* make sure we aren't trying to read too big of a buffer */ + if ( count > MAX_RW_SIZE ) + count = MAX_RW_SIZE; + + /* send the message */ + init_fusd_msg(&fusd_msg); + fusd_msg.subcmd = FUSD_READ; + fusd_msg.parm.fops_msg.length = count; + + /* send message to userspace */ + if ( ( retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction) ) < 0 ) + goto done; + } + + /* and wait for the reply */ + /* todo: store and retrieve the transid from the interrupted messsage */ + retval = fusd_fops_call_wait(fusd_file, &reply, transaction); + + /* return immediately in case of error */ + if ( retval < 0 || reply == NULL ) goto done; - } - - /* and wait for the reply */ - /* todo: store and retrieve the transid from the interrupted messsage */ - retval = fusd_fops_call_wait(fusd_file, &reply, transaction); - /* return immediately in case of error */ - if (retval < 0 || reply == NULL) - goto done; + /* adjust the reval if the retval indicates a larger read than the + * data that was actually provided */ + if ( reply->datalen != retval ) + { + RDEBUG(1, "warning: /dev/%s driver (pid %d) claimed it returned %d bytes " + "on read but actually returned %d", + NAME(fusd_dev), fusd_dev->pid, retval, reply->datalen); + retval = reply->datalen; + } - /* adjust the reval if the retval indicates a larger read than the - * data that was actually provided */ - if (reply->datalen != retval) { - RDEBUG(1, "warning: /dev/%s driver (pid %d) claimed it returned %d bytes " - "on read but actually returned %d", - NAME(fusd_dev), fusd_dev->pid, retval, reply->datalen); - retval = reply->datalen; - } + /* adjust if the device driver gave us more data than the user asked for + * (bad! bad! why is the driver broken???) */ + if ( retval > count ) + { + RDEBUG(1, "warning: /dev/%s driver (pid %d) returned %d bytes on read but " + "the user only asked for %d", + NAME(fusd_dev), fusd_dev->pid, retval, (int) count); + retval = count; + } - /* adjust if the device driver gave us more data than the user asked for - * (bad! bad! why is the driver broken???) */ - if (retval > count) { - RDEBUG(1, "warning: /dev/%s driver (pid %d) returned %d bytes on read but " - "the user only asked for %d", - NAME(fusd_dev), fusd_dev->pid, retval, (int) count); - retval = count; - } + /* copy the offset back from the message */ + *offset = reply->parm.fops_msg.offset; - /* copy the offset back from the message */ - *offset = reply->parm.fops_msg.offset; - - /* IFF return value indicates data present, copy it back */ - if (retval > 0) { - if (copy_to_user(buf, reply->data, retval)) { - retval = -EFAULT; - goto done; - } - } - - done: - /* clear the readable bit of our cached poll state */ - fusd_file->cached_poll_state &= ~(FUSD_NOTIFY_INPUT); - - free_fusd_msg(&reply); - UNLOCK_FUSD_FILE(fusd_file); - return retval; - - invalid_file: - invalid_dev: - zombie_dev: - RDEBUG(3, "got a read on client file from pid %d, driver has disappeared", - current->pid); - return -EPIPE; -} - -STATIC int fusd_add_transaction(fusd_file_t *fusd_file, int transid, int subcmd, int size, struct fusd_transaction** out_transaction) -{ - struct fusd_transaction* transaction = (struct fusd_transaction*) KMALLOC(sizeof(struct fusd_transaction), GFP_KERNEL); - if(transaction == NULL) - return -ENOMEM; - - transaction->msg_in = NULL; - transaction->transid = transid; - transaction->subcmd = subcmd; - transaction->pid = current->pid; - transaction->size = size; - - down(&fusd_file->transactions_sem); - list_add_tail(&transaction->list, &fusd_file->transactions); - up(&fusd_file->transactions_sem); - - if(out_transaction != NULL) - *out_transaction = transaction; - - return 0; -} - -STATIC void fusd_cleanup_transaction(fusd_file_t *fusd_file, struct fusd_transaction* transaction) -{ - free_fusd_msg(&transaction->msg_in); - fusd_remove_transaction(fusd_file, transaction); -} - -STATIC void fusd_remove_transaction(fusd_file_t *fusd_file, struct fusd_transaction* transaction) -{ - down(&fusd_file->transactions_sem); - list_del(&transaction->list); - up(&fusd_file->transactions_sem); - - KFREE(transaction); -} - -STATIC struct fusd_transaction* fusd_find_transaction(fusd_file_t *fusd_file, int transid) -{ - struct list_head* i; - down(&fusd_file->transactions_sem); - list_for_each(i, &fusd_file->transactions) - { - struct fusd_transaction* transaction = list_entry(i, struct fusd_transaction, list); - if(transaction->transid == transid) - { - up(&fusd_file->transactions_sem); - return transaction; - } - } - up(&fusd_file->transactions_sem); - return NULL; -} - -STATIC struct fusd_transaction* fusd_find_transaction_by_pid(fusd_file_t *fusd_file, int pid) -{ - struct list_head* i; - down(&fusd_file->transactions_sem); - list_for_each(i, &fusd_file->transactions) - { - struct fusd_transaction* transaction = list_entry(i, struct fusd_transaction, list); - if(transaction->pid == pid) - { - up(&fusd_file->transactions_sem); - return transaction; - } - } - up(&fusd_file->transactions_sem); - return NULL; -} - -STATIC ssize_t fusd_client_write(struct file *file, - const char *buffer, - size_t length, - loff_t *offset) -{ - fusd_dev_t *fusd_dev; - fusd_file_t *fusd_file; - fusd_msg_t fusd_msg; - fusd_msg_t *reply = NULL; - int retval = -EPIPE; - struct fusd_transaction* transaction; - - GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); - - if(ZOMBIE(fusd_dev)) - goto zombie_dev; - - LOCK_FUSD_FILE(fusd_file); - - RDEBUG(3, "got a write on /dev/%s (owned by pid %d) from pid %d", - NAME(fusd_dev), fusd_dev->pid, current->pid); - - transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_WRITE); - if (transaction && transaction->size != length) - { - RDEBUG(2, "Incomplete I/O transaction %ld thrown out, as the transaction's size of %d bytes was not equal to " - "the retry's size of %d bytes", transaction->transid, transaction->size, (int) length); - - fusd_cleanup_transaction(fusd_file, transaction); - transaction = NULL; - } - if(transaction == NULL) - { - if (length < 0) { - RDEBUG(2, "fusd_client_write: got invalid length %d", (int) length); - retval = -EINVAL; - goto done; - } - - if (length > MAX_RW_SIZE) - length = MAX_RW_SIZE; - - init_fusd_msg(&fusd_msg); - - /* sigh.. i guess zero length writes should be legal */ - if (length > 0) { - if ((fusd_msg.data = VMALLOC(length)) == NULL) { - retval = -ENOMEM; - goto done; - } - - if (copy_from_user(fusd_msg.data, buffer, length)) { - retval = -EFAULT; - goto done; - } - fusd_msg.datalen = length; - } - - fusd_msg.subcmd = FUSD_WRITE; - fusd_msg.parm.fops_msg.length = length; - - if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0) - goto done; - } - /* todo: fix transid on restart */ - retval = fusd_fops_call_wait(fusd_file, &reply, transaction); - - if (retval < 0 || reply == NULL) - goto done; - - /* drivers should not write more bytes than they were asked to! */ - if (retval > length) { - RDEBUG(1, "warning: /dev/%s driver (pid %d) returned %d bytes on write; " - "the user only wanted %d", - NAME(fusd_dev), fusd_dev->pid, retval, (int) length); - retval = length; - } - - *offset = reply->parm.fops_msg.offset; - - /* all done! */ - - done: - /* clear the writable bit of our cached poll state */ - fusd_file->cached_poll_state &= ~(FUSD_NOTIFY_OUTPUT); - - free_fusd_msg(&reply); - UNLOCK_FUSD_FILE(fusd_file); - return retval; - - invalid_file: - invalid_dev: - zombie_dev: - RDEBUG(3, "got a write on client file from pid %d, driver has disappeared", - current->pid); - return -EPIPE; -} - - -STATIC int fusd_client_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - fusd_dev_t *fusd_dev; - fusd_file_t *fusd_file; - fusd_msg_t fusd_msg, *reply = NULL; - int retval = -EPIPE, dir, length; - struct fusd_transaction* transaction; - - GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); - - if(ZOMBIE(fusd_dev)) - goto zombie_dev; - - LOCK_FUSD_FILE(fusd_file); - - RDEBUG(3, "got an ioctl on /dev/%s (owned by pid %d) from pid %d", - NAME(fusd_dev), fusd_dev->pid, current->pid); - - dir = _IOC_DIR(cmd); - length = _IOC_SIZE(cmd); - - transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_IOCTL); - // todo: Check to make sure the transaction is for the same IOCTL - - if(transaction == NULL) - { - /* if we're trying to read or write, make sure length is sane */ - if ((dir & (_IOC_WRITE | _IOC_READ)) && - (length <= 0 || length > MAX_RW_SIZE)) + /* IFF return value indicates data present, copy it back */ + if ( retval > 0 ) + { + if ( copy_to_user(buf, reply->data, retval) ) { - RDEBUG(2, "client ioctl got crazy IOC_SIZE of %d", length); - retval = -EINVAL; - goto done; + retval = -EFAULT; + goto done; } - - /* fill the struct */ - init_fusd_msg(&fusd_msg); - fusd_msg.subcmd = FUSD_IOCTL; - fusd_msg.parm.fops_msg.cmd = cmd; - fusd_msg.parm.fops_msg.arg.arg = arg; - - /* get the data if user is trying to write to the driver */ - if (dir & _IOC_WRITE) { - if ((fusd_msg.data = VMALLOC(length)) == NULL) { - RDEBUG(2, "can't vmalloc for client ioctl!"); - retval = -ENOMEM; - goto done; - } - - if (copy_from_user(fusd_msg.data, (void *) arg, length)) { - retval = -EFAULT; - goto done; - } - fusd_msg.datalen = length; - } - - /* send request to the driver */ - if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0) - goto done; - } - /* get the response */ - /* todo: fix transid on restart */ - if ((retval = fusd_fops_call_wait(fusd_file, &reply, transaction)) < 0 || reply == NULL) - goto done; + } - /* if user is trying to read from the driver, copy data back */ - if (dir & _IOC_READ) { - if (reply->data == NULL || reply->datalen != length) { - RDEBUG(2, "client_ioctl read reply with screwy data (%d, %d)", - reply->datalen, length); - retval = -EIO; - goto done; - } - if (copy_to_user((void *)arg, reply->data, length)) { - retval = -EFAULT; - goto done; - } - } +done: + /* clear the readable bit of our cached poll state */ + fusd_file->cached_poll_state &= ~( FUSD_NOTIFY_INPUT ); - /* all done! */ - done: - free_fusd_msg(&reply); - UNLOCK_FUSD_FILE(fusd_file); - return retval; + free_fusd_msg(&reply); + UNLOCK_FUSD_FILE(fusd_file); + return retval; - invalid_file: - invalid_dev: - zombie_dev: - RDEBUG(3, "got an ioctl on client file from pid %d, driver has disappeared", - current->pid); - return -EPIPE; +invalid_file: + invalid_dev : + zombie_dev : + RDEBUG(3, "got a read on client file from pid %d, driver has disappeared", + current->pid); + return -EPIPE; } -static void fusd_client_mm_open(struct vm_area_struct * vma); -static void fusd_client_mm_close(struct vm_area_struct * vma); -static struct page* fusd_client_nopage(struct vm_area_struct* vma, unsigned long address, int* type); -static struct vm_operations_struct fusd_remap_vm_ops = + +STATIC int fusd_add_transaction (fusd_file_t *fusd_file, int transid, int subcmd, int size, struct fusd_transaction** out_transaction) { - open: fusd_client_mm_open, - close: fusd_client_mm_close, - nopage: fusd_client_nopage, + struct fusd_transaction* transaction = (struct fusd_transaction*) KMALLOC(sizeof (struct fusd_transaction), GFP_KERNEL); + if ( transaction == NULL ) + return -ENOMEM; + + transaction->msg_in = NULL; + transaction->transid = transid; + transaction->subcmd = subcmd; + transaction->pid = current->pid; + transaction->size = size; + + down(&fusd_file->transactions_sem); + list_add_tail(&transaction->list, &fusd_file->transactions); + up(&fusd_file->transactions_sem); + + if ( out_transaction != NULL ) + *out_transaction = transaction; + + return 0; +} + +STATIC void fusd_cleanup_transaction (fusd_file_t *fusd_file, struct fusd_transaction* transaction) +{ + free_fusd_msg(&transaction->msg_in); + fusd_remove_transaction(fusd_file, transaction); +} + +STATIC void fusd_remove_transaction (fusd_file_t *fusd_file, struct fusd_transaction* transaction) +{ + down(&fusd_file->transactions_sem); + list_del(&transaction->list); + up(&fusd_file->transactions_sem); + + KFREE(transaction); +} + +STATIC struct fusd_transaction* fusd_find_transaction (fusd_file_t *fusd_file, int transid) +{ + struct list_head* i; + down(&fusd_file->transactions_sem); + + list_for_each(i, &fusd_file->transactions) + { + struct fusd_transaction* transaction = list_entry(i, struct fusd_transaction, list); + if ( transaction->transid == transid ) + { + up(&fusd_file->transactions_sem); + return transaction; + } + } + up(&fusd_file->transactions_sem); + return NULL; +} + +STATIC struct fusd_transaction* fusd_find_transaction_by_pid (fusd_file_t *fusd_file, int pid) +{ + struct list_head* i; + down(&fusd_file->transactions_sem); + + list_for_each(i, &fusd_file->transactions) + { + struct fusd_transaction* transaction = list_entry(i, struct fusd_transaction, list); + if ( transaction->pid == pid ) + { + up(&fusd_file->transactions_sem); + return transaction; + } + } + up(&fusd_file->transactions_sem); + return NULL; +} + +STATIC ssize_t fusd_client_write (struct file *file, + const char *buffer, + size_t length, + loff_t *offset) +{ + fusd_dev_t *fusd_dev; + fusd_file_t *fusd_file; + fusd_msg_t fusd_msg; + fusd_msg_t *reply = NULL; + int retval = -EPIPE; + struct fusd_transaction* transaction; + + GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); + + if ( ZOMBIE(fusd_dev) ) + goto zombie_dev; + + LOCK_FUSD_FILE(fusd_file); + + RDEBUG(3, "got a write on /dev/%s (owned by pid %d) from pid %d", + NAME(fusd_dev), fusd_dev->pid, current->pid); + + transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_WRITE); + if ( transaction && transaction->size != length ) + { + RDEBUG(2, "Incomplete I/O transaction %ld thrown out, as the transaction's size of %d bytes was not equal to " + "the retry's size of %d bytes", transaction->transid, transaction->size, (int) length); + + fusd_cleanup_transaction(fusd_file, transaction); + transaction = NULL; + } + if ( transaction == NULL ) + { + if ( length < 0 ) + { + RDEBUG(2, "fusd_client_write: got invalid length %d", (int) length); + retval = -EINVAL; + goto done; + } + + if ( length > MAX_RW_SIZE ) + length = MAX_RW_SIZE; + + init_fusd_msg(&fusd_msg); + + /* sigh.. i guess zero length writes should be legal */ + if ( length > 0 ) + { + if ( ( fusd_msg.data = VMALLOC(length) ) == NULL ) + { + retval = -ENOMEM; + goto done; + } + + if ( copy_from_user(fusd_msg.data, buffer, length) ) + { + retval = -EFAULT; + goto done; + } + fusd_msg.datalen = length; + } + + fusd_msg.subcmd = FUSD_WRITE; + fusd_msg.parm.fops_msg.length = length; + + if ( ( retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction) ) < 0 ) + goto done; + } + /* todo: fix transid on restart */ + retval = fusd_fops_call_wait(fusd_file, &reply, transaction); + + if ( retval < 0 || reply == NULL ) + goto done; + + /* drivers should not write more bytes than they were asked to! */ + if ( retval > length ) + { + RDEBUG(1, "warning: /dev/%s driver (pid %d) returned %d bytes on write; " + "the user only wanted %d", + NAME(fusd_dev), fusd_dev->pid, retval, (int) length); + retval = length; + } + + *offset = reply->parm.fops_msg.offset; + + /* all done! */ + +done: + /* clear the writable bit of our cached poll state */ + fusd_file->cached_poll_state &= ~( FUSD_NOTIFY_OUTPUT ); + + free_fusd_msg(&reply); + UNLOCK_FUSD_FILE(fusd_file); + return retval; + +invalid_file: + invalid_dev : + zombie_dev : + RDEBUG(3, "got a write on client file from pid %d, driver has disappeared", + current->pid); + return -EPIPE; +} + +STATIC int fusd_client_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + fusd_dev_t *fusd_dev; + fusd_file_t *fusd_file; + fusd_msg_t fusd_msg, *reply = NULL; + int retval = -EPIPE, dir, length; + struct fusd_transaction* transaction; + + GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); + + if ( ZOMBIE(fusd_dev) ) + goto zombie_dev; + + LOCK_FUSD_FILE(fusd_file); + + RDEBUG(3, "got an ioctl on /dev/%s (owned by pid %d) from pid %d", + NAME(fusd_dev), fusd_dev->pid, current->pid); + + dir = _IOC_DIR(cmd); + length = _IOC_SIZE(cmd); + + transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_IOCTL); + // todo: Check to make sure the transaction is for the same IOCTL + + if ( transaction == NULL ) + { + /* if we're trying to read or write, make sure length is sane */ + if ( ( dir & ( _IOC_WRITE | _IOC_READ ) ) && + ( length <= 0 || length > MAX_RW_SIZE ) ) + { + RDEBUG(2, "client ioctl got crazy IOC_SIZE of %d", length); + retval = -EINVAL; + goto done; + } + + /* fill the struct */ + init_fusd_msg(&fusd_msg); + fusd_msg.subcmd = FUSD_IOCTL; + fusd_msg.parm.fops_msg.cmd = cmd; + fusd_msg.parm.fops_msg.arg.arg = arg; + + /* get the data if user is trying to write to the driver */ + if ( dir & _IOC_WRITE ) + { + if ( ( fusd_msg.data = VMALLOC(length) ) == NULL ) + { + RDEBUG(2, "can't vmalloc for client ioctl!"); + retval = -ENOMEM; + goto done; + } + + if ( copy_from_user(fusd_msg.data, (void *) arg, length) ) + { + retval = -EFAULT; + goto done; + } + fusd_msg.datalen = length; + } + + /* send request to the driver */ + if ( ( retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction) ) < 0 ) + goto done; + } + /* get the response */ + /* todo: fix transid on restart */ + if ( ( retval = fusd_fops_call_wait(fusd_file, &reply, transaction) ) < 0 || reply == NULL ) + goto done; + + /* if user is trying to read from the driver, copy data back */ + if ( dir & _IOC_READ ) + { + if ( reply->data == NULL || reply->datalen != length ) + { + RDEBUG(2, "client_ioctl read reply with screwy data (%d, %d)", + reply->datalen, length); + retval = -EIO; + goto done; + } + if ( copy_to_user((void *) arg, reply->data, length) ) + { + retval = -EFAULT; + goto done; + } + } + + /* all done! */ +done: + free_fusd_msg(&reply); + UNLOCK_FUSD_FILE(fusd_file); + return retval; + +invalid_file: + invalid_dev : + zombie_dev : + RDEBUG(3, "got an ioctl on client file from pid %d, driver has disappeared", + current->pid); + return -EPIPE; +} +static void fusd_client_mm_open (struct vm_area_struct * vma); +static void fusd_client_mm_close (struct vm_area_struct * vma); +static int fusd_client_fault (struct vm_area_struct *vma, struct vm_fault *vmf, int *type); +static struct vm_operations_struct fusd_remap_vm_ops ={ + open : fusd_client_mm_open, + close : fusd_client_mm_close, + fault : fusd_client_fault, }; struct fusd_mmap_instance { - fusd_dev_t* fusd_dev; - fusd_file_t* fusd_file; - unsigned long addr; - int size; - atomic_t refcount; + fusd_dev_t* fusd_dev; + fusd_file_t* fusd_file; + unsigned long addr; + int size; + atomic_t refcount; }; -static void fusd_client_mm_open(struct vm_area_struct * vma) +static void fusd_client_mm_open (struct vm_area_struct * vma) { - struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data; - atomic_inc(&mmap_instance->refcount); - + struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data; + atomic_inc(&mmap_instance->refcount); + } -static void fusd_client_mm_close(struct vm_area_struct * vma) +static void fusd_client_mm_close (struct vm_area_struct * vma) { - struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data; - if(atomic_dec_and_test(&mmap_instance->refcount)) - { - KFREE(mmap_instance); - } + struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data; + if ( atomic_dec_and_test(&mmap_instance->refcount) ) + { + KFREE(mmap_instance); + } } -static int fusd_client_mmap(struct file *file, struct vm_area_struct * vma) +static int fusd_client_mmap (struct file *file, struct vm_area_struct * vma) { - fusd_dev_t *fusd_dev; - fusd_file_t *fusd_file; - struct fusd_transaction* transaction; - fusd_msg_t fusd_msg, *reply = NULL; - int retval = -EPIPE; - struct fusd_mmap_instance* mmap_instance; + fusd_dev_t *fusd_dev; + fusd_file_t *fusd_file; + struct fusd_transaction* transaction; + fusd_msg_t fusd_msg, *reply = NULL; + int retval = -EPIPE; + struct fusd_mmap_instance* mmap_instance; - GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); + GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); - if(ZOMBIE(fusd_dev)) - goto zombie_dev; + if ( ZOMBIE(fusd_dev) ) + goto zombie_dev; - LOCK_FUSD_FILE(fusd_file); + LOCK_FUSD_FILE(fusd_file); - RDEBUG(3, "got a mmap on /dev/%s (owned by pid %d) from pid %d", - NAME(fusd_dev), fusd_dev->pid, current->pid); + RDEBUG(3, "got a mmap on /dev/%s (owned by pid %d) from pid %d", + NAME(fusd_dev), fusd_dev->pid, current->pid); - transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_MMAP); + transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_MMAP); - if(transaction == NULL) - { - /* send the message */ - init_fusd_msg(&fusd_msg); - fusd_msg.subcmd = FUSD_MMAP; - fusd_msg.parm.fops_msg.offset = vma->vm_pgoff << PAGE_SHIFT; - fusd_msg.parm.fops_msg.flags = vma->vm_flags; - fusd_msg.parm.fops_msg.length = vma->vm_end - vma->vm_start; - - /* send message to userspace */ - if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0) - goto done; - } - - /* and wait for the reply */ - /* todo: store and retrieve the transid from the interrupted messsage */ - retval = fusd_fops_call_wait(fusd_file, &reply, transaction); - - mmap_instance = - (struct fusd_mmap_instance*) KMALLOC(sizeof(struct fusd_mmap_instance), GFP_KERNEL); - // todo: free this thing at some point - - mmap_instance->fusd_dev = fusd_dev; - mmap_instance->fusd_file = fusd_file; - mmap_instance->addr = reply->parm.fops_msg.arg.arg; - mmap_instance->size = reply->parm.fops_msg.length; - atomic_set(&mmap_instance->refcount, 0); - - retval = reply->parm.fops_msg.retval; - - vma->vm_private_data = mmap_instance; - vma->vm_ops = &fusd_remap_vm_ops; - vma->vm_flags |= VM_RESERVED; - - fusd_client_mm_open(vma); - - done: - free_fusd_msg(&reply); - UNLOCK_FUSD_FILE(fusd_file); - return retval; + if ( transaction == NULL ) + { + /* send the message */ + init_fusd_msg(&fusd_msg); + fusd_msg.subcmd = FUSD_MMAP; + fusd_msg.parm.fops_msg.offset = vma->vm_pgoff << PAGE_SHIFT; + fusd_msg.parm.fops_msg.flags = vma->vm_flags; + fusd_msg.parm.fops_msg.length = vma->vm_end - vma->vm_start; - invalid_file: - invalid_dev: - zombie_dev: - RDEBUG(3, "got a mmap on client file from pid %d, driver has disappeared", - current->pid); - return -EPIPE; + /* send message to userspace */ + if ( ( retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction) ) < 0 ) + goto done; + } + + /* and wait for the reply */ + /* todo: store and retrieve the transid from the interrupted messsage */ + retval = fusd_fops_call_wait(fusd_file, &reply, transaction); + + mmap_instance = + (struct fusd_mmap_instance*) KMALLOC(sizeof (struct fusd_mmap_instance), GFP_KERNEL); + // todo: free this thing at some point + + mmap_instance->fusd_dev = fusd_dev; + mmap_instance->fusd_file = fusd_file; + mmap_instance->addr = reply->parm.fops_msg.arg.arg; + mmap_instance->size = reply->parm.fops_msg.length; + atomic_set(&mmap_instance->refcount, 0); + + retval = reply->parm.fops_msg.retval; + + vma->vm_private_data = mmap_instance; + vma->vm_ops = &fusd_remap_vm_ops; + vma->vm_flags |= VM_RESERVED; + + fusd_client_mm_open(vma); + +done: + free_fusd_msg(&reply); + UNLOCK_FUSD_FILE(fusd_file); + return retval; + +invalid_file: + invalid_dev : + zombie_dev : + RDEBUG(3, "got a mmap on client file from pid %d, driver has disappeared", + current->pid); + return -EPIPE; } -static struct page* fusd_client_nopage(struct vm_area_struct* vma, unsigned long address, - int* type) +static int fusd_client_fault (struct vm_area_struct *vma, struct vm_fault *vmf, int *type) { - struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data; - unsigned long offset; - struct page *page = NOPAGE_SIGBUS; - int result; - offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); - // todo: worry about size - if(offset > mmap_instance->size) - goto out; - - down_read(&mmap_instance->fusd_dev->task->mm->mmap_sem); - result = get_user_pages(mmap_instance->fusd_dev->task, mmap_instance->fusd_dev->task->mm, mmap_instance->addr + offset, 1, 1, 0, &page, NULL); - up_read(&mmap_instance->fusd_dev->task->mm->mmap_sem); - - - if(PageAnon(page)) - { - RDEBUG(2, "Cannot mmap anonymous pages. Be sure to allocate your shared buffer with MAP_SHARED | MAP_ANONYMOUS"); - return NOPAGE_SIGBUS; - } - - if(result > 0) - { - get_page(page); - if (type) - *type = VM_FAULT_MINOR; - } + struct fusd_mmap_instance* mmap_instance = (struct fusd_mmap_instance*) vma->vm_private_data; + unsigned long offset; + struct page *page = NULL; + int result; + + offset = ( (unsigned long) vmf->virtual_address - vma->vm_start ) + ( vma->vm_pgoff << PAGE_SHIFT ); + // todo: worry about size + if ( offset > mmap_instance->size ) + goto out; + + down_read(&mmap_instance->fusd_dev->task->mm->mmap_sem); + result = get_user_pages(mmap_instance->fusd_dev->task, mmap_instance->fusd_dev->task->mm, mmap_instance->addr + offset, 1, 1, 0, &page, NULL); + up_read(&mmap_instance->fusd_dev->task->mm->mmap_sem); + + + if ( PageAnon(vmf->page) ) + { + RDEBUG(2, "Cannot mmap anonymous pages. Be sure to allocate your shared buffer with MAP_SHARED | MAP_ANONYMOUS"); + return VM_FAULT_SIGBUS; + } + + if ( result > 0 ) + { + get_page(page); + vmf->page = page; + if ( type ) + *type = VM_FAULT_MINOR; + } out: - return page; - - + return 0; } - /* * The design of poll for clients is a bit subtle. * @@ -1720,93 +1843,97 @@ out: * cached from the driver. * */ -STATIC unsigned int fusd_client_poll(struct file *file, poll_table *wait) +STATIC unsigned int fusd_client_poll (struct file *file, poll_table *wait) { - fusd_dev_t *fusd_dev; - fusd_file_t *fusd_file; - int kernel_bits = 0; - int send_poll = 0; + fusd_dev_t *fusd_dev; + fusd_file_t *fusd_file; + int kernel_bits = 0; + int send_poll = 0; - GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); - LOCK_FUSD_FILE(fusd_file); - LOCK_FUSD_DEV(fusd_dev); + GET_FUSD_FILE_AND_DEV(file->private_data, fusd_file, fusd_dev); + LOCK_FUSD_FILE(fusd_file); + LOCK_FUSD_DEV(fusd_dev); - RDEBUG(3, "got a select on /dev/%s (owned by pid %d) from pid %d, cps=%d", - NAME(fusd_dev), fusd_dev->pid, current->pid, - fusd_file->cached_poll_state); + RDEBUG(3, "got a select on /dev/%s (owned by pid %d) from pid %d, cps=%d", + NAME(fusd_dev), fusd_dev->pid, current->pid, + fusd_file->cached_poll_state); - poll_wait(file, &fusd_file->poll_wait, wait); + poll_wait(file, &fusd_file->poll_wait, wait); - /* - * If our currently cached poll state is not the same as the - * most-recently-sent polldiff request, then, dispatch a new - * request. (We DO NOT wait for a reply, but just dispatch the - * request). - * - * Also, don't send a new polldiff if the most recent one resulted - * in an error. - */ - if (fusd_file->last_poll_sent != fusd_file->cached_poll_state && - fusd_file->cached_poll_state >= 0) { - RDEBUG(3, "sending polldiff request because lps=%d, cps=%d", - fusd_file->last_poll_sent, fusd_file->cached_poll_state); - send_poll = 1; - fusd_file->last_poll_sent = fusd_file->cached_poll_state; - } + /* + * If our currently cached poll state is not the same as the + * most-recently-sent polldiff request, then, dispatch a new + * request. (We DO NOT wait for a reply, but just dispatch the + * request). + * + * Also, don't send a new polldiff if the most recent one resulted + * in an error. + */ + if ( fusd_file->last_poll_sent != fusd_file->cached_poll_state && + fusd_file->cached_poll_state >= 0 ) + { + RDEBUG(3, "sending polldiff request because lps=%d, cps=%d", + fusd_file->last_poll_sent, fusd_file->cached_poll_state); + send_poll = 1; + fusd_file->last_poll_sent = fusd_file->cached_poll_state; + } - /* compute what to return for the state we had cached, converting to - * bits that have meaning to the kernel */ - if (fusd_file->cached_poll_state > 0) { - if (fusd_file->cached_poll_state & FUSD_NOTIFY_INPUT) - kernel_bits |= POLLIN; - if (fusd_file->cached_poll_state & FUSD_NOTIFY_OUTPUT) - kernel_bits |= POLLOUT; - if (fusd_file->cached_poll_state & FUSD_NOTIFY_EXCEPT) - kernel_bits |= POLLPRI; - } + /* compute what to return for the state we had cached, converting to + * bits that have meaning to the kernel */ + if ( fusd_file->cached_poll_state > 0 ) + { + if ( fusd_file->cached_poll_state & FUSD_NOTIFY_INPUT ) + kernel_bits |= POLLIN; + if ( fusd_file->cached_poll_state & FUSD_NOTIFY_OUTPUT ) + kernel_bits |= POLLOUT; + if ( fusd_file->cached_poll_state & FUSD_NOTIFY_EXCEPT ) + kernel_bits |= POLLPRI; + } - /* Now that we've committed to sending the poll, etc., it should be - * safe to unlock the device */ - UNLOCK_FUSD_DEV(fusd_dev); - UNLOCK_FUSD_FILE(fusd_file); + /* Now that we've committed to sending the poll, etc., it should be + * safe to unlock the device */ + UNLOCK_FUSD_DEV(fusd_dev); + UNLOCK_FUSD_FILE(fusd_file); - if (send_poll) { - fusd_msg_t fusd_msg; + if ( send_poll ) + { + fusd_msg_t fusd_msg; - init_fusd_msg(&fusd_msg); - fusd_msg.cmd = FUSD_FOPS_NONBLOCK; - fusd_msg.subcmd = FUSD_POLL_DIFF; - fusd_msg.parm.fops_msg.cmd = fusd_file->cached_poll_state; - if (fusd_fops_call_send(fusd_file, &fusd_msg, NULL) < 0) { - /* If poll dispatched failed, set back to -1 so we try again. - * Not a race (I think), since sending an *extra* polldiff never - * hurts anything. */ - fusd_file->last_poll_sent = -1; - } - } - return kernel_bits; + init_fusd_msg(&fusd_msg); + fusd_msg.cmd = FUSD_FOPS_NONBLOCK; + fusd_msg.subcmd = FUSD_POLL_DIFF; + fusd_msg.parm.fops_msg.cmd = fusd_file->cached_poll_state; + if ( fusd_fops_call_send(fusd_file, &fusd_msg, NULL) < 0 ) + { + /* If poll dispatched failed, set back to -1 so we try again. + * Not a race (I think), since sending an *extra* polldiff never + * hurts anything. */ + fusd_file->last_poll_sent = -1; + } + } + return kernel_bits; - zombie_dev: - /* might jump here from LOCK_FUSD_DEV */ - UNLOCK_FUSD_FILE(fusd_file); - invalid_dev: - invalid_file: - RDEBUG(3, "got a select on client file from pid %d, driver has disappeared", - current->pid); - return POLLPRI; +zombie_dev: + /* might jump here from LOCK_FUSD_DEV */ + UNLOCK_FUSD_FILE(fusd_file); +invalid_dev: + invalid_file : + RDEBUG(3, "got a select on client file from pid %d, driver has disappeared", + current->pid); + return POLLPRI; } STATIC struct file_operations fusd_client_fops = { - owner: THIS_MODULE, - open: fusd_client_open, - release: fusd_client_release, - read: fusd_client_read, - write: fusd_client_write, - ioctl: fusd_client_ioctl, - poll: fusd_client_poll, - mmap: fusd_client_mmap + owner : THIS_MODULE, + open : fusd_client_open, + release : fusd_client_release, + read : fusd_client_read, + write : fusd_client_write, + ioctl : fusd_client_ioctl, + poll : fusd_client_poll, + mmap : fusd_client_mmap }; @@ -1815,320 +1942,376 @@ STATIC struct file_operations fusd_client_fops = { /*************************************************************************/ -STATIC fusd_file_t *find_fusd_reply_file(fusd_dev_t *fusd_dev, fusd_msg_t *msg) +STATIC fusd_file_t *find_fusd_reply_file (fusd_dev_t *fusd_dev, fusd_msg_t *msg) { - /* first, try the hint */ - int i = msg->parm.fops_msg.hint; - if (i >= 0 && - i < fusd_dev->num_files && - fusd_dev->files[i] == msg->parm.fops_msg.fusd_file) - { + /* first, try the hint */ + int i = msg->parm.fops_msg.hint; + if ( i >= 0 && + i < fusd_dev->num_files && + fusd_dev->files[i] == msg->parm.fops_msg.fusd_file ) + { RDEBUG(15, "find_fusd_reply_file: hint worked"); - } else { + } + else + { /* hint didn't work, fall back to a search of the whole array */ i = find_fusd_file(fusd_dev, msg->parm.fops_msg.fusd_file); RDEBUG(15, "find_fusd_reply_file: hint failed"); - } + } - /* we couldn't find anyone waiting for this message! */ - if (i < 0) { - return NULL; - } else { - return fusd_dev->files[i]; - } + /* we couldn't find anyone waiting for this message! */ + if ( i < 0 ) + { + return NULL; + } + else + { + return fusd_dev->files[i]; + } } - /* Process an incoming reply to a message dispatched by * fusd_fops_call. Called by fusd_write when a driver writes to * /dev/fusd. */ -STATIC int fusd_fops_reply(fusd_dev_t *fusd_dev, fusd_msg_t *msg) +STATIC int fusd_fops_reply (fusd_dev_t *fusd_dev, fusd_msg_t *msg) { - fusd_file_t *fusd_file; - struct fusd_transaction *transaction; + fusd_file_t *fusd_file; + struct fusd_transaction *transaction; - /* figure out the index of the file we are replying to. usually - * very fast (uses a hint) */ - if ((fusd_file = find_fusd_reply_file(fusd_dev, msg)) == NULL) { - RDEBUG(2, "fusd_fops_reply: got a reply on /dev/%s with no connection", - NAME(fusd_dev)); - goto discard; - } + /* figure out the index of the file we are replying to. usually + * very fast (uses a hint) */ + if ( ( fusd_file = find_fusd_reply_file(fusd_dev, msg) ) == NULL ) + { + RDEBUG(2, "fusd_fops_reply: got a reply on /dev/%s with no connection", + NAME(fusd_dev)); + goto discard; + } - /* make sure this is not an old reply going to an old instance that's gone */ - /* todo: kor fix this */ -/* - if (fusd_file->fusd_dev_version != fusd_dev->version || - msg->parm.fops_msg.transid != fusd_file->transid_outstanding) { - RDEBUG(2, "fusd_fops_reply: got an old message, discarding"); - goto discard; - }*/ - - transaction = fusd_find_transaction(fusd_file, msg->parm.fops_msg.transid); - if(transaction == NULL) - { - RDEBUG(2, "fusd_fops_reply: No transaction found with transid %ld", msg->parm.fops_msg.transid); - goto discard; - } - - RDEBUG(10, "fusd_fops_reply: /dev/%s completed transid %ld (retval %d)", - NAME(fusd_dev), msg->parm.fops_msg.transid, - (int) msg->parm.fops_msg.retval); + /* make sure this is not an old reply going to an old instance that's gone */ + /* todo: kor fix this */ + /* + if (fusd_file->fusd_dev_version != fusd_dev->version || + msg->parm.fops_msg.transid != fusd_file->transid_outstanding) { + RDEBUG(2, "fusd_fops_reply: got an old message, discarding"); + goto discard; + }*/ - transaction->msg_in = msg; - mb(); + transaction = fusd_find_transaction(fusd_file, msg->parm.fops_msg.transid); + if ( transaction == NULL ) + { + RDEBUG(2, "fusd_fops_reply: No transaction found with transid %ld", msg->parm.fops_msg.transid); + goto discard; + } - WAKE_UP_INTERRUPTIBLE_SYNC(&fusd_file->file_wait); + RDEBUG(10, "fusd_fops_reply: /dev/%s completed transid %ld (retval %d)", + NAME(fusd_dev), msg->parm.fops_msg.transid, + (int) msg->parm.fops_msg.retval); - return 0; + transaction->msg_in = msg; + mb(); - discard: - if (msg->subcmd == FUSD_OPEN && msg->parm.fops_msg.retval == 0) { - fusd_forge_close(msg, fusd_dev); - return 0; - } else { - return -EPIPE; - } + WAKE_UP_INTERRUPTIBLE_SYNC(&fusd_file->file_wait); + + return 0; + +discard: + if ( msg->subcmd == FUSD_OPEN && msg->parm.fops_msg.retval == 0 ) + { + fusd_forge_close(msg, fusd_dev); + return 0; + } + else + { + return -EPIPE; + } } - /* special function to process responses to POLL_DIFF */ -STATIC int fusd_polldiff_reply(fusd_dev_t *fusd_dev, fusd_msg_t *msg) +STATIC int fusd_polldiff_reply (fusd_dev_t *fusd_dev, fusd_msg_t *msg) { - fusd_file_t *fusd_file; + fusd_file_t *fusd_file; - /* figure out the index of the file we are replying to. usually - * very fast (uses a hint) */ - if ((fusd_file = find_fusd_reply_file(fusd_dev, msg)) == NULL) - return -EPIPE; + /* figure out the index of the file we are replying to. usually + * very fast (uses a hint) */ + if ( ( fusd_file = find_fusd_reply_file(fusd_dev, msg) ) == NULL ) + return -EPIPE; - /* record the poll state returned. convert all negative retvals to -1. */ - if ((fusd_file->cached_poll_state = msg->parm.fops_msg.retval) < 0) - fusd_file->cached_poll_state = -1; + /* record the poll state returned. convert all negative retvals to -1. */ + if ( ( fusd_file->cached_poll_state = msg->parm.fops_msg.retval ) < 0 ) + fusd_file->cached_poll_state = -1; - RDEBUG(3, "got updated poll state from /dev/%s driver: %d", NAME(fusd_dev), - fusd_file->cached_poll_state); + RDEBUG(3, "got updated poll state from /dev/%s driver: %d", NAME(fusd_dev), + fusd_file->cached_poll_state); - /* since the client has returned the polldiff we sent, set - * last_poll_sent to -1, so that we'll send a polldiff request on - * the next select. */ - fusd_file->last_poll_sent = -1; + /* since the client has returned the polldiff we sent, set + * last_poll_sent to -1, so that we'll send a polldiff request on + * the next select. */ + fusd_file->last_poll_sent = -1; - /* wake up select's queue so that a new polldiff is generated */ - wake_up_interruptible(&fusd_file->poll_wait); + /* wake up select's queue so that a new polldiff is generated */ + wake_up_interruptible(&fusd_file->poll_wait); - return 0; + return 0; } -STATIC int systest (struct super_block *sb,void *data){ - return 1; +STATIC int systest (struct super_block *sb, void *data) +{ + return 1; } -STATIC int fusd_register_device(fusd_dev_t *fusd_dev, - register_msg_t register_msg) +STATIC int fusd_register_device (fusd_dev_t *fusd_dev, + register_msg_t register_msg) { - int error = 0; - struct list_head *tmp; - int dev_id; + int error = 0; + struct list_head *tmp; + int dev_id; - /* make sure args are valid */ - if (fusd_dev == NULL) { - RDEBUG(0, "fusd_register_device: bug in arguments!"); - return -EINVAL; - } + /* make sure args are valid */ + if ( fusd_dev == NULL ) + { + RDEBUG(0, "fusd_register_device: bug in arguments!"); + return -EINVAL; + } - register_msg.name[FUSD_MAX_NAME_LENGTH] = '\0'; + register_msg.name[FUSD_MAX_NAME_LENGTH] = '\0'; - /* make sure that there isn't already a device by this name */ - down(&fusd_devlist_sem); - list_for_each(tmp, &fusd_devlist_head) { - fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist); - + /* make sure that there isn't already a device by this name */ + down(&fusd_devlist_sem); - if (d && d->name && !d->zombie && !strcmp(d->name, register_msg.name)) { - error = -EEXIST; - break; - } - } - up(&fusd_devlist_sem); - - if (error) - return error; + list_for_each(tmp, &fusd_devlist_head) + { + fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist); - /* allocate memory for the name, and copy */ - if ((fusd_dev->name = KMALLOC(strlen(register_msg.name)+1, GFP_KERNEL)) == NULL) { - RDEBUG(1, "yikes! kernel can't allocate memory"); - return -ENOMEM; - } - - strcpy(fusd_dev->name, register_msg.name); + if ( d && d->name && !d->zombie && !strcmp(d->name, register_msg.name) ) + { + error = -EEXIST; + break; + } + } - /* allocate memory for the class name, and copy */ - if ((fusd_dev->class_name = KMALLOC(strlen(register_msg.clazz)+1, GFP_KERNEL)) == NULL) { - RDEBUG(1, "yikes! kernel can't allocate memory"); - return -ENOMEM; - } - - strcpy(fusd_dev->class_name, register_msg.clazz); - - /* allocate memory for the class name, and copy */ - if ((fusd_dev->dev_name = KMALLOC(strlen(register_msg.devname)+1, GFP_KERNEL)) == NULL) { - RDEBUG(1, "yikes! kernel can't allocate memory"); - return -ENOMEM; - } - - strcpy(fusd_dev->dev_name, register_msg.devname); - - dev_id = 0; - - if((error = alloc_chrdev_region(&dev_id, 0, 1, fusd_dev->name)) < 0) - { + up(&fusd_devlist_sem); + + if ( error ) + return error; + + /* allocate memory for the name, and copy */ + if ( ( fusd_dev->name = KMALLOC(strlen(register_msg.name) + 1, GFP_KERNEL) ) == NULL ) + { + RDEBUG(1, "yikes! kernel can't allocate memory"); + return -ENOMEM; + } + + strcpy(fusd_dev->name, register_msg.name); + + /* allocate memory for the class name, and copy */ + if ( ( fusd_dev->class_name = KMALLOC(strlen(register_msg.clazz) + 1, GFP_KERNEL) ) == NULL ) + { + RDEBUG(1, "yikes! kernel can't allocate memory"); + return -ENOMEM; + } + + strcpy(fusd_dev->class_name, register_msg.clazz); + + /* allocate memory for the class name, and copy */ + if ( ( fusd_dev->dev_name = KMALLOC(strlen(register_msg.devname) + 1, GFP_KERNEL) ) == NULL ) + { + RDEBUG(1, "yikes! kernel can't allocate memory"); + return -ENOMEM; + } + + strcpy(fusd_dev->dev_name, register_msg.devname); + + dev_id = 0; + + if ( ( error = alloc_chrdev_region(&dev_id, 0, 1, fusd_dev->name) ) < 0 ) + { printk(KERN_ERR "alloc_chrdev_region failed status: %d\n", error); goto register_failed; - } - - fusd_dev->dev_id = dev_id; - - fusd_dev->handle = cdev_alloc(); - if(fusd_dev->handle == NULL) - { + } + + fusd_dev->dev_id = dev_id; + + fusd_dev->handle = cdev_alloc(); + if ( fusd_dev->handle == NULL ) + { printk(KERN_ERR "cdev_alloc() failed\n"); error = -ENOMEM; goto register_failed3; - } - - fusd_dev->handle->owner = THIS_MODULE; - fusd_dev->handle->ops = &fusd_client_fops; - - kobject_set_name(&fusd_dev->handle->kobj, fusd_dev->name); - - if((error = cdev_add(fusd_dev->handle, dev_id, 1)) < 0) - { + } + + fusd_dev->handle->owner = THIS_MODULE; + fusd_dev->handle->ops = &fusd_client_fops; + + kobject_set_name(&fusd_dev->handle->kobj, fusd_dev->name); + + if ( ( error = cdev_add(fusd_dev->handle, dev_id, 1) ) < 0 ) + { printk(KERN_ERR "cdev_add failed status: %d\n", error); kobject_put(&fusd_dev->handle->kobj); goto register_failed3; - } + } - /* look up class in sysfs */ + /* look up class in sysfs */ + { + struct CLASS *sys_class = NULL; + struct file_system_type *sysfs = get_fs_type("sysfs"); + struct dentry *classdir = NULL; + struct dentry *classdir2 = NULL; + struct super_block *sb = NULL; - { - struct CLASS *sys_class = NULL; - struct file_system_type *sysfs = get_fs_type("sysfs"); - struct dentry *classdir = NULL; - struct dentry *classdir2 = NULL; - struct super_block *sb = NULL; - - if(sysfs){ - sb = sget (sysfs, systest, NULL,NULL); - - /* because put_filesystem isn't exported */ - module_put(sysfs->owner); + if ( sysfs ) + { + /* Get FS superblock */ + sb = sget(sysfs, systest, NULL, NULL); - if(sb){ - struct dentry *root = sb->s_root; + /* because put_filesystem isn't exported */ + module_put(sysfs->owner); - if(root){ - struct qstr name; + if ( sb ) + { + /* Take root entry from SuperBlock */ + struct dentry *root = sb->s_root; + + if ( root ) + { + struct qstr name; - name.name = "class"; - name.len = 5; - name.hash = full_name_hash(name.name, name.len); - classdir = d_lookup(root, &name); - - if(classdir){ - name.name = register_msg.clazz; - name.len = strlen(name.name); - name.hash = full_name_hash(name.name, name.len); - classdir2 = d_lookup(classdir, &name); - - if(classdir2){ - // jackpot. extract the class. - struct kobject *ko = to_kobj(classdir2); - sys_class = (ko?to_class(ko):NULL); + /* Search for directory "class" in the root of this filesystem */ + name.name = "class"; + name.len = 5; + name.hash = full_name_hash(name.name, name.len); + classdir = d_lookup(root, &name); - if(!sys_class) - RDEBUG(2, "WARNING: sysfs entry for %s has no kobject!\n",register_msg.clazz); - } - }else{ - RDEBUG(2, "WARNING: sysfs does not list a class directory!\n"); - } - }else{ - RDEBUG(2, "WARNING: unable to access root firectory in sysfs!\n"); - } - }else{ - RDEBUG(2, "WARNING: unable to access superblock for sysfs!\n"); + if ( classdir ) + { + /* Found, now search for class wanted name */ + name.name = register_msg.clazz; + name.len = strlen(name.name); + name.hash = full_name_hash(name.name, name.len); + classdir2 = d_lookup(classdir, &name); + + if ( classdir2 ) + { + // jackpot. extract the class. + struct kobject *ko = to_kobj(classdir2); + sys_class = ( ko ? to_class(ko)->class : NULL ); + + if ( sys_class ) + { + /* W T F ???? Using an existing sys_class will led to a NULL pointer crash + * during device creation.. Need more investigation, this comportement is clearly not + * normal. */ + RDEBUG(1, "ERROR: Using existing class name is currently unsported !!!"); + goto register_failed4; + } + + if ( !sys_class ) + RDEBUG(2, "WARNING: sysfs entry for %s has no kobject!\n", register_msg.clazz); + } + + } + else + { + RDEBUG(2, "WARNING: sysfs does not list a class directory!\n"); + } + } + else + { + RDEBUG(2, "WARNING: unable to access root firectory in sysfs!\n"); + } + } + else + { + RDEBUG(2, "WARNING: unable to access superblock for sysfs!\n"); + } + } + else + { + RDEBUG(2, "WARNING: sysfs not mounted or unavailable!\n"); } - }else{ - RDEBUG(2, "WARNING: sysfs not mounted or unavailable!\n"); - } - - if(sys_class){ - RDEBUG(3, "Found entry for class '%s' in sysfs\n",register_msg.clazz); - fusd_dev->clazz = sys_class; - fusd_dev->owns_class = 0; - }else{ - RDEBUG(3, "Sysfs has no entry for '%s'; registering new class\n",register_msg.clazz); - fusd_dev->clazz = class_create(THIS_MODULE, fusd_dev->class_name); - if(IS_ERR(fusd_dev->clazz)) - { - error = PTR_ERR(fusd_dev->clazz); - printk(KERN_ERR "class_create failed status: %d\n", error); - goto register_failed4; - } - fusd_dev->owns_class = 1; - } - if(classdir) - dput(classdir); - if(classdir2) - dput(classdir2); - - if(sb){ - up_write(&sb->s_umount); - deactivate_super(sb); - } - } - - fusd_dev->class_device = CLASS_DEVICE_CREATE(fusd_dev->clazz, NULL, fusd_dev->dev_id, NULL, fusd_dev->dev_name); - if(fusd_dev->class_device == NULL) - { - error = PTR_ERR(fusd_dev->class_device); - printk(KERN_ERR "class_device_create failed status: %d\n", error); + if ( sys_class ) + { + RDEBUG(3, "Found entry for class '%s' in sysfs\n", register_msg.clazz); + fusd_dev->clazz = sys_class; + fusd_dev->owns_class = 0; + } + else + { + RDEBUG(3, "Sysfs has no entry for '%s'; registering new class\n", register_msg.clazz); + fusd_dev->clazz = class_create(THIS_MODULE, fusd_dev->class_name); + if ( IS_ERR(fusd_dev->clazz) ) + { + error = PTR_ERR(fusd_dev->clazz); + printk(KERN_ERR "class_create failed status: %d\n", error); + goto register_failed4; + } + fusd_dev->owns_class = 1; + } + + if ( classdir ) + dput(classdir); + if ( classdir2 ) + dput(classdir2); + + if ( sb ) + { + up_write(&sb->s_umount); + deactivate_super(sb); + } + } + + /* Dump sys_class */ + RDEBUG(9, "fusd_dev->clazz = { .name='%s' .owner=%p .class_attrs=%p\n" + ".dev_attrs=%p .dev_kobj=%p .dev_uevent=%p\n" + ".devnode=%p .class_release=%p .dev_release=%p\n" + ".suspend=%p .resume=%p .pm=%p\n" + ".p = %p };", + fusd_dev->clazz->name, fusd_dev->clazz->owner, fusd_dev->clazz->class_attrs, + fusd_dev->clazz->dev_attrs, fusd_dev->clazz->dev_kobj, fusd_dev->clazz->dev_uevent, + fusd_dev->clazz->devnode, fusd_dev->clazz->class_release, fusd_dev->clazz->dev_release, + fusd_dev->clazz->suspend, fusd_dev->clazz->resume, fusd_dev->clazz->pm, fusd_dev->clazz->p); + fusd_dev->device = CLASS_DEVICE_CREATE(fusd_dev->clazz, NULL, fusd_dev->dev_id, NULL, fusd_dev->dev_name); + if ( fusd_dev->device == NULL ) + { + error = PTR_ERR(fusd_dev->device); + printk(KERN_ERR "device_create failed status: %d\n", error); goto register_failed5; - } - - /* make sure the registration was successful */ - if (fusd_dev->handle == 0) { - error = -EIO; - goto register_failed; - } - - /* remember the user's private data so we can pass it back later */ - fusd_dev->private_data = register_msg.device_info; - - /* everything ok */ - fusd_dev->version = atomic_inc_and_ret(&last_version); - RDEBUG(3, "pid %d registered /dev/%s v%ld", fusd_dev->pid, NAME(fusd_dev), - fusd_dev->version); - wake_up_interruptible(&new_device_wait); - return 0; + } + + /* make sure the registration was successful */ + if ( fusd_dev->handle == 0 ) + { + error = -EIO; + goto register_failed; + } + + /* remember the user's private data so we can pass it back later */ + fusd_dev->private_data = register_msg.device_info; + + /* everything ok */ + fusd_dev->version = atomic_inc_and_ret(&last_version); + RDEBUG(3, "pid %d registered /dev/%s v%ld", fusd_dev->pid, NAME(fusd_dev), + fusd_dev->version); + wake_up_interruptible(&new_device_wait); + return 0; register_failed5: - class_destroy(fusd_dev->clazz); - fusd_dev->clazz = NULL; + class_destroy(fusd_dev->clazz); + fusd_dev->clazz = NULL; register_failed4: - cdev_del(fusd_dev->handle); - fusd_dev->handle = NULL; + cdev_del(fusd_dev->handle); + fusd_dev->handle = NULL; register_failed3: - //register_failed2: - unregister_chrdev_region(dev_id, 1); + //register_failed2: + unregister_chrdev_region(dev_id, 1); register_failed: - KFREE(fusd_dev->name); - fusd_dev->name = NULL; - return error; + KFREE(fusd_dev->name); + fusd_dev->name = NULL; + return error; } @@ -2136,284 +2319,316 @@ register_failed: /******************** CONTROL CHANNEL CALLBACK FUNCTIONS ********************/ /****************************************************************************/ - /* open() called on /dev/fusd itself */ -STATIC int fusd_open(struct inode *inode, struct file *file) +STATIC int fusd_open (struct inode *inode, struct file *file) { - fusd_dev_t *fusd_dev = NULL; - fusd_file_t **file_array = NULL; + fusd_dev_t *fusd_dev = NULL; + fusd_file_t **file_array = NULL; - /* keep the module from being unloaded during initialization! */ - //MOD_INC_USE_COUNT; + /* keep the module from being unloaded during initialization! */ + //MOD_INC_USE_COUNT; - /* allocate memory for the device state */ - if ((fusd_dev = KMALLOC(sizeof(fusd_dev_t), GFP_KERNEL)) == NULL) - goto dev_malloc_failed; - memset(fusd_dev, 0, sizeof(fusd_dev_t)); + /* allocate memory for the device state */ + if ( ( fusd_dev = KMALLOC(sizeof (fusd_dev_t ), GFP_KERNEL) ) == NULL ) + goto dev_malloc_failed; + memset(fusd_dev, 0, sizeof (fusd_dev_t )); - if ((file_array = fusd_dev_adjsize(fusd_dev)) == NULL) - goto file_malloc_failed; + if ( ( file_array = fusd_dev_adjsize(fusd_dev) ) == NULL ) + goto file_malloc_failed; - init_waitqueue_head(&fusd_dev->dev_wait); - init_MUTEX(&fusd_dev->dev_sem); - fusd_dev->magic = FUSD_DEV_MAGIC; - fusd_dev->pid = current->pid; - fusd_dev->task = current; - file->private_data = fusd_dev; + init_waitqueue_head(&fusd_dev->dev_wait); + init_MUTEX(&fusd_dev->dev_sem); + fusd_dev->magic = FUSD_DEV_MAGIC; + fusd_dev->pid = current->pid; + fusd_dev->task = current; + file->private_data = fusd_dev; - /* add to the list of valid devices */ - down(&fusd_devlist_sem); - list_add(&fusd_dev->devlist, &fusd_devlist_head); - up(&fusd_devlist_sem); + /* add to the list of valid devices */ + down(&fusd_devlist_sem); + list_add(&fusd_dev->devlist, &fusd_devlist_head); + up(&fusd_devlist_sem); - RDEBUG(3, "pid %d opened /dev/fusd", fusd_dev->pid); - return 0; + RDEBUG(3, "pid %d opened /dev/fusd", fusd_dev->pid); + return 0; - file_malloc_failed: - KFREE(fusd_dev); - dev_malloc_failed: - RDEBUG(1, "out of memory in fusd_open!"); - //MOD_DEC_USE_COUNT; - return -ENOMEM; +file_malloc_failed: + KFREE(fusd_dev); +dev_malloc_failed: + RDEBUG(1, "out of memory in fusd_open!"); + //MOD_DEC_USE_COUNT; + return -ENOMEM; } - /* close() called on /dev/fusd itself. destroy the device that * was registered by it, if any. */ -STATIC int fusd_release(struct inode *inode, struct file *file) +STATIC int fusd_release (struct inode *inode, struct file *file) { - fusd_dev_t *fusd_dev; + fusd_dev_t *fusd_dev; - GET_FUSD_DEV(file->private_data, fusd_dev); - LOCK_FUSD_DEV(fusd_dev); + GET_FUSD_DEV(file->private_data, fusd_dev); + LOCK_FUSD_DEV(fusd_dev); - if (fusd_dev->pid != current->pid) { - RDEBUG(2, "yikes!: when releasing device, pid mismatch"); - } + if ( fusd_dev->pid != current->pid ) + { + RDEBUG(2, "yikes!: when releasing device, pid mismatch"); + } - RDEBUG(3, "pid %d closing /dev/fusd", current->pid); + RDEBUG(3, "pid %d closing /dev/fusd", current->pid); #if 0 - /* This delay is needed to exercise the openrace.c race condition, - * i.e. testing to make sure that our open_in_progress stuff works */ - { - int target = jiffies + 10*HZ; + /* This delay is needed to exercise the openrace.c race condition, + * i.e. testing to make sure that our open_in_progress stuff works */ + { + int target = jiffies + 10 * HZ; - RDEBUG(1, "starting to wait"); - while (jiffies < target) - schedule(); - RDEBUG(1, "stopping wait"); - } + RDEBUG(1, "starting to wait"); + while ( jiffies < target ) + schedule(); + RDEBUG(1, "stopping wait"); + } #endif - if(fusd_dev->handle){ - class_device_destroy(fusd_dev->clazz, fusd_dev->dev_id); - if(fusd_dev->owns_class) + if ( fusd_dev->handle ) + { + CLASS_DEVICE_DESTROY(fusd_dev->clazz, fusd_dev->dev_id); + if ( fusd_dev->owns_class ) { - class_destroy(fusd_dev->clazz); + class_destroy(fusd_dev->clazz); } - cdev_del(fusd_dev->handle); - unregister_chrdev_region(fusd_dev->dev_id, 1); - } + cdev_del(fusd_dev->handle); + unregister_chrdev_region(fusd_dev->dev_id, 1); + } - /* mark the driver as being gone */ - zombify_dev(fusd_dev); + /* mark the driver as being gone */ + zombify_dev(fusd_dev); - /* ...and possibly free it. (Release lock if it hasn't been freed) */ - if (!maybe_free_fusd_dev(fusd_dev)) - UNLOCK_FUSD_DEV(fusd_dev); + /* ...and possibly free it. (Release lock if it hasn't been freed) */ + if ( !maybe_free_fusd_dev(fusd_dev) ) + UNLOCK_FUSD_DEV(fusd_dev); - /* notify fusd_status readers that there has been a change in the - * list of registered devices */ - atomic_inc_and_ret(&last_version); - wake_up_interruptible(&new_device_wait); + /* notify fusd_status readers that there has been a change in the + * list of registered devices */ + atomic_inc_and_ret(&last_version); + wake_up_interruptible(&new_device_wait); - return 0; + return 0; - zombie_dev: - invalid_dev: - RDEBUG(1, "invalid device found in fusd_release!!"); - return -ENODEV; +zombie_dev: + invalid_dev : + RDEBUG(1, "invalid device found in fusd_release!!"); + return -ENODEV; } - /* * This function processes messages coming from userspace device drivers * (i.e., writes to the /dev/fusd control channel.) */ -STATIC ssize_t fusd_process_write(struct file *file, - const char *user_msg_buffer, size_t user_msg_len, - const char *user_data_buffer, size_t user_data_len) +STATIC ssize_t fusd_process_write (struct file *file, + const char *user_msg_buffer, size_t user_msg_len, + const char *user_data_buffer, size_t user_data_len) { - fusd_dev_t *fusd_dev; - fusd_msg_t *msg = NULL; - int retval = 0; - int yield = 0; + fusd_dev_t *fusd_dev; + fusd_msg_t *msg = NULL; + int retval = 0; + int yield = 0; - GET_FUSD_DEV(file->private_data, fusd_dev); - LOCK_FUSD_DEV(fusd_dev); + GET_FUSD_DEV(file->private_data, fusd_dev); + LOCK_FUSD_DEV(fusd_dev); - /* get the header from userspace (first make sure there's enough data) */ - if (user_msg_len != sizeof(fusd_msg_t)) { - RDEBUG(6, "control channel got bad write of %d bytes (wanted %d)", - (int) user_msg_len, (int) sizeof(fusd_msg_t)); - retval = -EINVAL; - goto out_no_free; - } - if ((msg = KMALLOC(sizeof(fusd_msg_t), GFP_KERNEL)) == NULL) { - retval = -ENOMEM; - RDEBUG(1, "yikes! kernel can't allocate memory"); - goto out; - } - memset(msg, 0, sizeof(fusd_msg_t)); - - if (copy_from_user(msg, user_msg_buffer, sizeof(fusd_msg_t))) { - retval = -EFAULT; - goto out; - } - msg->data = NULL; /* pointers from userspace have no meaning */ - - /* check the magic number before acting on the message at all */ - if (msg->magic != FUSD_MSG_MAGIC) { - RDEBUG(2, "got invalid magic number on /dev/fusd write from pid %d", - current->pid); - retval = -EIO; - goto out; - } - - /* now get data portion of the message */ - if (user_data_len < 0 || user_data_len > MAX_RW_SIZE) { - RDEBUG(2, "fusd_process_write: got invalid length %d", (int) user_data_len); - retval = -EINVAL; - goto out; - } - if (msg->datalen != user_data_len) { - RDEBUG(2, "msg->datalen(%d) != user_data_len(%d), sigh!", - msg->datalen, (int) user_data_len); - retval = -EINVAL; - goto out; - } - if (user_data_len > 0) { - if (user_data_buffer == NULL) { - RDEBUG(2, "msg->datalen and no data buffer, sigh!"); + /* get the header from userspace (first make sure there's enough data) */ + if ( user_msg_len != sizeof (fusd_msg_t ) ) + { + RDEBUG(6, "control channel got bad write of %d bytes (wanted %d)", + (int) user_msg_len, (int) sizeof (fusd_msg_t )); retval = -EINVAL; - goto out; - } - if ((msg->data = VMALLOC(user_data_len)) == NULL) { + goto out_no_free; + } + if ( ( msg = KMALLOC(sizeof (fusd_msg_t ), GFP_KERNEL) ) == NULL ) + { retval = -ENOMEM; RDEBUG(1, "yikes! kernel can't allocate memory"); goto out; - } - if (copy_from_user(msg->data, user_data_buffer, user_data_len)) { + } + memset(msg, 0, sizeof (fusd_msg_t )); + + if ( copy_from_user(msg, user_msg_buffer, sizeof (fusd_msg_t )) ) + { retval = -EFAULT; goto out; - } - } + } + msg->data = NULL; /* pointers from userspace have no meaning */ - /* before device registration, the only command allowed is 'register'. */ - /* - if (!fusd_dev->handle && msg->cmd != FUSD_REGISTER_DEVICE) { - RDEBUG(2, "got a message other than 'register' on a new device!"); - retval = -EINVAL; - goto out; - } - */ + /* check the magic number before acting on the message at all */ + if ( msg->magic != FUSD_MSG_MAGIC ) + { + RDEBUG(2, "got invalid magic number on /dev/fusd write from pid %d", + current->pid); + retval = -EIO; + goto out; + } - /* now dispatch the command to the appropriate handler */ - switch (msg->cmd) { - case FUSD_REGISTER_DEVICE: - retval = fusd_register_device(fusd_dev, msg->parm.register_msg); - goto out; - break; - case FUSD_FOPS_REPLY: - /* if reply is successful, DO NOT free the message */ - if ((retval = fusd_fops_reply(fusd_dev, msg)) == 0) { - yield = 1; - goto out_no_free; - } - break; - case FUSD_FOPS_NONBLOCK_REPLY: - switch (msg->subcmd) { - case FUSD_POLL_DIFF: - retval = fusd_polldiff_reply(fusd_dev, msg); - break; - default: - RDEBUG(2, "fusd_fops_nonblock got unknown subcmd %d", msg->subcmd); + /* now get data portion of the message */ + if ( user_data_len < 0 || user_data_len > MAX_RW_SIZE ) + { + RDEBUG(2, "fusd_process_write: got invalid length %d", (int) user_data_len); retval = -EINVAL; - } - break; - default: - RDEBUG(2, "warning: unknown message type of %d received!", msg->cmd); - retval = -EINVAL; - goto out; - break; - } + goto out; + } + if ( msg->datalen != user_data_len ) + { + RDEBUG(2, "%s : msg->datalen(%d) != user_data_len(%d), sigh!", __func__, + msg->datalen, (int) user_data_len); + retval = -EINVAL; + goto out; + } + if ( user_data_len > 0 ) + { + if ( user_data_buffer == NULL ) + { + RDEBUG(2, "msg->datalen and no data buffer, sigh!"); + retval = -EINVAL; + goto out; + } + if ( ( msg->data = VMALLOC(user_data_len) ) == NULL ) + { + retval = -ENOMEM; + RDEBUG(1, "yikes! kernel can't allocate memory"); + goto out; + } + if ( copy_from_user(msg->data, user_data_buffer, user_data_len) ) + { + retval = -EFAULT; + goto out; + } + } + + /* before device registration, the only command allowed is 'register'. */ + /* + if (!fusd_dev->handle && msg->cmd != FUSD_REGISTER_DEVICE) { + RDEBUG(2, "got a message other than 'register' on a new device!"); + retval = -EINVAL; + goto out; + } + */ + + /* now dispatch the command to the appropriate handler */ + switch ( msg->cmd ) + { + case FUSD_REGISTER_DEVICE: + retval = fusd_register_device(fusd_dev, msg->parm.register_msg); + goto out; + break; + case FUSD_FOPS_REPLY: + /* if reply is successful, DO NOT free the message */ + if ( ( retval = fusd_fops_reply(fusd_dev, msg) ) == 0 ) + { + yield = 1; + goto out_no_free; + } + break; + case FUSD_FOPS_NONBLOCK_REPLY: + switch ( msg->subcmd ) + { + case FUSD_POLL_DIFF: + retval = fusd_polldiff_reply(fusd_dev, msg); + break; + default: + RDEBUG(2, "fusd_fops_nonblock got unknown subcmd %d", msg->subcmd); + retval = -EINVAL; + } + break; + default: + RDEBUG(2, "warning: unknown message type of %d received!", msg->cmd); + retval = -EINVAL; + goto out; + break; + } - out: - if (msg && msg->data) { - VFREE(msg->data); - msg->data = NULL; - } - if (msg != NULL) { - KFREE(msg); - msg = NULL; - } +out: + if ( msg && msg->data ) + { + VFREE(msg->data); + msg->data = NULL; + } + if ( msg != NULL ) + { + KFREE(msg); + msg = NULL; + } - out_no_free: +out_no_free: - /* the functions we call indicate success by returning 0. we - * convert that into a success indication by changing the retval to - * the length of the write. */ - if (retval == 0) - retval = user_data_len + user_msg_len; + /* the functions we call indicate success by returning 0. we + * convert that into a success indication by changing the retval to + * the length of the write. */ + if ( retval == 0 ) + retval = user_data_len + user_msg_len; - UNLOCK_FUSD_DEV(fusd_dev); + UNLOCK_FUSD_DEV(fusd_dev); - /* if we successfully completed someone's syscall, yield the - * processor to them immediately as a throughput optimization. we - * also hope that in the case of bulk data transfer, their next - * syscall will come in before we are scheduled again. */ - if (yield) { + /* if we successfully completed someone's syscall, yield the + * processor to them immediately as a throughput optimization. we + * also hope that in the case of bulk data transfer, their next + * syscall will come in before we are scheduled again. */ + if ( yield ) + { #ifdef SCHED_YIELD - current->policy |= SCHED_YIELD; + current->policy |= SCHED_YIELD; #endif - schedule(); - } + schedule(); + } - return retval; + return retval; - zombie_dev: - invalid_dev: - RDEBUG(1, "fusd_process_write: got invalid device!"); - return -EPIPE; +zombie_dev: + invalid_dev : + RDEBUG(1, "fusd_process_write: got invalid device!"); + return -EPIPE; } - -STATIC ssize_t fusd_write(struct file *file, - const char *buffer, - size_t length, - loff_t *offset) +STATIC ssize_t fusd_write (struct file *file, + const char *buffer, + size_t length, + loff_t *offset) { - return fusd_process_write(file, buffer, length, NULL, 0); + RDEBUG(1, "%s: [%p:%p:%d:%p] [sl: %d]!!", __func__, file, buffer, length, offset, sizeof (fusd_msg_t )); + return fusd_process_write(file, buffer, length, NULL, 0); } - -STATIC ssize_t fusd_writev(struct file *file, - const struct iovec *iov, - unsigned long count, - loff_t *offset) +STATIC ssize_t fusd_writev (struct file *file, + const struct iovec *iov, + unsigned long count, + loff_t *offset) { - if (count != 2) { - RDEBUG(2, "fusd_writev: got illegal iov count of %ld", count); - return -EINVAL; - } + if ( count != 2 ) + { + RDEBUG(2, "fusd_writev: got illegal iov count of %ld", count); + return -EINVAL; + } - return fusd_process_write(file, - iov[0].iov_base, iov[0].iov_len, - iov[1].iov_base, iov[1].iov_len); + return fusd_process_write(file, + iov[0].iov_base, iov[0].iov_len, + iov[1].iov_base, iov[1].iov_len); } +STATIC int fusd_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *) arg; + struct iovec iov; + + if ( ( argp != NULL ) && ( cmd == 0xb16b00b5 ) ) + { + RDEBUG(9, "%s: !!!!!!! ( o )( o ) !!!!!!!", __func__); + + /* Act like writev... */ + copy_from_user(&iov, argp, sizeof (struct iovec) * 2); + return fusd_writev(file, &iov, 2, NULL); + } + RDEBUG(2, "%s: got illegal ioctl #%08X# Or ARG is null [%p]", __func__, cmd, argp); + return -EINVAL; +} /* fusd_read: a process is reading on /dev/fusd. return any messages * waiting to go from kernel to userspace. @@ -2451,232 +2666,243 @@ STATIC ssize_t fusd_writev(struct file *file, * because each instance of /dev/fusd has a completely independent * message queue.) */ - /* do a "header" read: used by fusd_read */ -STATIC int fusd_read_header(char *user_buffer, size_t user_length, fusd_msg_t *msg) +STATIC int fusd_read_header (char *user_buffer, size_t user_length, fusd_msg_t *msg) { - int len = sizeof(fusd_msg_t); + int len = sizeof (fusd_msg_t ); - if (user_length != len) { - RDEBUG(4, "bad length of %d sent to /dev/fusd for peek", (int) user_length); - return -EINVAL; - } + if ( user_length != len ) + { + RDEBUG(4, "bad length of %d sent to /dev/fusd for peek", (int) user_length); + return -EINVAL; + } - if (copy_to_user(user_buffer, msg, len)) - return -EFAULT; + if ( copy_to_user(user_buffer, msg, len) ) + return -EFAULT; - return sizeof(fusd_msg_t); + return sizeof (fusd_msg_t ); } - /* do a "data" read: used by fusd_read */ -STATIC int fusd_read_data(char *user_buffer, size_t user_length, fusd_msg_t *msg) +STATIC int fusd_read_data (char *user_buffer, size_t user_length, fusd_msg_t *msg) { - int len = msg->datalen; + int len = msg->datalen; - if (len == 0 || msg->data == NULL) { - RDEBUG(1, "fusd_read_data: no data to send!"); - return -EIO; - } + if ( len == 0 || msg->data == NULL ) + { + RDEBUG(1, "fusd_read_data: no data to send!"); + return -EIO; + } - /* make sure the user is requesting exactly the right amount (as a - sanity check) */ - if (user_length != len) { - RDEBUG(4, "bad read for %d bytes on /dev/fusd (need %d)", (int) user_length,len); - return -EINVAL; - } + /* make sure the user is requesting exactly the right amount (as a + sanity check) */ + if ( user_length != len ) + { + RDEBUG(4, "bad read for %d bytes on /dev/fusd (need %d)", (int) user_length, len); + return -EINVAL; + } - /* now copy to userspace */ - if (copy_to_user(user_buffer, msg->data, len)) - return -EFAULT; + /* now copy to userspace */ + if ( copy_to_user(user_buffer, msg->data, len) ) + return -EFAULT; - /* done! */ - return len; + /* done! */ + return len; } - -STATIC ssize_t fusd_read(struct file *file, - char *user_buffer, /* The buffer to fill with data */ - size_t user_length, /* The length of the buffer */ - loff_t *offset) /* Our offset in the file */ +STATIC ssize_t fusd_read (struct file *file, + char *user_buffer, /* The buffer to fill with data */ + size_t user_length, /* The length of the buffer */ + loff_t *offset) /* Our offset in the file */ { - fusd_dev_t *fusd_dev; - fusd_msgC_t *msg_out; - int retval, dequeue = 0; + fusd_dev_t *fusd_dev; + fusd_msgC_t *msg_out; + int retval, dequeue = 0; - GET_FUSD_DEV(file->private_data, fusd_dev); - LOCK_FUSD_DEV(fusd_dev); + GET_FUSD_DEV(file->private_data, fusd_dev); + LOCK_FUSD_DEV(fusd_dev); - RDEBUG(15, "driver pid %d (/dev/%s) entering fusd_read", current->pid, - NAME(fusd_dev)); + RDEBUG(15, "driver pid %d (/dev/%s) entering fusd_read", current->pid, + NAME(fusd_dev)); - /* if no messages are waiting, either block or return EAGAIN */ - while ((msg_out = fusd_dev->msg_head) == NULL) { - DECLARE_WAITQUEUE(wait, current); + /* if no messages are waiting, either block or return EAGAIN */ + while ( ( msg_out = fusd_dev->msg_head ) == NULL ) + { + DECLARE_WAITQUEUE(wait, current); - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto out; - } + if ( file->f_flags & O_NONBLOCK ) + { + retval = -EAGAIN; + goto out; + } - /* - * sleep, waiting for a message to arrive. we are unrolling - * interruptible_sleep_on to avoid a race between unlocking the - * device and sleeping (what if a message arrives in that - * interval?) - */ - current->state = TASK_INTERRUPTIBLE; - add_wait_queue(&fusd_dev->dev_wait, &wait); - UNLOCK_FUSD_DEV(fusd_dev); - schedule(); - remove_wait_queue(&fusd_dev->dev_wait, &wait); - LOCK_FUSD_DEV(fusd_dev); + /* + * sleep, waiting for a message to arrive. we are unrolling + * interruptible_sleep_on to avoid a race between unlocking the + * device and sleeping (what if a message arrives in that + * interval?) + */ + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&fusd_dev->dev_wait, &wait); + UNLOCK_FUSD_DEV(fusd_dev); + schedule(); + remove_wait_queue(&fusd_dev->dev_wait, &wait); + LOCK_FUSD_DEV(fusd_dev); - /* we're back awake! --see if a signal woke us up */ - if (signal_pending(current)) { - retval = -ERESTARTSYS; - goto out; - } - } + /* we're back awake! --see if a signal woke us up */ + if ( signal_pending(current) ) + { + retval = -ERESTARTSYS; + goto out; + } + } - /* is this a header read or data read? */ - if (!msg_out->peeked) { - /* this is a header read (first read) */ - retval = fusd_read_header(user_buffer, user_length, &msg_out->fusd_msg); + /* is this a header read or data read? */ + if ( !msg_out->peeked ) + { + /* this is a header read (first read) */ + retval = fusd_read_header(user_buffer, user_length, &msg_out->fusd_msg); - /* is there data? if so, make sure next read gets data. if not, - * make sure message is dequeued now.*/ - if (msg_out->fusd_msg.datalen) { - msg_out->peeked = 1; - dequeue = 0; - } else { - dequeue = 1; - } - } else { - /* this is a data read (second read) */ - retval = fusd_read_data(user_buffer, user_length, &msg_out->fusd_msg); - dequeue = 1; /* message should be dequeued */ - } + /* is there data? if so, make sure next read gets data. if not, + * make sure message is dequeued now.*/ + if ( msg_out->fusd_msg.datalen ) + { + msg_out->peeked = 1; + dequeue = 0; + } + else + { + dequeue = 1; + } + } + else + { + /* this is a data read (second read) */ + retval = fusd_read_data(user_buffer, user_length, &msg_out->fusd_msg); + dequeue = 1; /* message should be dequeued */ + } - /* if this message is done, take it out of the outgoing queue */ - if (dequeue) { - if (fusd_dev->msg_tail == fusd_dev->msg_head) - fusd_dev->msg_tail = fusd_dev->msg_head = NULL; - else - fusd_dev->msg_head = msg_out->next; - FREE_FUSD_MSGC(msg_out); - } + /* if this message is done, take it out of the outgoing queue */ + if ( dequeue ) + { + if ( fusd_dev->msg_tail == fusd_dev->msg_head ) + fusd_dev->msg_tail = fusd_dev->msg_head = NULL; + else + fusd_dev->msg_head = msg_out->next; + FREE_FUSD_MSGC(msg_out); + } - out: - UNLOCK_FUSD_DEV(fusd_dev); - return retval; +out: + UNLOCK_FUSD_DEV(fusd_dev); + return retval; - zombie_dev: - invalid_dev: - RDEBUG(2, "got read on /dev/fusd for unknown device!"); - return -EPIPE; +zombie_dev: + invalid_dev : + RDEBUG(2, "got read on /dev/fusd for unknown device!"); + return -EPIPE; } - /* a poll on /dev/fusd itself (the control channel) */ -STATIC unsigned int fusd_poll(struct file *file, poll_table *wait) +STATIC unsigned int fusd_poll (struct file *file, poll_table *wait) { - fusd_dev_t *fusd_dev; - GET_FUSD_DEV(file->private_data, fusd_dev); + fusd_dev_t *fusd_dev; + GET_FUSD_DEV(file->private_data, fusd_dev); - poll_wait(file, &fusd_dev->dev_wait, wait); + poll_wait(file, &fusd_dev->dev_wait, wait); - if (fusd_dev->msg_head != NULL) { - return POLLIN | POLLRDNORM; - } + if ( fusd_dev->msg_head != NULL ) + { + return POLLIN | POLLRDNORM; + } - invalid_dev: - return 0; +invalid_dev: + return 0; } STATIC struct file_operations fusd_fops = { - owner: THIS_MODULE, - open: fusd_open, - read: fusd_read, - write: fusd_write, - writev: fusd_writev, - release: fusd_release, - poll: fusd_poll, + owner : THIS_MODULE, + open : fusd_open, + read : fusd_read, + write : fusd_write, + //writev: fusd_writev, + ioctl : fusd_ioctl, + release : fusd_release, + poll : fusd_poll, }; - - /*************************************************************************/ -typedef struct fusd_status_state { - int binary_status; - int need_new_status; - char *curr_status; - int curr_status_len; - int last_version_seen; +typedef struct fusd_status_state +{ + int binary_status; + int need_new_status; + char *curr_status; + int curr_status_len; + int last_version_seen; } fusd_statcontext_t; /* open() called on /dev/fusd/status */ -STATIC int fusd_status_open(struct inode *inode, struct file *file) +STATIC int fusd_status_open (struct inode *inode, struct file *file) { - int error = 0; - fusd_statcontext_t *fs; + int error = 0; + fusd_statcontext_t *fs; - //MOD_INC_USE_COUNT; + //MOD_INC_USE_COUNT; - if ((fs = KMALLOC(sizeof(fusd_statcontext_t), GFP_KERNEL)) == NULL) { - RDEBUG(1, "yikes! kernel can't allocate memory"); - error = -ENOMEM; - goto out; - } + if ( ( fs = KMALLOC(sizeof (fusd_statcontext_t ), GFP_KERNEL) ) == NULL ) + { + RDEBUG(1, "yikes! kernel can't allocate memory"); + error = -ENOMEM; + goto out; + } - memset(fs, 0, sizeof(fusd_statcontext_t)); - fs->need_new_status = 1; - file->private_data = (void *) fs; + memset(fs, 0, sizeof (fusd_statcontext_t )); + fs->need_new_status = 1; + file->private_data = (void *) fs; - out: - //if (error) - // MOD_DEC_USE_COUNT; - return error; +out: + //if (error) + // MOD_DEC_USE_COUNT; + return error; } /* close on /dev/fusd_status */ -STATIC int fusd_status_release(struct inode *inode, struct file *file) +STATIC int fusd_status_release (struct inode *inode, struct file *file) { - fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data; + fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data; - if (fs) { - if (fs->curr_status) - KFREE(fs->curr_status); - KFREE(fs); - } + if ( fs ) + { + if ( fs->curr_status ) + KFREE(fs->curr_status); + KFREE(fs); + } - //MOD_DEC_USE_COUNT; - return 0; + //MOD_DEC_USE_COUNT; + return 0; } - /* ioctl() on /dev/fusd/status */ -STATIC int fusd_status_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +STATIC int fusd_status_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data; + fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data; - if (!fs) - return -EIO; + if ( !fs ) + return -EIO; - switch (cmd) { - case FUSD_STATUS_USE_BINARY: - fs->binary_status = 1; - return 0; - default: - return -EINVAL; - break; - } + switch ( cmd ) + { + case FUSD_STATUS_USE_BINARY: + fs->binary_status = 1; + return 0; + default: + return -EINVAL; + break; + } } - /* * maybe_expand_buffer: expand a buffer exponentially as it fills. We * are given: @@ -2689,349 +2915,353 @@ STATIC int fusd_status_ioctl(struct inode *inode, struct file *file, * If there isn't at least space_needed difference between buf_size * and len, the existing contents are moved into a larger buffer. */ -STATIC int maybe_expand_buffer(char **buf, int *buf_size, int len, - int space_needed) +STATIC int maybe_expand_buffer (char **buf, int *buf_size, int len, + int space_needed) { - if (*buf_size - len < space_needed) { - char *old_buf = *buf; + if ( *buf_size - len < space_needed ) + { + char *old_buf = *buf; - *buf_size *= 2; - *buf = KMALLOC(*buf_size, GFP_KERNEL); + *buf_size *= 2; + *buf = KMALLOC(*buf_size, GFP_KERNEL); - if (*buf != NULL) - memmove(*buf, old_buf, len); - KFREE(old_buf); - if (*buf == NULL) { - RDEBUG(1, "out of memory!"); - return -1; - } - } - return 0; + if ( *buf != NULL ) + memmove(*buf, old_buf, len); + KFREE(old_buf); + if ( *buf == NULL ) + { + RDEBUG(1, "out of memory!"); + return -1; + } + } + return 0; } - - /* Build a text buffer containing current fusd status. */ -STATIC void fusd_status_build_text(fusd_statcontext_t *fs) +STATIC void fusd_status_build_text (fusd_statcontext_t *fs) { - int buf_size = 512; - char *buf = KMALLOC(buf_size, GFP_KERNEL); - int len = 0, total_clients = 0, total_files = 0; - struct list_head *tmp; + int buf_size = 512; + char *buf = KMALLOC(buf_size, GFP_KERNEL); + int len = 0, total_clients = 0, total_files = 0; + struct list_head *tmp; - if (buf == NULL) { - RDEBUG(1, "fusd_status_build: out of memory!"); - return; - } + if ( buf == NULL ) + { + RDEBUG(1, "fusd_status_build: out of memory!"); + return; + } - len += snprintf(buf + len, buf_size - len, - " PID Open Name\n" - "------ ---- -----------------\n"); + len += snprintf(buf + len, buf_size - len, + " PID Open Name\n" + "------ ---- -----------------\n"); - down(&fusd_devlist_sem); - list_for_each(tmp, &fusd_devlist_head) { - fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist); + down(&fusd_devlist_sem); - if (!d) - continue; + list_for_each(tmp, &fusd_devlist_head) + { + fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist); - /* Possibly expand the buffer if we need more space */ - if (maybe_expand_buffer(&buf, &buf_size, len, FUSD_MAX_NAME_LENGTH+120) < 0) - goto out; + if ( !d ) + continue; - len += snprintf(buf + len, buf_size - len, - "%6d %4d %s%s\n", d->pid, d->num_files, - d->zombie ? "" : "", NAME(d)); + /* Possibly expand the buffer if we need more space */ + if ( maybe_expand_buffer(&buf, &buf_size, len, FUSD_MAX_NAME_LENGTH + 120) < 0 ) + goto out; - total_files++; - total_clients += d->num_files; - } + len += snprintf(buf + len, buf_size - len, + "%6d %4d %s%s\n", d->pid, d->num_files, + d->zombie ? "" : "", NAME(d)); - len += snprintf(buf + len, buf_size - len, - "\nFUSD $Revision$ - %d devices used by %d clients\n", - total_files, total_clients); + total_files++; + total_clients += d->num_files; + } - out: - fs->last_version_seen = last_version; - up(&fusd_devlist_sem); + len += snprintf(buf + len, buf_size - len, + "\nFUSD $Id$ - %d devices used by %d clients\n", + total_files, total_clients); - if (fs->curr_status) - KFREE(fs->curr_status); +out: + fs->last_version_seen = last_version; + up(&fusd_devlist_sem); - fs->curr_status = buf; - fs->curr_status_len = len; - fs->need_new_status = 0; + if ( fs->curr_status ) + KFREE(fs->curr_status); + + fs->curr_status = buf; + fs->curr_status_len = len; + fs->need_new_status = 0; } - /* Build the binary version of status */ -STATIC void fusd_status_build_binary(fusd_statcontext_t *fs) +STATIC void fusd_status_build_binary (fusd_statcontext_t *fs) { - int buf_size = 512; - char *buf = KMALLOC(buf_size, GFP_KERNEL); - int len = 0, i = 0; - struct list_head *tmp; - fusd_status_t *s; + int buf_size = 512; + char *buf = KMALLOC(buf_size, GFP_KERNEL); + int len = 0, i = 0; + struct list_head *tmp; + fusd_status_t *s; - if (buf == NULL) { - RDEBUG(1, "out of memory!"); - return; - } + if ( buf == NULL ) + { + RDEBUG(1, "out of memory!"); + return; + } - down(&fusd_devlist_sem); - list_for_each(tmp, &fusd_devlist_head) { - fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist); + down(&fusd_devlist_sem); - if (!d) - continue; + list_for_each(tmp, &fusd_devlist_head) + { + fusd_dev_t *d = list_entry(tmp, fusd_dev_t, devlist); - /* Possibly expand the buffer if we need more space */ - if (maybe_expand_buffer(&buf, &buf_size, len, sizeof(fusd_status_t)) < 0) - goto out; + if ( !d ) + continue; - s = &((fusd_status_t *) buf)[i]; + /* Possibly expand the buffer if we need more space */ + if ( maybe_expand_buffer(&buf, &buf_size, len, sizeof (fusd_status_t )) < 0 ) + goto out; - /* construct this status entry */ - memset(s, 0, sizeof(fusd_status_t)); - strncpy(s->name, NAME(d), FUSD_MAX_NAME_LENGTH); - s->zombie = d->zombie; - s->pid = d->pid; - s->num_open = d->num_files; + s = &( (fusd_status_t *) buf )[i]; - i++; - len += sizeof(fusd_status_t); - } - - out: - fs->last_version_seen = last_version; - up(&fusd_devlist_sem); + /* construct this status entry */ + memset(s, 0, sizeof (fusd_status_t )); + strncpy(s->name, NAME(d), FUSD_MAX_NAME_LENGTH); + s->zombie = d->zombie; + s->pid = d->pid; + s->num_open = d->num_files; - if (fs->curr_status) - KFREE(fs->curr_status); + i++; + len += sizeof (fusd_status_t ); + } - fs->curr_status = buf; - fs->curr_status_len = len; - fs->need_new_status = 0; +out: + fs->last_version_seen = last_version; + up(&fusd_devlist_sem); + + if ( fs->curr_status ) + KFREE(fs->curr_status); + + fs->curr_status = buf; + fs->curr_status_len = len; + fs->need_new_status = 0; } - - -STATIC ssize_t fusd_status_read(struct file *file, - char *user_buffer, /* The buffer to fill with data */ - size_t user_length, /* The length of the buffer */ - loff_t *offset) /* Our offset in the file */ +STATIC ssize_t fusd_status_read (struct file *file, + char *user_buffer, /* The buffer to fill with data */ + size_t user_length, /* The length of the buffer */ + loff_t *offset) /* Our offset in the file */ { - fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data; + fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data; - if (!fs) - return -EIO; + if ( !fs ) + return -EIO; - /* create a new status page, if we aren't in the middle of one */ - if (fs->need_new_status) { - if (fs->binary_status) - fusd_status_build_binary(fs); - else - fusd_status_build_text(fs); - } + /* create a new status page, if we aren't in the middle of one */ + if ( fs->need_new_status ) + { + if ( fs->binary_status ) + fusd_status_build_binary(fs); + else + fusd_status_build_text(fs); + } - /* return EOF if we're at the end */ - if (fs->curr_status == NULL || fs->curr_status_len == 0) { - fs->need_new_status = 1; - return 0; - } + /* return EOF if we're at the end */ + if ( fs->curr_status == NULL || fs->curr_status_len == 0 ) + { + fs->need_new_status = 1; + return 0; + } - /* return only as much data as we have */ - if (fs->curr_status_len < user_length) - user_length = fs->curr_status_len; - if (copy_to_user(user_buffer, fs->curr_status, user_length)) - return -EFAULT; + /* return only as much data as we have */ + if ( fs->curr_status_len < user_length ) + user_length = fs->curr_status_len; + if ( copy_to_user(user_buffer, fs->curr_status, user_length) ) + return -EFAULT; - /* update fs, so we don't return the same data next time */ - fs->curr_status_len -= user_length; - if (fs->curr_status_len) - memmove(fs->curr_status, fs->curr_status + user_length, fs->curr_status_len); - else { - KFREE(fs->curr_status); - fs->curr_status = NULL; - } + /* update fs, so we don't return the same data next time */ + fs->curr_status_len -= user_length; + if ( fs->curr_status_len ) + memmove(fs->curr_status, fs->curr_status + user_length, fs->curr_status_len); + else + { + KFREE(fs->curr_status); + fs->curr_status = NULL; + } - return user_length; + return user_length; } - /* a poll on /dev/fusd itself (the control channel) */ -STATIC unsigned int fusd_status_poll(struct file *file, poll_table *wait) +STATIC unsigned int fusd_status_poll (struct file *file, poll_table *wait) { - fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data; + fusd_statcontext_t *fs = (fusd_statcontext_t *) file->private_data; - poll_wait(file, &new_device_wait, wait); + poll_wait(file, &new_device_wait, wait); - if (fs->last_version_seen < last_version) - return POLLIN | POLLRDNORM; - else - return 0; + if ( fs->last_version_seen < last_version ) + return POLLIN | POLLRDNORM; + else + return 0; } STATIC struct file_operations fusd_status_fops = { - owner: THIS_MODULE, - open: fusd_status_open, - ioctl: fusd_status_ioctl, - read: fusd_status_read, - release: fusd_status_release, - poll: fusd_status_poll, + owner : THIS_MODULE, + open : fusd_status_open, + ioctl : fusd_status_ioctl, + read : fusd_status_read, + release : fusd_status_release, + poll : fusd_status_poll, }; - /*************************************************************************/ -STATIC int init_fusd(void) +STATIC int init_fusd (void) { - int retval; + int retval; #ifdef CONFIG_FUSD_MEMDEBUG - if ((retval = fusd_mem_init()) < 0) - return retval; + if ( ( retval = fusd_mem_init() ) < 0 ) + return retval; #endif - printk(KERN_INFO - "fusd: starting, $Revision$, $Date$"); + printk(KERN_INFO + "fusd: starting, $Id$"); #ifdef CVSTAG - printk(", release %s", CVSTAG); + printk(", release %s", CVSTAG); #endif #ifdef CONFIG_FUSD_DEBUG - printk(", debuglevel=%d\n", fusd_debug_level); + printk(", debuglevel=%d\n", fusd_debug_level); #else - printk(", debugging messages disabled\n"); + printk(", debugging messages disabled\n"); #endif - fusd_control_device = NULL; - fusd_status_device = NULL; - - fusd_class = class_create(THIS_MODULE, "fusd"); - if(IS_ERR(fusd_class)) - { - retval = PTR_ERR(fusd_class); - printk(KERN_ERR "class_create failed status: %d\n", retval); - goto fail0; - } - - control_id = 0; + fusd_control_cdev = NULL; + fusd_status_cdev = NULL; - if((retval = alloc_chrdev_region(&control_id, 0, 1, FUSD_CONTROL_FILENAME)) < 0) - { - printk(KERN_ERR "alloc_chrdev_region failed status: %d\n", retval); - goto fail1; - } + fusd_class = class_create(THIS_MODULE, "fusd"); + if ( IS_ERR(fusd_class) ) + { + retval = PTR_ERR(fusd_class); + printk(KERN_ERR "class_create failed status: %d\n", retval); + goto fail0; + } - fusd_control_device = cdev_alloc(); - if(fusd_control_device == NULL) - { - printk(KERN_ERR "cdev-alloc failed\n"); - retval = -ENOMEM; - goto fail3; - } + control_id = 0; - fusd_control_device->owner = THIS_MODULE; - fusd_control_device->ops = &fusd_fops; - kobject_set_name(&fusd_control_device->kobj, FUSD_CONTROL_FILENAME); + if ( ( retval = alloc_chrdev_region(&control_id, 0, 1, FUSD_CONTROL_FILENAME) ) < 0 ) + { + printk(KERN_ERR "alloc_chrdev_region failed status: %d\n", retval); + goto fail1; + } - printk(KERN_ERR "cdev control id: %d\n", control_id); - if((retval = cdev_add(fusd_control_device, control_id, 1)) < 0) - { - printk(KERN_ERR "cdev_add failed status: %d\n", retval); - kobject_put(&fusd_control_device->kobj); - goto fail4; - } - - fusd_control_class_device = CLASS_DEVICE_CREATE(fusd_class, NULL, control_id, NULL, "control"); - if(fusd_control_class_device == NULL) - { - retval = PTR_ERR(fusd_control_class_device); - printk("class_device_create failed status: %d\n", retval); - goto fail5; - } + fusd_control_cdev = cdev_alloc(); + if ( fusd_control_cdev == NULL ) + { + printk(KERN_ERR "cdev-alloc failed\n"); + retval = -ENOMEM; + goto fail3; + } - status_id = 0; + fusd_control_cdev->owner = THIS_MODULE; + fusd_control_cdev->ops = &fusd_fops; + kobject_set_name(&fusd_control_cdev->kobj, FUSD_CONTROL_FILENAME); - if((retval = alloc_chrdev_region(&status_id, 0, 1, FUSD_STATUS_FILENAME)) < 0) - { - printk(KERN_ERR "alloc_chrdev_region failed status: %d\n", retval); - goto fail6; - } + printk(KERN_ERR "cdev control id: %d\n", control_id); + if ( ( retval = cdev_add(fusd_control_cdev, control_id, 1) ) < 0 ) + { + printk(KERN_ERR "cdev_add failed status: %d\n", retval); + kobject_put(&fusd_control_cdev->kobj); + goto fail4; + } - fusd_status_device = cdev_alloc(); - if(fusd_status_device == NULL) - { - retval = -ENOMEM; - goto fail8; - } + fusd_control_device = CLASS_DEVICE_CREATE(fusd_class, NULL, control_id, NULL, "control"); + if ( fusd_control_device == NULL ) + { + retval = PTR_ERR(fusd_control_device); + printk("device_create failed status: %d\n", retval); + goto fail5; + } - fusd_status_device->owner = THIS_MODULE; - fusd_status_device->ops = &fusd_status_fops; - kobject_set_name(&fusd_status_device->kobj, FUSD_STATUS_FILENAME); + status_id = 0; - if((retval = cdev_add(fusd_status_device, status_id, 1)) < 0) - { - printk(KERN_ERR "cdev_add failed status: %d\n", retval); - kobject_put(&fusd_status_device->kobj); - goto fail9; - } - - fusd_status_class_device = CLASS_DEVICE_CREATE(fusd_class, NULL, status_id, NULL, "status"); - if(fusd_status_class_device == NULL) - { - printk(KERN_ERR "class_device_create failed status: %d\n", retval); - retval = PTR_ERR(fusd_status_class_device); - goto fail10; - } - - RDEBUG(1, "registration successful"); - return 0; + if ( ( retval = alloc_chrdev_region(&status_id, 0, 1, FUSD_STATUS_FILENAME) ) < 0 ) + { + printk(KERN_ERR "alloc_chrdev_region failed status: %d\n", retval); + goto fail6; + } + + fusd_status_cdev = cdev_alloc(); + if ( fusd_status_cdev == NULL ) + { + retval = -ENOMEM; + goto fail8; + } + + fusd_status_cdev->owner = THIS_MODULE; + fusd_status_cdev->ops = &fusd_status_fops; + kobject_set_name(&fusd_status_cdev->kobj, FUSD_STATUS_FILENAME); + + if ( ( retval = cdev_add(fusd_status_cdev, status_id, 1) ) < 0 ) + { + printk(KERN_ERR "cdev_add failed status: %d\n", retval); + kobject_put(&fusd_status_cdev->kobj); + goto fail9; + } + + fusd_status_device = CLASS_DEVICE_CREATE(fusd_class, NULL, status_id, NULL, "status"); + if ( fusd_status_device == NULL ) + { + printk(KERN_ERR "device_create failed status: %d\n", retval); + retval = PTR_ERR(fusd_status_device); + goto fail10; + } + + RDEBUG(1, "registration successful"); + return 0; fail10: - cdev_del(fusd_status_device); + cdev_del(fusd_status_cdev); fail9: - kfree(fusd_status_device); + kfree(fusd_status_cdev); fail8: - //fail7: - unregister_chrdev_region(status_id, 1); + //fail7: + unregister_chrdev_region(status_id, 1); fail6: - class_device_destroy(fusd_class, control_id); + CLASS_DEVICE_DESTROY(fusd_class, control_id); fail5: - cdev_del(fusd_control_device); + cdev_del(fusd_control_cdev); fail4: - kfree(fusd_control_device); + kfree(fusd_control_cdev); fail3: - //fail2: - unregister_chrdev_region(control_id, 1); + //fail2: + unregister_chrdev_region(control_id, 1); fail1: - class_destroy(fusd_class); + class_destroy(fusd_class); fail0: - return retval; + return retval; } -STATIC void cleanup_fusd(void) +STATIC void cleanup_fusd (void) { - RDEBUG(1, "cleaning up"); + RDEBUG(1, "cleaning up"); - class_device_destroy(fusd_class, status_id); - class_device_destroy(fusd_class, control_id); - - cdev_del(fusd_control_device); - cdev_del(fusd_status_device); + CLASS_DEVICE_DESTROY(fusd_class, status_id); + CLASS_DEVICE_DESTROY(fusd_class, control_id); + + cdev_del(fusd_control_cdev); + cdev_del(fusd_status_cdev); + + class_destroy(fusd_class); - class_destroy(fusd_class); - #ifdef CONFIG_FUSD_MEMDEBUG - fusd_mem_cleanup(); + fusd_mem_cleanup(); #endif } -module_init(init_fusd); -module_exit(cleanup_fusd); +module_init (init_fusd); +module_exit (cleanup_fusd); diff --git a/libfusd/libfusd.c b/libfusd/libfusd.c index b199b60..d4f089a 100755 --- a/libfusd/libfusd.c +++ b/libfusd/libfusd.c @@ -328,8 +328,6 @@ void fusd_fdset_add(fd_set *set, int *max) } } - - /* * fusd_dispatch_fdset: given an fd_set full of descriptors, call * fusd_dispatch on every descriptor in the set which is a valid FUSD @@ -410,16 +408,21 @@ static int fusd_dispatch_one(int fd, fusd_file_operations_t *fops) /* dispatch on operation type */ user_retval = -ENOSYS; + printf("dispatch_one: subcmd: %d - ", msg->subcmd); + switch (msg->subcmd) { case FUSD_OPEN: + printf("FUSD_OPEN\n"); if (fops && fops->open) user_retval = fops->open(file); break; case FUSD_CLOSE: + printf("FUSD_CLOSE\n"); if (fops && fops->close) user_retval = fops->close(file); break; case FUSD_READ: + printf("FUSD_READ\n"); /* allocate a buffer and make the call */ if (fops && fops->read) { if ((msg->data = malloc(msg->parm.fops_msg.length)) == NULL) { @@ -433,11 +436,13 @@ static int fusd_dispatch_one(int fd, fusd_file_operations_t *fops) } break; case FUSD_WRITE: + printf("FUSD_WRITE\n"); if (fops && fops->write) user_retval = fops->write(file, msg->data, msg->datalen, &msg->parm.fops_msg.offset); break; case FUSD_MMAP: + printf("FUSD_MMAP\n"); if (fops && fops->mmap) { user_retval = fops->mmap(file, msg->parm.fops_msg.offset, msg->parm.fops_msg.length, msg->parm.fops_msg.flags, @@ -445,6 +450,7 @@ static int fusd_dispatch_one(int fd, fusd_file_operations_t *fops) } break; case FUSD_IOCTL: + printf("FUSD_IOCTL\n"); if (fops && fops->ioctl) { /* in the case of an ioctl read, allocate a buffer for the * driver to write to, IF there isn't already a buffer. (there @@ -466,6 +472,7 @@ static int fusd_dispatch_one(int fd, fusd_file_operations_t *fops) break; case FUSD_POLL_DIFF: + printf("FUSD_POLL_DIFF\n"); /* This callback requests notification when an event occurs on a file, * e.g. becoming readable or writable */ if (fops && fops->poll_diff) @@ -473,6 +480,7 @@ static int fusd_dispatch_one(int fd, fusd_file_operations_t *fops) break; case FUSD_UNBLOCK: + printf("FUSD_UNBLOCK\n"); /* This callback is called when a system call is interrupted */ if (fops && fops->unblock) user_retval = fops->unblock(file); @@ -533,6 +541,7 @@ void fusd_dispatch(int fd) if (!FUSD_FD_VALID(fd)) { errno = EBADF; retval = -1; + fprintf(stderr, "libfusd: not a valid FUSD FD\n"); goto out; } fops = FUSD_GET_FOPS(fd); @@ -555,7 +564,7 @@ void fusd_dispatch(int fd) out: if (retval < 0 && errno != EPIPE) - fprintf(stderr, "libfusd: fusd_dispatch error on fd %d: %m\n", fd); + fprintf(stderr, "libfusd: fusd_dispatch error on fd %d: [%d] %m \n", fd, retval); } @@ -648,11 +657,16 @@ int fusd_return(fusd_file_info_t *file, ssize_t retval) /* send message to kernel */ if (msg->datalen && msg->data != NULL) { + printf("(msg->datalen [%d] && msg->data != NULL [%p]", msg->datalen, msg->data); iov[0].iov_base = msg; iov[0].iov_len = sizeof(fusd_msg_t); iov[1].iov_base = msg->data; iov[1].iov_len = msg->datalen; +#if 0 driver_retval = writev(fd, iov, 2); +#else + driver_retval = ioctl(fd, 0xb16b00b5, iov); +#endif } else { driver_retval = write(fd, msg, sizeof(fusd_msg_t));