diff -uar -x .svn fusd-1.10/ChangeLog fusd-kor-1.10-10/ChangeLog --- fusd-1.10/ChangeLog 2003-08-20 16:12:26.000000000 -0600 +++ fusd-kor-1.10-10/ChangeLog 2005-09-16 22:31:33.000000000 -0600 @@ -1,3 +1,26 @@ + +v kor-1.10-10: Sept 16, 2005 + + Modified to work with 2.6.13 + +v kor-1.10-9: Jun 18, 2005 + + Added support for mmap + Added support for simultaneous requests on the same file descriptor + from separate processes. + +v kor-1.10-8: Feb 10, 2005 + + Fixed some shutdown issues for non-devfs systems. + +v kor-1.10-7: Feb 9, 2005 + + Modified to work udev + +v kor-1.10-6: Feb 17, 2004. + + Modified to work with the 2.6 kernel and devfs. + v 1.10: August 19, 2003 First UCLA release -- no longer publically maintained or released @@ -58,4 +81,4 @@ v 1.00: September 28, 2001 Initial public release. - \ No newline at end of file + diff -uar -x .svn fusd-1.10/examples/console-read.c fusd-kor-1.10-10/examples/console-read.c --- fusd-1.10/examples/console-read.c 2003-07-11 16:29:38.000000000 -0600 +++ fusd-kor-1.10-10/examples/console-read.c 2005-02-09 19:39:26.000000000 -0700 @@ -88,7 +88,7 @@ read: do_read, close: do_open_or_close }; - if (fusd_register("/dev/console-read", 0666, NULL, &fops) < 0) + if (fusd_register("/dev/console-read", "misc", "console-read", 0666, NULL, &fops) < 0) perror("Unable to register device"); else { printf("/dev/console-read should now exist - calling fusd_run...\n"); diff -uar -x .svn fusd-1.10/examples/drums2.c fusd-kor-1.10-10/examples/drums2.c --- fusd-1.10/examples/drums2.c 2003-07-11 16:29:38.000000000 -0600 +++ fusd-kor-1.10-10/examples/drums2.c 2005-02-09 19:39:26.000000000 -0700 @@ -124,10 +124,12 @@ { struct drum_info *d; char buf[128]; + char devname[128]; for (d = drums; d->name != NULL; d++) { sprintf(buf, "/dev/drums/%s", d->name); - if (fusd_register(buf, 0666, d, &drums_fops) < 0) + sprintf(devname, "drum%s", d->name); + if (fusd_register(buf, "drums", devname, 0666, d, &drums_fops) < 0) fprintf(stderr, "%s register failed: %m\n", d->name); } /* ... */ diff -uar -x .svn fusd-1.10/examples/drums3.c fusd-kor-1.10-10/examples/drums3.c --- fusd-1.10/examples/drums3.c 2003-07-11 16:29:38.000000000 -0600 +++ fusd-kor-1.10-10/examples/drums3.c 2005-02-09 19:39:26.000000000 -0700 @@ -155,12 +155,14 @@ { int i; char buf[128]; + char devname[128]; fd_set fds, tmp; int max; for (i = 0; drums_strings[i] != NULL; i++) { sprintf(buf, "/dev/drums/%s", drums_strings[i]); - if (fusd_register(buf, 0666, drums_strings[i], &drums_fops) < 0) + sprintf(devname, "drum%s", drums_strings[i]); + if (fusd_register(buf, "drums", devname, 0666, drums_strings[i], &drums_fops) < 0) fprintf(stderr, "%s register failed: %m\n", drums_strings[i]); } diff -uar -x .svn fusd-1.10/examples/drums.c fusd-kor-1.10-10/examples/drums.c --- fusd-1.10/examples/drums.c 2003-07-11 16:29:38.000000000 -0600 +++ fusd-kor-1.10-10/examples/drums.c 2005-02-09 19:39:26.000000000 -0700 @@ -101,10 +101,12 @@ { int i; char buf[128]; + char devname[128]; for (i = 0; drums_strings[i] != NULL; i++) { sprintf(buf, "/dev/drums/%s", drums_strings[i]); - if (fusd_register(buf, 0666, drums_strings[i], &drums_fops) < 0) + sprintf(devname, "drum%s", drums_strings[i]); + if (fusd_register(buf, "drums", devname, 0666, drums_strings[i], &drums_fops) < 0) fprintf(stderr, "%s register failed: %m\n", drums_strings[i]); } diff -uar -x .svn fusd-1.10/examples/echo.c fusd-kor-1.10-10/examples/echo.c --- fusd-1.10/examples/echo.c 2003-07-11 16:29:38.000000000 -0600 +++ fusd-kor-1.10-10/examples/echo.c 2005-02-09 19:39:26.000000000 -0700 @@ -113,7 +113,7 @@ int main(int argc, char *argv[]) { - if (fusd_register("/dev/echo", 0666, NULL, &echo_fops) < 0) { + if (fusd_register("/dev/echo", "misc", "echo", 0666, NULL, &echo_fops) < 0) { perror("register of /dev/echo failed"); exit(1); } diff -uar -x .svn fusd-1.10/examples/helloworld.c fusd-kor-1.10-10/examples/helloworld.c --- fusd-1.10/examples/helloworld.c 2003-07-11 16:29:38.000000000 -0600 +++ fusd-kor-1.10-10/examples/helloworld.c 2005-02-09 19:39:26.000000000 -0700 @@ -80,7 +80,7 @@ read: do_read, close: do_open_or_close }; - if (fusd_register("/dev/hello-world", 0666, NULL, &fops) < 0) + if (fusd_register("/dev/hello-world", "misc", "hello-word", 0666, NULL, &fops) < 0) perror("Unable to register device"); else { printf("/dev/hello-world should now exist - calling fusd_run...\n"); diff -uar -x .svn fusd-1.10/examples/logring.c fusd-kor-1.10-10/examples/logring.c --- fusd-1.10/examples/logring.c 2003-07-11 16:29:39.000000000 -0600 +++ fusd-kor-1.10-10/examples/logring.c 2005-02-09 19:39:26.000000000 -0700 @@ -441,7 +441,7 @@ } /* register the fusd device */ - fusd_simple_register(name, 0666, NULL, + fusd_simple_register(name, "misc", "logring", 0666, NULL, open: logring_open, close: logring_close, read: logring_read, write: logring_write, poll_diff: logring_polldiff); diff -uar -x .svn fusd-1.10/examples/pager.c fusd-kor-1.10-10/examples/pager.c --- fusd-1.10/examples/pager.c 2003-07-11 16:29:39.000000000 -0600 +++ fusd-kor-1.10-10/examples/pager.c 2005-02-09 19:39:26.000000000 -0700 @@ -366,12 +366,12 @@ int main(int argc, char *argv[]) { /* register the input device */ - fusd_simple_register("/dev/pager/input", 0666, NULL, + fusd_simple_register("/dev/pager/input", "pager", "input", 0666, NULL, open: fusd_success, close: fusd_success, write: pager_input_write); /* register the notification device */ - fusd_simple_register("/dev/pager/notify", 0666, NULL, + fusd_simple_register("/dev/pager/notify", "pager", "notify", 0666, NULL, open: pager_notify_open, close: pager_notify_close, read: pager_notify_read, diff -uar -x .svn fusd-1.10/examples/uid-filter.c fusd-kor-1.10-10/examples/uid-filter.c --- fusd-1.10/examples/uid-filter.c 2003-07-11 16:29:39.000000000 -0600 +++ fusd-kor-1.10-10/examples/uid-filter.c 2005-02-09 19:39:26.000000000 -0700 @@ -103,7 +103,7 @@ read: do_read, close: do_close }; - if (fusd_register("/dev/my-pid", 0666, NULL, &fops) < 0) + if (fusd_register("/dev/my-pid", "misc", "my-pid", 0666, NULL, &fops) < 0) perror("Unable to register device"); else { printf("/dev/my-pid should now exist - calling fusd_run...\n"); diff -uar -x .svn fusd-1.10/include/fusd.h fusd-kor-1.10-10/include/fusd.h --- fusd-1.10/include/fusd.h 2003-07-11 16:29:39.000000000 -0600 +++ fusd-kor-1.10-10/include/fusd.h 2005-06-16 21:34:48.000000000 -0600 @@ -64,6 +64,8 @@ #define FUSD_NOTIFY_EXCEPT 0x4 +#define FUSD_KOR_HACKED_VERSION + struct fusd_file_info; /* forward decl */ typedef @@ -76,7 +78,8 @@ size_t length, loff_t *offset); int (*ioctl) (struct fusd_file_info *file, int request, void *data); int (*poll_diff) (struct fusd_file_info *file, unsigned int cached_state); - int (*unblock) (struct fusd_file_info *file); + int (*unblock) (struct fusd_file_info *file); + int (*mmap) (struct fusd_file_info *file, int offset, size_t length, int flags, void** addr, size_t* out_length); } fusd_file_operations_t; @@ -144,15 +147,15 @@ * fusd_dispatch). */ -int fusd_register(const char *name, mode_t mode, void *device_info, +int fusd_register(const char *name, const char* clazz, const char* devname, mode_t mode, void *device_info, struct fusd_file_operations *fops); /* "simple" interface to fusd_register. */ -#define fusd_simple_register(name, perms, arg, ops...) do { \ +#define fusd_simple_register(name, clazz, devname, perms, arg, ops...) do { \ struct fusd_file_operations f = { ops } ; \ - if (fusd_register(name, perms, arg, &f) < 0) \ + if (fusd_register(name, clazz, devname, perms, arg, &f) < 0) \ perror("warning: fusd unavailable"); \ } while(0) diff -uar -x .svn fusd-1.10/include/fusd_msg.h fusd-kor-1.10-10/include/fusd_msg.h --- fusd-1.10/include/fusd_msg.h 2003-07-11 16:29:39.000000000 -0600 +++ fusd-kor-1.10-10/include/fusd_msg.h 2005-06-16 20:21:13.000000000 -0600 @@ -76,6 +76,7 @@ #define FUSD_IOCTL 104 #define FUSD_POLL_DIFF 105 #define FUSD_UNBLOCK 106 +#define FUSD_MMAP 107 /* other constants */ #define FUSD_MSG_MAGIC 0x7a6b93cd @@ -83,6 +84,8 @@ /* user->kernel: register a device */ typedef struct { char name[FUSD_MAX_NAME_LENGTH+1]; + char clazz[FUSD_MAX_NAME_LENGTH+1]; + char devname[FUSD_MAX_NAME_LENGTH+1]; mode_t mode; void *device_info; } register_msg_t; diff -uar -x .svn fusd-1.10/include/kfusd.h fusd-kor-1.10-10/include/kfusd.h --- fusd-1.10/include/kfusd.h 2003-07-11 16:29:39.000000000 -0600 +++ fusd-kor-1.10-10/include/kfusd.h 2005-09-16 18:45:31.000000000 -0600 @@ -74,9 +74,21 @@ unsigned int peeked:1; /* has the first half of this been read? */ }; +struct fusd_transaction +{ + struct list_head list; + long transid; + int subcmd; + int pid; + int size; + fusd_msg_t* msg_in; +}; + /* magical forward declarations to break the circular dependency */ struct fusd_dev_t_s; typedef struct fusd_dev_t_s fusd_dev_t; +struct class; +struct class_device; /* state kept per opened file (i.e., an instance of a device) */ typedef struct { @@ -94,11 +106,9 @@ /* structures used for messaging */ wait_queue_head_t file_wait; /* Wait on this for a user->kernel msg */ wait_queue_head_t poll_wait; /* Given to kernel for poll() queue */ - long transid_outstanding; /* transid of msg we are waiting for */ - int subcmd_outstanding; /* subcmd of msg we are waiting for */ - pid_t sys_restarting_pid; /* PID we just returned -ERESTARTSYS to */ - int sys_restarting_subcmd; /* subcmd of restarting syscall */ - fusd_msg_t *msg_in; /* A reply we've just received */ + struct list_head transactions; + struct semaphore transactions_sem; + } fusd_file_t; @@ -108,9 +118,19 @@ long version; /* Instance number of this device */ int zombie; /* Is the device dead? */ pid_t pid; /* PID of device driver */ + struct task_struct* task; + char *name; /* Name of the device under devfs (/dev) */ + char *class_name; + char *dev_name; + struct class *clazz; + int owns_class; + struct class_device *class_device; + void *private_data; /* User's private data */ - devfs_handle_t handle; /* The devfs-provided handle */ + struct cdev* handle; + dev_t dev_id; +// devfs_handle_t handle; /* The devfs-provided handle */ fusd_file_t **files; /* Array of this device's open files */ int array_size; /* Size of the array pointed to by 'files' */ @@ -138,14 +158,18 @@ STATIC int free_fusd_file(fusd_dev_t *fusd_dev, fusd_file_t *fusd_file); STATIC int fusd_fops_call_send(fusd_file_t *fusd_file_arg, - fusd_msg_t *fusd_msg); + fusd_msg_t *fusd_msg, struct fusd_transaction** transaction); STATIC int fusd_fops_call_wait(fusd_file_t *fusd_file_arg, - fusd_msg_t **reply); + fusd_msg_t **fusd_msg_reply, struct fusd_transaction* transaction); STATIC void fusd_fops_call_done(fusd_file_t *fusd_file); STATIC void fusd_forge_close(fusd_msg_t *msg, fusd_dev_t *fusd_dev); - +STATIC int fusd_add_transaction(fusd_file_t *fusd_file, int transid, int subcmd, int size, struct fusd_transaction** out_transaction); +STATIC void fusd_cleanup_transaction(fusd_file_t *fusd_file, struct fusd_transaction* transaction); +STATIC void fusd_remove_transaction(fusd_file_t *fusd_file, struct fusd_transaction* transaction); +STATIC struct fusd_transaction* fusd_find_transaction(fusd_file_t *fusd_file, int transid); +STATIC struct fusd_transaction* fusd_find_transaction_by_pid(fusd_file_t *fusd_file, int pid); diff -uar -x .svn fusd-1.10/kfusd/kfusd.c fusd-kor-1.10-10/kfusd/kfusd.c --- fusd-1.10/kfusd/kfusd.c 2005-06-13 22:18:21.000000000 -0600 +++ fusd-kor-1.10-10/kfusd/kfusd.c 2005-09-16 18:50:33.000000000 -0600 @@ -70,15 +70,22 @@ #include #include #include +#include +#include +#include +#include +#include + #include #include #include - +#include +#include #define STATIC /* Define this if you want to emit debug messages (adds ~8K) */ -// #define CONFIG_FUSD_DEBUG +#define CONFIG_FUSD_DEBUG /* Default debug level for FUSD messages. Has no effect unless * CONFIG_FUSD_DEBUG is defined. */ @@ -87,7 +94,7 @@ #endif /* Define this to check for memory leaks */ -/* #define CONFIG_FUSD_MEMDEBUG */ +/*#define CONFIG_FUSD_MEMDEBUG*/ /* Define this to use the faster wake_up_interruptible_sync instead of * the normal wake_up_interruptible. Note: you can't do this unless @@ -101,6 +108,15 @@ # define snprintf(str, len, args...) sprintf(str, args) #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) + +typedef class_simple class; +#define class_create class_simple_create +#define class_destroy class_simple_destroy +#define class_device_create class_simple_device_add +#define class_device_destroy(a, b) class_simple_device_remove(b) + +#endif /**************************************************************************/ @@ -112,13 +128,18 @@ # error "***FUSD doesn't work before Linux Kernel v2.4.0" #endif -#ifndef CONFIG_DEVFS_FS -# error "****FUSD needs DEVFS enabled in the kernel!" -#endif +STATIC struct cdev* fusd_control_device; +STATIC struct cdev* fusd_status_device; + +STATIC dev_t control_id; +STATIC dev_t status_id; -/* handles that devfs gives /dev/fusd and /dev/fusd_status */ -STATIC devfs_handle_t fusd_handle = 0; -STATIC devfs_handle_t fusd_status_handle = 0; +static struct class *fusd_class; + +static struct class_device *fusd_control_class_device; +static struct class_device *fusd_status_class_device; + +extern struct class *sound_class; /* version number incremented for each registered device */ STATIC int last_version = 1; @@ -133,10 +154,10 @@ LIST_HEAD(fusd_devlist_head); DECLARE_MUTEX(fusd_devlist_sem); -#ifdef MODULE_LICENSE +//#ifdef MODULE_LICENSE MODULE_AUTHOR("Jeremy Elson (c)2001"); MODULE_LICENSE("GPL"); -#endif +//#endif /***************************Debugging Support*****************************/ @@ -426,12 +447,25 @@ 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 the device's name */ if (fusd_dev->name != NULL) { KFREE(fusd_dev->name); fusd_dev->name = NULL; } + /* free the array used to store pointers to fusd_file_t's */ if (fusd_dev->files != NULL) { @@ -448,7 +482,7 @@ atomic_inc_and_ret(&last_version); wake_up_interruptible(&new_device_wait); - MOD_DEC_USE_COUNT; + //MOD_DEC_USE_COUNT; return 1; } @@ -513,7 +547,8 @@ 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"); @@ -524,11 +559,19 @@ /* there might be an incoming message waiting for a restarted system * call. free it -- after possibly forging a close (see * fusd_forge_close). */ - if (fusd_file->msg_in) { - if (fusd_file->msg_in->subcmd == FUSD_OPEN && fusd_file->msg_in->parm.fops_msg.retval == 0) - fusd_forge_close(fusd_file->msg_in, fusd_dev); - free_fusd_msg(&fusd_file->msg_in); - } + + + 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)); @@ -553,7 +596,7 @@ /****************************************************************************/ -/* +/* todo * fusd_restart_check: Called from the beginning of most system calls * to see if we are restarting a system call. * @@ -568,23 +611,24 @@ * call on that file descriptor -- well, we lose. Clear state of that * old syscall out and continue as usual. */ -STATIC int fusd_restart_check(fusd_file_t *fusd_file, int subcmd) +STATIC struct fusd_transaction* fusd_find_incomplete_transaction(fusd_file_t *fusd_file, int subcmd) { - if (fusd_file->sys_restarting_pid == 0) - return 0; + struct fusd_transaction* transaction = fusd_find_transaction_by_pid(fusd_file, current->pid); + if(transaction == NULL) + return NULL; - if (fusd_file->sys_restarting_pid == current->pid && - fusd_file->subcmd_outstanding == subcmd) { - RDEBUG(4, "pid %d restarting system call with transid %ld", current->pid, - fusd_file->transid_outstanding); - return ERESTARTSYS; - } - /* uh oh. we think we are restarting a syscall but PID does match. - give up. */ - fusd_fops_call_done(fusd_file); - free_fusd_msg(&fusd_file->msg_in); - return 0; + 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; } @@ -651,7 +695,7 @@ * 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) + fusd_msg_t *fusd_msg, struct fusd_transaction** transaction) { fusd_dev_t *fusd_dev; fusd_file_t *fusd_file; @@ -681,8 +725,7 @@ case FUSD_FOPS_CALL: /* common case */ fusd_msg->parm.fops_msg.hint = fusd_file->index; - fusd_file->transid_outstanding = fusd_msg->parm.fops_msg.transid; - fusd_file->subcmd_outstanding = fusd_msg->subcmd; + break; case FUSD_FOPS_CALL_DROPREPLY: @@ -697,7 +740,16 @@ 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); @@ -717,7 +769,7 @@ * 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) + fusd_msg_t **fusd_msg_reply, struct fusd_transaction* transaction) { fusd_dev_t *fusd_dev; fusd_file_t *fusd_file; @@ -738,14 +790,15 @@ * sleep condition and sleeping. */ LOCK_FUSD_DEV(fusd_dev); - while (fusd_file->msg_in == NULL) { + while (transaction->msg_in == NULL) { DECLARE_WAITQUEUE(wait, current); - RDEBUG(10, "pid %d blocking on transid %ld", current->pid, - fusd_file->transid_outstanding); + 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; @@ -763,10 +816,11 @@ if (signal_pending(current)) { RDEBUG(5, "blocked pid %d got a signal; sending -ERESTARTSYS", current->pid); - fusd_file->sys_restarting_pid = 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); } @@ -774,39 +828,38 @@ /* ok - at this point we are awake due to a message received. */ - if (fusd_file->msg_in->cmd != FUSD_FOPS_REPLY || - fusd_file->msg_in->subcmd != fusd_file->subcmd_outstanding || - fusd_file->msg_in->parm.fops_msg.transid != fusd_file->transid_outstanding || - fusd_file->msg_in->parm.fops_msg.fusd_file != fusd_file) { + 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 = fusd_file->msg_in->parm.fops_msg.flags; - fusd_file->private_data = fusd_file->msg_in->parm.fops_msg.private_info; + 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 = fusd_file->msg_in->parm.fops_msg.retval; + 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 = fusd_file->msg_in; - fusd_file->msg_in = NULL; + *fusd_msg_reply = transaction->msg_in; + transaction->msg_in = NULL; } else { /* free the message ourselves */ - free_fusd_msg(&fusd_file->msg_in); + free_fusd_msg(&transaction->msg_in); } - + /* success */ - fusd_fops_call_done(fusd_file); + fusd_cleanup_transaction(fusd_file, transaction); return retval; invalid_reply: - free_fusd_msg(&fusd_file->msg_in); - fusd_fops_call_done(fusd_file); + fusd_cleanup_transaction(fusd_file, transaction); return -EPIPE; /* bizarre errors go straight here */ @@ -824,11 +877,10 @@ /* 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_fops_call_done(fusd_file_t *fusd_file) +STATIC void fusd_transaction_done(struct fusd_transaction *transaction) { - fusd_file->sys_restarting_pid = 0; - fusd_file->transid_outstanding = -1; - fusd_file->subcmd_outstanding = -1; + transaction->transid = -1; + transaction->pid = 0; } @@ -948,7 +1000,9 @@ 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; @@ -967,6 +1021,22 @@ return 0; } +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; +} /* * A client has called open() has been called on a registered device. @@ -976,10 +1046,11 @@ { int retval; int device_freed = 0; - fusd_dev_t *fusd_dev = (fusd_dev_t *) file->private_data; + 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; @@ -1003,7 +1074,7 @@ * 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(). + * the device lock, due to the access of it in fusd_dev_is_valid(). */ down(&fusd_devlist_sem); fusd_dev->open_in_progress--; @@ -1026,9 +1097,10 @@ * locked during that operation. */ UNLOCK_FUSD_DEV(fusd_dev); - retval = fusd_fops_call_send(fusd_file, &fusd_msg); + retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction); + if (retval >= 0) - retval = fusd_fops_call_wait(fusd_file, NULL); + 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 @@ -1062,7 +1134,8 @@ 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); @@ -1072,10 +1145,12 @@ /* 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); + 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); - + 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 @@ -1101,6 +1176,7 @@ { fusd_dev_t *fusd_dev; fusd_file_t *fusd_file; + struct fusd_transaction* transaction; fusd_msg_t fusd_msg, *reply = NULL; int retval = -EPIPE; @@ -1110,25 +1186,35 @@ RDEBUG(3, "got a read on /dev/%s (owned by pid %d) from pid %d", NAME(fusd_dev), fusd_dev->pid, current->pid); - if (fusd_restart_check(fusd_file, FUSD_READ) == ERESTARTSYS) - goto restarted_syscall; - - /* 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; + 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, count); - /* send message to userspace */ - if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg)) < 0) - goto done; + fusd_cleanup_transaction(fusd_file, transaction); + transaction = NULL; + } - restarted_syscall: + 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 */ - retval = fusd_fops_call_wait(fusd_file, &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) @@ -1178,6 +1264,76 @@ 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) +{ + down(&fusd_file->transactions_sem); + struct list_head* i; + 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) +{ + down(&fusd_file->transactions_sem); + struct list_head* i; + 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, @@ -1189,48 +1345,58 @@ 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); 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); - if (fusd_restart_check(fusd_file, FUSD_WRITE) == ERESTARTSYS) - goto restarted_syscall; + 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, length); - if (length < 0) { - RDEBUG(2, "fusd_client_write: got invalid length %d", length); - retval = -EINVAL; - goto done; + fusd_cleanup_transaction(fusd_file, transaction); + transaction = NULL; } - - 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; + if(transaction == NULL) + { + if (length < 0) { + RDEBUG(2, "fusd_client_write: got invalid length %d", length); + retval = -EINVAL; goto done; } - fusd_msg.datalen = length; - } - fusd_msg.subcmd = FUSD_WRITE; - fusd_msg.parm.fops_msg.length = length; + if (length > MAX_RW_SIZE) + length = MAX_RW_SIZE; - if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg)) < 0) - goto done; - restarted_syscall: - retval = fusd_fops_call_wait(fusd_file, &reply); + 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; @@ -1270,7 +1436,8 @@ 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); LOCK_FUSD_FILE(fusd_file); @@ -1280,45 +1447,48 @@ dir = _IOC_DIR(cmd); length = _IOC_SIZE(cmd); - if (fusd_restart_check(fusd_file, FUSD_IOCTL) == ERESTARTSYS) - goto restarted_syscall; + transaction = fusd_find_incomplete_transaction(fusd_file, FUSD_IOCTL); + // todo: Check to make sure the transaction is for the same IOCTL - /* 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; - - /* 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(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; + + /* 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; } - - if (copy_from_user(fusd_msg.data, (void *) arg, length)) { - retval = -EFAULT; + + /* send request to the driver */ + if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg, &transaction)) < 0) goto done; - } - fusd_msg.datalen = length; } - - /* send request to the driver */ - if ((retval = fusd_fops_call_send(fusd_file, &fusd_msg)) < 0) - goto done; - restarted_syscall: /* get the response */ - if ((retval = fusd_fops_call_wait(fusd_file, &reply)) < 0 || reply == NULL) + /* 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 */ @@ -1347,6 +1517,139 @@ 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 = +{ + open: fusd_client_mm_open, + close: fusd_client_mm_close, + nopage: fusd_client_nopage, +}; + +struct fusd_mmap_instance +{ + 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) +{ + 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) +{ + 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) +{ + 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); + 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); + + 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); + + struct fusd_mmap_instance* 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; + 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: + 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) +{ + 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; + } +out: + return page; + + +} /* @@ -1425,7 +1728,7 @@ 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) < 0) { + 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. */ @@ -1454,6 +1757,7 @@ write: fusd_client_write, ioctl: fusd_client_ioctl, poll: fusd_client_poll, + mmap: fusd_client_mmap }; @@ -1502,23 +1806,30 @@ } /* 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; - } - - if (fusd_file->msg_in != NULL) { - RDEBUG(1, "fusd_fops_reply: incoming message already exists!!"); - goto discard; - } - + }*/ + + struct fusd_transaction *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, msg->parm.fops_msg.retval); - fusd_file->msg_in = msg; - WAKE_UP_INTERRUPTIBLE(&fusd_file->file_wait); + transaction->msg_in = msg; + mb(); + + WAKE_UP_INTERRUPTIBLE_SYNC(&fusd_file->file_wait); + return 0; discard: @@ -1559,12 +1870,12 @@ return 0; } - 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; /* make sure args are valid */ if (fusd_dev == NULL) { @@ -1573,8 +1884,8 @@ } /* user can only register one device per instance */ - if (fusd_dev->handle != 0) - return -EBUSY; +// if (fusd_dev->handle != 0) +// return -EBUSY; register_msg.name[FUSD_MAX_NAME_LENGTH] = '\0'; @@ -1599,20 +1910,94 @@ RDEBUG(1, "yikes! kernel can't allocate memory"); return -ENOMEM; } + strcpy(fusd_dev->name, register_msg.name); - /* try to register the requested device */ - fusd_dev->handle = devfs_register(NULL, register_msg.name, - DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | register_msg.mode, - &fusd_client_fops, - fusd_dev); - /* make sure the registration was successful */ + /* 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("alloc_chrdev_region failed status: %d\n", error); + goto register_failed; + } + + fusd_dev->dev_id = dev_id; + + #ifdef CONFIG_DEVFS_FS + if((error = devfs_mk_cdev(dev_id, S_IFCHR | register_msg.mode, fusd_dev->name)) < 0) + { + printk("devfs_mk_cdev failed status: %d\n", error); + goto register_failed2; + } + #endif + + fusd_dev->handle = cdev_alloc(); + if(fusd_dev->handle == NULL) + { + 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) + { + printk("cdev_add failed status: %d\n", error); + kobject_put(&fusd_dev->handle->kobj); + goto register_failed3; + } + + // Hack to add my class to the sound class + if(strcmp("sound", register_msg.clazz) == 0) + { + fusd_dev->clazz = sound_class; + fusd_dev->owns_class = 0; + } + else + { + fusd_dev->clazz = class_create(THIS_MODULE, fusd_dev->class_name); + if(IS_ERR(fusd_dev->clazz)) + { + error = PTR_ERR(fusd_dev->clazz); + goto register_failed4; + } + fusd_dev->owns_class = 1; + } + + fusd_dev->class_device = class_device_create(fusd_dev->clazz, fusd_dev->dev_id, NULL, fusd_dev->dev_name); + if(fusd_dev->class_device == NULL) + { + error = PTR_ERR(fusd_dev->class_device); + printk("class_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; @@ -1624,7 +2009,17 @@ wake_up_interruptible(&new_device_wait); return 0; - register_failed: +register_failed5: + class_destroy(fusd_dev->clazz); +register_failed4: + cdev_del(fusd_dev->handle); +register_failed3: +#ifdef CONFIG_DEVFS_FS + devfs_remove(fusd_dev->name); +#endif +register_failed2: + unregister_chrdev_region(dev_id, 1); +register_failed: KFREE(fusd_dev->name); fusd_dev->name = NULL; return error; @@ -1643,7 +2038,7 @@ fusd_file_t **file_array = NULL; /* keep the module from being unloaded during initialization! */ - MOD_INC_USE_COUNT; + //MOD_INC_USE_COUNT; /* allocate memory for the device state */ if ((fusd_dev = KMALLOC(sizeof(fusd_dev_t), GFP_KERNEL)) == NULL) @@ -1657,6 +2052,7 @@ 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 */ @@ -1671,7 +2067,7 @@ KFREE(fusd_dev); dev_malloc_failed: RDEBUG(1, "out of memory in fusd_open!"); - MOD_DEC_USE_COUNT; + //MOD_DEC_USE_COUNT; return -ENOMEM; } @@ -1704,14 +2100,19 @@ } #endif - if (fusd_dev->handle) { - RDEBUG(3, "unregistering /dev/%s from pid %d", NAME(fusd_dev), - fusd_dev->pid); - devfs_unregister(fusd_dev->handle); - fusd_dev->handle = 0; - } else { - RDEBUG(2, "pid %d releasing without a registered device!", current->pid); - } + if(fusd_dev->handle) + { + class_device_destroy(fusd_dev->clazz, fusd_dev->dev_id); + if(fusd_dev->owns_class) + { + class_destroy(fusd_dev->clazz); + } + cdev_del(fusd_dev->handle); +#ifdef CONFIG_DEVFS_FS + devfs_remove(fusd_dev->name); +#endif + unregister_chrdev_region(fusd_dev->dev_id, 1); + } /* mark the driver as being gone */ zombify_dev(fusd_dev); @@ -1808,11 +2209,13 @@ } /* 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) { @@ -2118,7 +2521,7 @@ 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"); @@ -2131,8 +2534,8 @@ file->private_data = (void *) fs; out: - if (error) - MOD_DEC_USE_COUNT; + //if (error) + // MOD_DEC_USE_COUNT; return error; } @@ -2147,7 +2550,7 @@ KFREE(fs); } - MOD_DEC_USE_COUNT; + //MOD_DEC_USE_COUNT; return 0; } @@ -2243,9 +2646,9 @@ } len += snprintf(buf + len, buf_size - len, - "\nFUSD $Revision: 1.97 $ - %d devices used by %d clients\n", + "\nFUSD $Revision: 1.97-kor-hacked-8 $ - %d devices used by %d clients\n", total_files, total_clients); - + out: fs->last_version_seen = last_version; up(&fusd_devlist_sem); @@ -2383,15 +2786,16 @@ STATIC int init_fusd(void) { -#ifdef CONFIG_FUSD_MEMDEBUG - int retval; + int retval; +#ifdef CONFIG_FUSD_MEMDEBUG if ((retval = fusd_mem_init()) < 0) return retval; #endif + printk(KERN_INFO - "fusd: starting, $Revision: 1.97 $, $Date: 2003/07/11 22:29:39 $"); + "fusd: starting, $Revision: 1.97-kor-hacked-8 $, $Date: 2003/07/11 22:29:39 $"); #ifdef CVSTAG printk(", release %s", CVSTAG); #endif @@ -2401,40 +2805,148 @@ printk(", debugging messages disabled\n"); #endif - /* register the control channel with devfs */ - fusd_handle = - devfs_register(NULL, FUSD_CONTROL_FILENAME, - DEVFS_FL_AUTO_DEVNUM, 0, 0, - S_IFCHR | 0666, &fusd_fops, NULL); - - if (fusd_handle == NULL) { - printk("fusd: unable to register fusd control device!\n"); - return -EIO; - } - - - /* register the status device with devfs */ - fusd_status_handle = - devfs_register(NULL, FUSD_STATUS_FILENAME, - DEVFS_FL_AUTO_DEVNUM, 0, 0, - S_IFCHR | 0666, &fusd_status_fops, (void *) 0); + 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("class_create failed status: %d\n", retval); + goto fail0; + } + + control_id = 0; + + if((retval = alloc_chrdev_region(&control_id, 0, 1, FUSD_CONTROL_FILENAME)) < 0) + { + printk("alloc_chrdev_region failed status: %d\n", retval); + goto fail1; + } +#ifdef CONFIG_DEVFS_FS + if((retval = devfs_mk_cdev(control_id, S_IFCHR | 0666, FUSD_CONTROL_FILENAME)) < 0) + { + printk("devfs_mk_cdev failed status: %d\n", retval); + goto fail2; + } +#endif - if (fusd_status_handle == NULL) - printk("fusd: warning: unable to register status device\n"); + fusd_control_device = cdev_alloc(); + if(fusd_control_device == NULL) + { + retval = -ENOMEM; + goto fail3; + } + + fusd_control_device->owner = THIS_MODULE; + fusd_control_device->ops = &fusd_fops; + kobject_set_name(&fusd_control_device->kobj, FUSD_CONTROL_FILENAME); + + printk("cdev control id: %d\n", control_id); + if((retval = cdev_add(fusd_control_device, control_id, 1)) < 0) + { + printk("cdev_add failed status: %d\n", retval); + kobject_put(&fusd_control_device->kobj); + goto fail4; + } + + fusd_control_class_device = class_device_create(fusd_class, 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; + } + + status_id = 0; + + if((retval = alloc_chrdev_region(&status_id, 0, 1, FUSD_STATUS_FILENAME)) < 0) + { + printk("alloc_chrdev_region failed status: %d\n", retval); + goto fail6; + } +#ifdef CONFIG_DEVFS_FS + if((retval = devfs_mk_cdev(status_id, S_IFCHR | 0666, FUSD_STATUS_FILENAME)) < 0) + { + printk("devfs_mk_cdev failed status: %d\n", retval); + goto fail7; + } +#endif + fusd_status_device = cdev_alloc(); + if(fusd_status_device == NULL) + { + retval = -ENOMEM; + goto fail8; + } + + fusd_status_device->owner = THIS_MODULE; + fusd_status_device->ops = &fusd_status_fops; + kobject_set_name(&fusd_status_device->kobj, FUSD_STATUS_FILENAME); + + if((retval = cdev_add(fusd_status_device, status_id, 1)) < 0) + { + printk("cdev_add failed status: %d\n", retval); + kobject_put(&fusd_status_device->kobj); + goto fail9; + } + + fusd_status_class_device = class_device_create(fusd_class, status_id, NULL, "status"); + if(fusd_status_class_device == NULL) + { + printk("class_device_create failed status: %d\n", retval); + retval = PTR_ERR(fusd_status_class_device); + goto fail10; + } + RDEBUG(1, "registration successful"); return 0; + +fail10: + cdev_del(fusd_status_device); +fail9: + kfree(fusd_status_device); +fail8: +#ifdef CONFIG_DEVFS_FS + devfs_remove(FUSD_STATUS_FILENAME); +#endif +fail7: + unregister_chrdev_region(status_id, 1); +fail6: + class_device_destroy(fusd_class, control_id); +fail5: + cdev_del(fusd_control_device); +fail4: + kfree(fusd_control_device); +fail3: +#ifdef CONFIG_DEVFS_FS + devfs_remove(FUSD_CONTROL_FILENAME); +#endif +fail2: + unregister_chrdev_region(control_id, 1); + +fail1: + class_destroy(fusd_class); +fail0: + return retval; } STATIC void cleanup_fusd(void) { RDEBUG(1, "cleaning up"); - devfs_unregister(fusd_handle); + class_device_destroy(fusd_class, status_id); + class_device_destroy(fusd_class, control_id); + + cdev_del(fusd_control_device); + cdev_del(fusd_status_device); + + devfs_remove(FUSD_CONTROL_FILENAME); + devfs_remove(FUSD_STATUS_FILENAME); - if (fusd_status_handle) - devfs_unregister(fusd_status_handle); + class_destroy(fusd_class); + #ifdef CONFIG_FUSD_MEMDEBUG fusd_mem_cleanup(); #endif Only in fusd-1.10/kfusd: kfusd.c~ Only in fusd-kor-1.10-10/kfusd: .kfusd.ko.cmd Only in fusd-kor-1.10-10/kfusd: .kfusd.mod.o.cmd Only in fusd-kor-1.10-10/kfusd: .kfusd.o.cmd Only in fusd-kor-1.10-10/kfusd: Makefile Only in fusd-kor-1.10-10/kfusd: .tmp_versions diff -uar -x .svn fusd-1.10/libfusd/libfusd.c fusd-kor-1.10-10/libfusd/libfusd.c --- fusd-1.10/libfusd/libfusd.c 2003-07-11 16:29:39.000000000 -0600 +++ fusd-kor-1.10-10/libfusd/libfusd.c 2005-06-16 22:07:31.000000000 -0600 @@ -101,7 +101,6 @@ if (fusd_init_needed) { int i; - struct stat statbuf; fusd_init_needed = 0; @@ -109,19 +108,12 @@ FUSD_SET_FOPS(i, &null_fops); FD_ZERO(&fusd_fds); - /* test to see if devfs is actually mounted where we think it is */ - if (stat(DEFAULT_DEV_ROOT ".devfsd", &statbuf) < 0) { - fprintf(stderr, "libfusd: devfs doesn't seem mounted under %s!\n", - DEFAULT_DEV_ROOT); - dev_root = NULL; - } else { - dev_root = DEFAULT_DEV_ROOT; - } + dev_root = DEFAULT_DEV_ROOT; } } -int fusd_register(const char *name, mode_t mode, void *device_info, +int fusd_register(const char *name, const char* clazz, const char* devname, mode_t mode, void *device_info, struct fusd_file_operations *fops) { int fd = -1, retval = 0; @@ -181,6 +173,8 @@ message.cmd = FUSD_REGISTER_DEVICE; message.datalen = 0; strcpy(message.parm.register_msg.name, name); + strcpy(message.parm.register_msg.clazz, clazz); + strcpy(message.parm.register_msg.devname, devname); message.parm.register_msg.mode = mode; message.parm.register_msg.device_info = device_info; @@ -443,6 +437,13 @@ user_retval = fops->write(file, msg->data, msg->datalen, &msg->parm.fops_msg.offset); break; + case FUSD_MMAP: + if (fops && fops->mmap) + { + user_retval = fops->mmap(file, msg->parm.fops_msg.offset, msg->parm.fops_msg.length, msg->parm.fops_msg.flags, + (void**) &msg->parm.fops_msg.arg, &msg->parm.fops_msg.length); + } + break; case FUSD_IOCTL: if (fops && fops->ioctl) { /* in the case of an ioctl read, allocate a buffer for the diff -uar -x .svn fusd-1.10/Makefile fusd-kor-1.10-10/Makefile --- fusd-1.10/Makefile 2001-09-29 13:23:26.000000000 -0600 +++ fusd-kor-1.10-10/Makefile 2005-06-17 00:16:22.000000000 -0600 @@ -4,14 +4,14 @@ # # Change this to reflect where your kernel sources are -KERNEL_HOME := /usr/src/linux +KERNEL_HOME := /lib/modules/$(shell uname -r)/build ################################################################## TARGETS := \ libfusd.a \ - kfusd.o \ + kfusd.ko \ regdevice \ opentest \ simpleopen \ @@ -46,9 +46,11 @@ #################################################### +KDIR := /lib/modules/$(shell uname -r)/build -$(OBJDIR)/kfusd.o: $(MODPATH)/kfusd/kfusd.c fusd_msg.h kfusd.h - $(CC) $(KCFLAGS) -c $(MODPATH)/kfusd/kfusd.c -o $(OBJDIR)/kfusd.o +$(OBJDIR)/kfusd.ko: $(MODPATH)/kfusd/kfusd.c fusd_msg.h kfusd.h + $(MAKE) -C $(MODPATH)/kfusd +# $(CC) $(KCFLAGS) -c $(MODPATH)/kfusd/kfusd.c -o $(OBJDIR)/kfusd.o $(OBJDIR)/libfusd.a: $(OBJDIR)/libfusd.o $(AR) -cr $(OBJDIR)/libfusd.a $(OBJDIR)/libfusd.o @@ -64,3 +66,4 @@ install: cp $(OBJDIR)/libfusd.a /usr/local/lib cp include/*.h /usr/local/include + $(MAKE) -C $(MODPATH)/kfusd install diff -uar -x .svn fusd-1.10/make.include fusd-kor-1.10-10/make.include --- fusd-1.10/make.include 2001-09-29 13:27:16.000000000 -0600 +++ fusd-kor-1.10-10/make.include 2005-06-17 00:16:25.000000000 -0600 @@ -72,7 +72,7 @@ KERNEL_INCLUDE := $(KERNEL_HOME)/include BINSTRIP := strip -KCFLAGS += -I$(KERNEL_INCLUDE) $(INCLUDEPATH) +KCFLAGS += $(INCLUDEPATH) CFLAGS += $(INCLUDEPATH) $(LIBPATH) CCFLAGS += $(CFLAGS) Only in fusd-kor-1.10-10: obj.i686-linux diff -uar -x .svn fusd-1.10/test/ioctl.c fusd-kor-1.10-10/test/ioctl.c --- fusd-1.10/test/ioctl.c 2003-07-11 16:29:39.000000000 -0600 +++ fusd-kor-1.10-10/test/ioctl.c 2005-02-09 19:39:06.000000000 -0700 @@ -195,7 +195,7 @@ /* ioctl server */ struct fusd_file_operations f = { open: zeroreturn, close: zeroreturn, ioctl: do_ioctl}; - if (fusd_register("ioctltest", 0666, NULL, &f) < 0) + if (fusd_register("ioctltest", "misc", "ioctltest", 0666, NULL, &f) < 0) perror("registering ioctltest"); printf("server starting\n"); fusd_run(); diff -uar -x .svn fusd-1.10/test/opentest.c fusd-kor-1.10-10/test/opentest.c --- fusd-1.10/test/opentest.c 2003-07-11 16:29:40.000000000 -0600 +++ fusd-kor-1.10-10/test/opentest.c 2005-02-09 19:39:06.000000000 -0700 @@ -98,7 +98,7 @@ int f; if (argc != 2) { - fprintf(stderr, "usage: %s \n", argv[0]); + fprintf(stderr, "usage: %s \n", argv[0]); exit(0); } @@ -124,7 +124,7 @@ }; int fd; - if ((fd = fusd_register(argv[1], 0666, 0, &fops)) < 0) { + if ((fd = fusd_register(argv[1], argv[2], argv[3], 0666, 0, &fops)) < 0) { perror("Register failed"); } diff -uar -x .svn fusd-1.10/test/oracle.c fusd-kor-1.10-10/test/oracle.c --- fusd-1.10/test/oracle.c 2003-07-11 16:29:40.000000000 -0600 +++ fusd-kor-1.10-10/test/oracle.c 2005-02-09 19:39:06.000000000 -0700 @@ -116,7 +116,7 @@ struct fusd_file_operations f = { open: do_open, close: do_close, read: do_read, write: do_write }; - if (fusd_register("oracle", 0666, NULL, &f) < 0) + if (fusd_register("oracle", "misc", "oracle", 0666, NULL, &f) < 0) perror("/dev/oracle"); else { printf("oracle ready to answer queries\n"); diff -uar -x .svn fusd-1.10/test/regdevice.c fusd-kor-1.10-10/test/regdevice.c --- fusd-1.10/test/regdevice.c 2003-07-11 16:29:40.000000000 -0600 +++ fusd-kor-1.10-10/test/regdevice.c 2005-02-09 19:39:06.000000000 -0700 @@ -37,12 +37,12 @@ int main(int argc, char *argv[]) { - if (argc != 2) { - fprintf(stderr, "usage: %s \n", argv[0]); + if (argc != 4) { + fprintf(stderr, "usage: %s \n", argv[0]); exit(0); } - if (fusd_register(argv[1], 0666, 0, NULL) < 0) { + if (fusd_register(argv[1], argv[2], argv[3], 0666, 0, NULL) < 0) { perror("Register failed"); } else { printf("Registered %s - sleeping 10 seconds\n", argv[1]); diff -uar -x .svn fusd-1.10/test/rwtest.c fusd-kor-1.10-10/test/rwtest.c --- fusd-1.10/test/rwtest.c 2003-07-11 16:29:40.000000000 -0600 +++ fusd-kor-1.10-10/test/rwtest.c 2005-02-09 19:39:06.000000000 -0700 @@ -99,8 +99,8 @@ { int f; - if (argc != 2) { - fprintf(stderr, "usage: %s \n", argv[0]); + if (argc != 4) { + fprintf(stderr, "usage: %s \n", argv[0]); exit(0); } @@ -123,7 +123,7 @@ NULL, NULL}; - if (fusd_register(argv[1], 0666, 0, &fops) < 0) { + if (fusd_register(argv[1], argv[2], argv[3], 0666, 0, &fops) < 0) { perror("Register failed"); } else { fusd_run(); diff -uar -x .svn fusd-1.10/test/select_test.c fusd-kor-1.10-10/test/select_test.c --- fusd-1.10/test/select_test.c 2003-07-11 16:29:40.000000000 -0600 +++ fusd-kor-1.10-10/test/select_test.c 2005-02-09 19:39:06.000000000 -0700 @@ -180,19 +180,19 @@ int main(int argc, char *argv[]) { - if (argc != 3) { - fprintf(stderr, "usage: %s \n", + if (argc != 5) { + fprintf(stderr, "usage: %s \n", argv[0]); exit(1); } - if (!strcmp(argv[2], "server")) { + if (!strcmp(argv[4], "server")) { /* server */ struct fusd_file_operations f = { open: zeroreturn, close: zeroreturn, read: do_read, write: do_write, poll_diff: do_poll_diff}; printf("server starting\n"); - if (fusd_register(argv[1], 0666, NULL, &f) < 0) + if (fusd_register(argv[1], argv[2], argv[3], 0666, NULL, &f) < 0) perror(argv[1]); else fusd_run(); diff -uar -x .svn fusd-1.10/test/simpleopen.c fusd-kor-1.10-10/test/simpleopen.c --- fusd-1.10/test/simpleopen.c 2003-07-11 16:29:40.000000000 -0600 +++ fusd-kor-1.10-10/test/simpleopen.c 2005-02-09 19:39:06.000000000 -0700 @@ -92,7 +92,7 @@ struct fusd_file_operations f = { open: do_open, close: do_close, read: do_read, write: do_write }; - fd = fusd_register("/dev/open", 0666, NULL, &f); + fd = fusd_register("/dev/open", "misc", "open", 0666, NULL, &f); if (fd < 0) { perror("trying to register /dev/open"); diff -uar -x .svn fusd-1.10/test/statetest.c fusd-kor-1.10-10/test/statetest.c --- fusd-1.10/test/statetest.c 2003-07-11 16:29:40.000000000 -0600 +++ fusd-kor-1.10-10/test/statetest.c 2005-02-09 19:39:06.000000000 -0700 @@ -90,12 +90,15 @@ struct fusd_file_operations f = { open: do_close, close: do_close, read: do_read }; char *buf; + char *devname; int i; for (i = 0; i < n; i++) { buf = malloc(100); + devname = malloc(100); sprintf(buf, "/dev/fusd-test/state%03d", i); - if (fusd_register(buf, 0666, buf+strlen("/dev/fusd-test/state"), &f) < 0) + sprintf(devname, "state%03d", i); + if (fusd_register(buf, "fusd-test", devname, 0666, buf+strlen("/dev/fusd-test/state"), &f) < 0) perror(buf); } printf("server starting\n"); diff -uar -x .svn fusd-1.10/test/torturetest.c fusd-kor-1.10-10/test/torturetest.c --- fusd-1.10/test/torturetest.c 2003-07-11 16:29:40.000000000 -0600 +++ fusd-kor-1.10-10/test/torturetest.c 2005-02-09 19:39:06.000000000 -0700 @@ -80,6 +80,8 @@ int num; int retval; char **devs; + char **classes; + char **devnames; pid_t *pids; // init function table @@ -100,6 +102,8 @@ num = atoi(argv[1]); devs = (char**)malloc(sizeof(char *)*num); + classes = (char**)malloc(sizeof(char *)*num); + devnames = (char**)malloc(sizeof(char *)*num); pids = (pid_t *)malloc(sizeof(pid_t)*num); @@ -108,6 +112,10 @@ char dev[30]; sprintf(dev,"/dev/fusd-test/test%d",i); devs[i] = strdup(dev); + sprintf(dev,"fusd-test"); + classes[i] = strdup(dev); + sprintf(dev,"test%d",i); + devnames[i] = strdup(dev); } /* create devices; 2 devices handled per process */ @@ -116,7 +124,7 @@ if (fork2 == 0) { - if (fusd_register(devs[i], 0666, 0, &fops) < 0) { + if (fusd_register(devs[i], classes[i], devnames[i], 0666, 0, &fops) < 0) { perror("Register failed"); exit(1); } else { @@ -126,7 +134,7 @@ i++; if (i < num) { - if (fusd_register(devs[i], 0666, 0, &fops) < 0) { + if (fusd_register(devs[i], classes[i], devnames[i], 0666, 0, &fops) < 0) { perror("Register failed"); exit(1); } else { diff -uar -x .svn fusd-1.10/test/zero-fusd.c fusd-kor-1.10-10/test/zero-fusd.c --- fusd-1.10/test/zero-fusd.c 2003-07-11 16:29:40.000000000 -0600 +++ fusd-kor-1.10-10/test/zero-fusd.c 2005-02-09 19:39:06.000000000 -0700 @@ -54,7 +54,7 @@ struct fusd_file_operations f = { open: return_zero, close: return_zero, read: do_read }; - fd = fusd_register("zero-fusd", 0666, NULL, &f); + fd = fusd_register("zero-fusd", "misc", "zero-fusd", 0666, NULL, &f); if (fd < 0) { perror("trying to register /dev/zero-fusd");