psdev.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:59k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *              An implementation of a loadable kernel mode driver providing
  3.  *              multiple kernel/user space bidirectional communications links.
  4.  *
  5.  *              Author:         Alan Cox <alan@cymru.net>
  6.  *
  7.  *              This program is free software; you can redistribute it and/or
  8.  *              modify it under the terms of the GNU General Public License
  9.  *              as published by the Free Software Foundation; either version
  10.  *              2 of the License, or (at your option) any later version.
  11.  *
  12.  *              Adapted to become the Linux 2.0 Coda pseudo device
  13.  *              Peter  Braam  <braam@maths.ox.ac.uk>
  14.  *              Michael Callahan <mjc@emmy.smith.edu>
  15.  *
  16.  *              Changes for Linux 2.1
  17.  *              Copyright (c) 1997 Carnegie-Mellon University
  18.  *
  19.  *              Redone again for InterMezzo
  20.  *              Copyright (c) 1998 Peter J. Braam
  21.  *              Copyright (c) 2000 Mountain View Data, Inc.
  22.  *              Copyright (c) 2000 Tacitus Systems, Inc.
  23.  *              Copyright (c) 2001 Cluster File Systems, Inc.
  24.  *
  25.  * Extended attribute support
  26.  * Copyright (c) 2001 Shirish. H. Phatak
  27.  * Copyright (c) 2001 Tacit Networks, Inc.
  28.  */
  29. #include <linux/module.h>
  30. #include <linux/errno.h>
  31. #include <linux/kernel.h>
  32. #include <linux/major.h>
  33. #include <linux/sched.h>
  34. #include <linux/lp.h>
  35. #include <linux/slab.h>
  36. #include <linux/ioport.h>
  37. #include <linux/fcntl.h>
  38. #include <linux/delay.h>
  39. #include <linux/skbuff.h>
  40. #include <linux/proc_fs.h>
  41. #include <linux/vmalloc.h>
  42. #include <linux/fs.h>
  43. #include <linux/poll.h>
  44. #include <linux/init.h>
  45. #include <linux/list.h>
  46. #include <asm/io.h>
  47. #include <asm/segment.h>
  48. #include <asm/system.h>
  49. #include <asm/poll.h>
  50. #include <asm/uaccess.h>
  51. #include <linux/intermezzo_fs.h>
  52. #include <linux/intermezzo_upcall.h>
  53. #include <linux/intermezzo_psdev.h>
  54. #include <linux/intermezzo_kml.h>
  55. #ifdef PRESTO_DEVEL
  56. int  presto_print_entry = 1;
  57. int  presto_debug = 4095;
  58. #else
  59. int  presto_print_entry = 0;
  60. int  presto_debug = 0;
  61. #endif
  62. /* Like inode.c (presto_sym_iops), the initializer is just to prevent
  63.    upc_comms from appearing as a COMMON symbol (and therefore
  64.    interfering with other modules that use the same variable name. */
  65. struct upc_comm upc_comms[MAX_PRESTODEV] = {{0}};
  66. /*
  67.  * Device operations: map file to upcall structure
  68.  */
  69. static inline struct upc_comm *presto_psdev_f2u(struct file *file)
  70. {
  71.         int minor;
  72.         if ( MAJOR(file->f_dentry->d_inode->i_rdev) != PRESTO_PSDEV_MAJOR ) {
  73.                 EXIT;
  74.                 return NULL;
  75.         }
  76.         minor = MINOR(file->f_dentry->d_inode->i_rdev);
  77.         if ( minor < 0 || minor >= MAX_PRESTODEV ) {
  78.                 EXIT;
  79.                 return NULL;
  80.         }
  81.         return &(upc_comms[minor]);
  82. }
  83. inline int presto_lento_up(int minor) 
  84. {
  85.         return upc_comms[minor].uc_pid;
  86. }
  87. static unsigned int presto_psdev_poll(struct file *file, poll_table * wait)
  88. {
  89.         struct upc_comm *upccom;
  90.         unsigned int mask = POLLOUT | POLLWRNORM;
  91.         /* ENTRY; this will flood you */
  92.         if ( ! (upccom = presto_psdev_f2u(file)) ) {
  93.                 kdev_t dev = file->f_dentry->d_inode->i_rdev;
  94.                 printk("InterMezzo: %s, bad device %sn",
  95.                        __FUNCTION__, kdevname(dev));
  96.         }
  97.         poll_wait(file, &(upccom->uc_waitq), wait);
  98.         if (!list_empty(&upccom->uc_pending)) {
  99.                 CDEBUG(D_PSDEV, "Non-empty pending list.n");
  100.                 mask |= POLLIN | POLLRDNORM;
  101.         }
  102.         /* EXIT; will flood you */
  103.         return mask;
  104. }
  105. /*
  106.  *      Receive a message written by Lento to the psdev
  107.  */
  108. static ssize_t presto_psdev_write(struct file *file, const char *buf,
  109.                                   size_t count, loff_t *off)
  110. {
  111.         struct upc_comm *upccom;
  112.         struct upc_req *req = NULL;
  113.         struct upc_req *tmp;
  114.         struct list_head *lh;
  115.         struct lento_down_hdr hdr;
  116.         int error;
  117.         if ( ! (upccom = presto_psdev_f2u(file)) ) {
  118.                 kdev_t dev = file->f_dentry->d_inode->i_rdev;
  119.                 printk("InterMezzo: %s, bad device %sn",
  120.                        __FUNCTION__, kdevname(dev));
  121.         }
  122.         /* Peek at the opcode, uniquefier */
  123.         if ( count < sizeof(hdr) ) {
  124.               printk("presto_psdev_write: Lento didn't write full hdr.n");
  125.                 return -EINVAL;
  126.         }
  127.         error = copy_from_user(&hdr, buf, sizeof(hdr));
  128.         if ( error )
  129.                 return error;
  130.         CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%d,%d)n",
  131.                current->pid, hdr.opcode, hdr.unique);
  132.         /* Look for the message on the processing queue. */
  133.         lh  = &upccom->uc_processing;
  134.         while ( (lh = lh->next) != &upccom->uc_processing ) {
  135.                 tmp = list_entry(lh, struct upc_req , rq_chain);
  136.                 if (tmp->rq_unique == hdr.unique) {
  137.                         req = tmp;
  138.                       /* unlink here: keeps search length minimal */
  139.                         list_del(&req->rq_chain);
  140.                       INIT_LIST_HEAD(&req->rq_chain);
  141.                         CDEBUG(D_PSDEV,"Eureka opc %d uniq %d!n",
  142.                                hdr.opcode, hdr.unique);
  143.                         break;
  144.                 }
  145.         }
  146.         if (!req) {
  147.                 printk("psdev_write: msg (%d, %d) not foundn",
  148.                        hdr.opcode, hdr.unique);
  149.                 return(-ESRCH);
  150.         }
  151.         /* move data into response buffer. */
  152.         if (req->rq_bufsize < count) {
  153.                 printk("psdev_write: too much cnt: %d, cnt: %Zd, "
  154.                        "opc: %d, uniq: %d.n",
  155.                        req->rq_bufsize, count, hdr.opcode, hdr.unique);
  156.                 count = req->rq_bufsize; /* don't have more space! */
  157.         }
  158.         error = copy_from_user(req->rq_data, buf, count);
  159.         if ( error )
  160.                 return error;
  161.         /* adjust outsize: good upcalls can be aware of this */
  162.         req->rq_rep_size = count;
  163.         req->rq_flags |= REQ_WRITE;
  164.         wake_up(&req->rq_sleep);
  165.         return(count);
  166. }
  167. /*
  168.  *      Read a message from the kernel to Lento
  169.  */
  170. static ssize_t presto_psdev_read(struct file * file, char * buf,
  171.                                  size_t count, loff_t *off)
  172. {
  173.         struct upc_comm *upccom;
  174.         struct upc_req *req;
  175.         int result = count;
  176.         if ( ! (upccom = presto_psdev_f2u(file)) ) {
  177.                 kdev_t dev = file->f_dentry->d_inode->i_rdev;
  178.                 printk("InterMezzo: %s, bad device %sn",
  179.                        __FUNCTION__, kdevname(dev));
  180.         }
  181.         CDEBUG(D_PSDEV, "count %Zdn", count);
  182.         if (list_empty(&(upccom->uc_pending))) {
  183.                 CDEBUG(D_UPCALL, "Empty pending list in read, not goodn");
  184.                 return -EINVAL;
  185.         }
  186.         req = list_entry((upccom->uc_pending.next), struct upc_req, rq_chain);
  187.         list_del(&(req->rq_chain));
  188.       if (! (req->rq_flags & REQ_ASYNC) ) {
  189.               list_add(&(req->rq_chain), upccom->uc_processing.prev);
  190.       }
  191.       req->rq_flags |= REQ_READ;
  192.         /* Move the input args into userspace */
  193.         if (req->rq_bufsize <= count) {
  194.                 result = req->rq_bufsize;
  195.         }
  196.         if (count < req->rq_bufsize) {
  197.                 printk ("psdev_read: buffer too small, read %Zd of %d bytesn",
  198.                         count, req->rq_bufsize);
  199.         }
  200.         if ( copy_to_user(buf, req->rq_data, result) ) {
  201.                 return -EFAULT;
  202.         }
  203.         /* If request was asynchronous don't enqueue, but free */
  204.         if (req->rq_flags & REQ_ASYNC) {
  205.                 CDEBUG(D_PSDEV, "psdev_read: async msg (%d, %d), result %dn",
  206.                        req->rq_opcode, req->rq_unique, result);
  207.                 PRESTO_FREE(req->rq_data, req->rq_bufsize);
  208.                 PRESTO_FREE(req, sizeof(*req));
  209.                 return result;
  210.         }
  211.         return result;
  212. }
  213. static int presto_psdev_ioctl(struct inode *inode, struct file *file,
  214.                               unsigned int cmd, unsigned long arg)
  215. {
  216.         struct upc_comm *upccom;
  217.         /* XXX is this rdev or dev? */
  218.         kdev_t dev = inode->i_rdev;
  219.         ENTRY;
  220.         upccom = presto_psdev_f2u(file);
  221.         if ( !upccom) {
  222.                 printk("InterMezzo: %s, bad device %sn",
  223.                        __FUNCTION__, kdevname(dev));
  224.                 EXIT;
  225.                 return -ENODEV;
  226.         }
  227.         switch(cmd) {
  228.         case TCGETS:
  229.                 return -EINVAL;
  230.         case PRESTO_GETMOUNT: {
  231.                 /* return all the mounts for this device.  */
  232.                 int minor = 0;
  233.                 int len, outlen;
  234.                 struct readmount readmount;
  235.                 struct readmount *user_readmount = (struct readmount *) arg;
  236.                 char * tmp;
  237.                 int error;
  238.                 error = copy_from_user(&readmount, (void *)arg,
  239.                                        sizeof(readmount));
  240.                 if ( error )  {
  241.                         printk("psdev: can't copy %Zd bytes from %p to %pn",
  242.                                 sizeof(readmount), (struct readmount *) arg,
  243.                                 &readmount);
  244.                         EXIT;
  245.                         return error;
  246.                 }
  247.                 len = readmount.io_len;
  248.                 minor = MINOR(dev);
  249.                 PRESTO_ALLOC(tmp, char *, len);
  250.                 if (!tmp) {
  251.                         EXIT;
  252.                         return -ENOMEM;
  253.                 }
  254.                 outlen = presto_sprint_mounts(tmp, len, minor);
  255.                 CDEBUG(D_PSDEV, "presto_sprint_mounts returns %d bytesn",
  256.                                 outlen);
  257.                 /* as this came out on 1/3/2000, it could NEVER work.
  258.                  * So fix it ... RGM
  259.                  * I mean, let's let the compiler do a little work ...
  260.                  * gcc suggested the extra ()
  261.                  */
  262.                 error = copy_to_user(readmount.io_string, tmp, outlen);
  263.                 if ( error ) {
  264.                         CDEBUG(D_PSDEV, "Copy_to_user string 0x%p failedn",
  265.                                readmount.io_string);
  266.                 }
  267.                 if ((!error) && (error = copy_to_user(&(user_readmount->io_len),
  268.                                                       &outlen, sizeof(int))) ) {
  269.                         CDEBUG(D_PSDEV, "Copy_to_user len @0x%p failedn",
  270.                                &(user_readmount->io_len));
  271.                 }
  272.                 PRESTO_FREE(tmp, len);
  273.                 EXIT;
  274.                 return error;
  275.         }
  276.         case PRESTO_SETPID: {
  277.                 /*
  278.                  * This ioctl is performed by each Lento that starts up
  279.                  * and wants to do further communication with presto.
  280.                  */
  281.                 CDEBUG(D_PSDEV, "Setting current pid to %dn", current->pid);
  282.                 upccom->uc_pid = current->pid;
  283.                 if ( !list_empty(&upccom->uc_processing) ) {
  284.                         struct list_head *lh;
  285.                         struct upc_req *req;
  286.                         printk("WARNING: setpid & processing not empty!n");
  287.                         lh = &upccom->uc_processing;
  288.                         while ( (lh = lh->next) != &upccom->uc_processing) {
  289.                                 req = list_entry(lh, struct upc_req, rq_chain);
  290.                                 /* freeing of req and data is done by the sleeper */
  291.                                 wake_up(&req->rq_sleep);
  292.                         }
  293.                 }
  294.                 if ( !list_empty(&upccom->uc_processing) ) {
  295.                         printk("BAD: FAILDED TO CLEAN PROCESSING LIST!n");
  296.                 }
  297.                 EXIT;
  298.                 return 0;
  299.         }
  300.         case PRESTO_CLEAR_FSETROOT: {
  301.                 /*
  302.                  * Close KML files.
  303.                  */
  304.                 int error;
  305.                 int saved_pid = upccom->uc_pid;
  306.                 char *path;
  307.                 struct {
  308.                         char *path;
  309.                         int   path_len;
  310.                 } input;
  311.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  312.                 if ( error ) {
  313.                         EXIT;
  314.                         return error;
  315.                 }
  316.                 PRESTO_ALLOC(path, char *, input.path_len + 1);
  317.                 if ( !path ) {
  318.                         EXIT;
  319.                         return -ENOMEM;
  320.                 }
  321.                 error = copy_from_user(path, input.path, input.path_len);
  322.                 if ( error ) {
  323.                         PRESTO_FREE(path, input.path_len + 1);
  324.                         EXIT;
  325.                         return error;
  326.                 }
  327.                 path[input.path_len] = '';
  328.                 CDEBUG(D_PSDEV, "clear_fsetroot: path %sn", path);
  329.                 upccom->uc_pid = current->pid;
  330.                 error = presto_clear_fsetroot(path);
  331.                 upccom->uc_pid = saved_pid;
  332.                 PRESTO_FREE(path, input.path_len + 1);
  333.                 EXIT;
  334.                 return error;
  335.         }
  336.         case PRESTO_CLEAR_ALL_FSETROOTS: {
  337.                 /*
  338.                  * Close KML files.
  339.                  */
  340.                 int error;
  341.                 int saved_pid = upccom->uc_pid;
  342.                 char *path;
  343.                 struct {
  344.                         char *path;
  345.                         int   path_len;
  346.                 } input;
  347.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  348.                 if ( error ) {
  349.                         EXIT;
  350.                         return error;
  351.                 }
  352.                 PRESTO_ALLOC(path, char *, input.path_len + 1);
  353.                 if ( !path ) {
  354.                         EXIT;
  355.                         return -ENOMEM;
  356.                 }
  357.                 error = copy_from_user(path, input.path, input.path_len);
  358.                 if ( error ) {
  359.                         PRESTO_FREE(path, input.path_len + 1);
  360.                         EXIT;
  361.                         return error;
  362.                 }
  363.                 path[input.path_len] = '';
  364.                 CDEBUG(D_PSDEV, "clear_all_fsetroot: path %sn", path);
  365.                 upccom->uc_pid = current->pid;
  366.                 error = presto_clear_all_fsetroots(path);
  367.                 upccom->uc_pid = saved_pid;
  368.                 PRESTO_FREE(path, input.path_len + 1);
  369.                 EXIT;
  370.                 return error;
  371.         }
  372.         case PRESTO_GET_KMLSIZE: {
  373.                 int error;
  374.                 int saved_pid = upccom->uc_pid;
  375.                 char *path;
  376.                 size_t size = 0;
  377.                 struct {
  378.                         __u64 size;
  379.                         char *path;
  380.                         int   path_len;
  381.                 } input;
  382.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  383.                 if ( error ) {
  384.                         EXIT;
  385.                         return error;
  386.                 }
  387.                 PRESTO_ALLOC(path, char *, input.path_len + 1);
  388.                 if ( !path ) {
  389.                         EXIT;
  390.                         return -ENOMEM;
  391.                 }
  392.                 error = copy_from_user(path, input.path, input.path_len);
  393.                 if ( error ) {
  394.                         PRESTO_FREE(path, input.path_len + 1);
  395.                         EXIT;
  396.                         return error;
  397.                 }
  398.                 path[input.path_len] = '';
  399.                 CDEBUG(D_PSDEV, "get_kmlsize: len %d path %sn", 
  400.                        input.path_len, path);
  401.                 upccom->uc_pid = current->pid;
  402.                 error = presto_get_kmlsize(path, &size);
  403.                 PRESTO_FREE(path, input.path_len + 1);
  404.                 if (error) {
  405.                         EXIT;
  406.                         return error;
  407.                 }
  408.                 input.size = size;
  409.                 upccom->uc_pid = saved_pid;
  410.                 CDEBUG(D_PSDEV, "get_kmlsize: size = %Zdn", size);
  411.                 EXIT;
  412.                 return copy_to_user((char *)arg, &input, sizeof(input));
  413.         }
  414.         case PRESTO_GET_RECNO: {
  415.                 int error;
  416.                 int saved_pid = upccom->uc_pid;
  417.                 char *path;
  418.                 off_t recno = 0;
  419.                 struct {
  420.                         __u64 recno;
  421.                         char *path;
  422.                         int   path_len;
  423.                 } input;
  424.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  425.                 if ( error ) {
  426.                         EXIT;
  427.                         return error;
  428.                 }
  429.                 PRESTO_ALLOC(path, char *, input.path_len + 1);
  430.                 if ( !path ) {
  431.                         EXIT;
  432.                         return -ENOMEM;
  433.                 }
  434.                 error = copy_from_user(path, input.path, input.path_len);
  435.                 if ( error ) {
  436.                         PRESTO_FREE(path, input.path_len + 1);
  437.                         EXIT;
  438.                         return error;
  439.                 }
  440.                 path[input.path_len] = '';
  441.                 CDEBUG(D_PSDEV, "get_recno: len %d path %sn", 
  442.                        input.path_len, path);
  443.                 upccom->uc_pid = current->pid;
  444.                 error = presto_get_lastrecno(path, &recno);
  445.                 PRESTO_FREE(path, input.path_len + 1);
  446.                 if (error) {
  447.                         EXIT;
  448.                         return error;
  449.                 }
  450.                 input.recno = recno;
  451.                 upccom->uc_pid = saved_pid;
  452.                 CDEBUG(D_PSDEV, "get_recno: recno = %dn", (int) recno);
  453.                 EXIT;
  454.                 return copy_to_user((char *)arg, &input, sizeof(input));
  455.         }
  456.         case PRESTO_SET_FSETROOT: {
  457.                 /*
  458.                  * Save information about the cache, and initialize "special"
  459.                  * cache files (KML, etc).
  460.                  */
  461.                 int error;
  462.                 int saved_pid = upccom->uc_pid;
  463.                 char *fsetname;
  464.                 char *path;
  465.                 struct {
  466.                         char *path;
  467.                         int   path_len;
  468.                         char *name;
  469.                         int   name_len;
  470.                         int   id;
  471.                         int   flags;
  472.                 } input;
  473.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  474.                 if ( error ) {
  475.                         EXIT;
  476.                         return error;
  477.                 }
  478.                 PRESTO_ALLOC(path, char *, input.path_len + 1);
  479.                 if ( !path ) {
  480.                         EXIT;
  481.                         return -ENOMEM;
  482.                 }
  483.                 error = copy_from_user(path, input.path, input.path_len);
  484.                 if ( error ) {
  485.                         EXIT;
  486.                         goto exit_free_path;
  487.                 }
  488.                 path[input.path_len] = '';
  489.                 PRESTO_ALLOC(fsetname, char *, input.name_len + 1);
  490.                 if ( !fsetname ) {
  491.                         error = -ENOMEM;
  492.                         EXIT;
  493.                         goto exit_free_path;
  494.                 }
  495.                 error = copy_from_user(fsetname, input.name, input.name_len);
  496.                 if ( error ) {
  497.                         EXIT;
  498.                         goto exit_free_fsetname;
  499.                 }
  500.                 fsetname[input.name_len] = '';
  501.                 CDEBUG(D_PSDEV,
  502.                        "set_fsetroot: path %s name %s, id %d, flags %xn",
  503.                        path, fsetname, input.id, input.flags);
  504.                 upccom->uc_pid = current->pid;
  505.                 error = presto_set_fsetroot(path, fsetname, input.id,input.flags);
  506.                 upccom->uc_pid = saved_pid;
  507.                 if ( error ) {
  508.                         EXIT;
  509.                         goto exit_free_fsetname;
  510.                 }
  511.                 /* fsetname is kept in the fset, so don't free it now */
  512.                 PRESTO_FREE(path, input.path_len + 1);
  513.                 EXIT;
  514.                 return 0;
  515.         exit_free_fsetname:
  516.                 PRESTO_FREE(fsetname, input.name_len + 1);
  517.         exit_free_path:
  518.                 PRESTO_FREE(path, input.path_len + 1);
  519.                 return error;
  520.         }
  521.         case PRESTO_CLOSE_JOURNALF: {
  522.                 int saved_pid = upccom->uc_pid;
  523.                 int error;
  524.                 CDEBUG(D_SUPER, "HELLOn");
  525.                 /* pretend we are lento: we should lock something */
  526.                 upccom->uc_pid = current->pid;
  527.                 error = presto_close_journal_file(NULL);
  528.                 CDEBUG(D_PSDEV, "error is %dn", error);
  529.                 upccom->uc_pid = saved_pid;
  530.                 EXIT;
  531.                 return error;
  532.         }
  533.         case PRESTO_GETOPT:
  534.         case PRESTO_SETOPT: {
  535.                 /* return all the mounts for this device.  */
  536.                 int dosetopt(int, struct psdev_opt *);
  537.                 int dogetopt(int, struct psdev_opt *);
  538.                 int minor = 0;
  539.                 struct psdev_opt kopt;
  540.                 struct psdev_opt *user_opt = (struct psdev_opt *) arg;
  541.                 int error;
  542.                 error = copy_from_user(&kopt, (void *)arg, sizeof(kopt));
  543.                 if ( error )  {
  544.                         printk("psdev: can't copyin %Zd bytes from %p to %pn",
  545.                                sizeof(kopt), (struct kopt *) arg, &kopt);
  546.                         EXIT;
  547.                         return error;
  548.                 }
  549.                 minor = MINOR(dev);
  550.                 if (cmd == PRESTO_SETOPT)
  551.                         error = dosetopt(minor, &kopt);
  552.                 if ( error ) {
  553.                         CDEBUG(D_PSDEV,
  554.                                "dosetopt failed minor %d, opt %d, val %dn",
  555.                                minor, kopt.optname, kopt.optval);
  556.                         EXIT;
  557.                         return error;
  558.                 }
  559.                 error = dogetopt(minor, &kopt);
  560.                 if ( error ) {
  561.                         CDEBUG(D_PSDEV,
  562.                                "dogetopt failed minor %d, opt %d, val %dn",
  563.                                minor, kopt.optname, kopt.optval);
  564.                         EXIT;
  565.                         return error;
  566.                 }
  567.                 error = copy_to_user(user_opt, &kopt, sizeof(kopt));
  568.                 if ( error ) {
  569.                         CDEBUG(D_PSDEV, "Copy_to_user opt 0x%p failedn",
  570.                                user_opt);
  571.                         EXIT;
  572.                         return error;
  573.                 }
  574.                 CDEBUG(D_PSDEV, "dosetopt minor %d, opt %d, val %d return %dn",
  575.                          minor, kopt.optname, kopt.optval, error);
  576.                 EXIT;
  577.                 return 0;
  578.         }
  579.         case PRESTO_VFS_SETATTR: {
  580.                 int error;
  581.                 struct lento_input_attr input;
  582.                 struct iattr iattr;
  583.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  584.                 if ( error ) {
  585.                         EXIT;
  586.                         return error;
  587.                 }
  588.                 iattr.ia_valid = input.valid;
  589.                 iattr.ia_mode  = (umode_t)input.mode;
  590.                 iattr.ia_uid   = (uid_t)input.uid;
  591.                 iattr.ia_gid   = (gid_t)input.gid;
  592.                 iattr.ia_size  = (off_t)input.size;
  593.                 iattr.ia_atime = (time_t)input.atime;
  594.                 iattr.ia_mtime = (time_t)input.mtime;
  595.                 iattr.ia_ctime = (time_t)input.ctime;
  596.                 iattr.ia_attr_flags = input.attr_flags;
  597.                 error = lento_setattr(input.name, &iattr, &input.info);
  598.                 EXIT;
  599.                 return error;
  600.         }
  601.         case PRESTO_VFS_CREATE: {
  602.                 int error;
  603.                 struct lento_input_mode input;
  604.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  605.                 if ( error ) {
  606.                         EXIT;
  607.                         return error;
  608.                 }
  609.                 error = lento_create(input.name, input.mode, &input.info);
  610.                 EXIT;
  611.                 return error;
  612.         }
  613.         case PRESTO_VFS_LINK: {
  614.                 int error;
  615.                 struct lento_input_old_new input;
  616.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  617.                 if ( error ) {
  618.                         EXIT;
  619.                         return error;
  620.                 }
  621.                 error = lento_link(input.oldname, input.newname, &input.info);
  622.                 EXIT;
  623.                 return error;
  624.         }
  625.         case PRESTO_VFS_UNLINK: {
  626.                 int error;
  627.                 struct lento_input input;
  628.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  629.                 if ( error ) {
  630.                         EXIT;
  631.                         return error;
  632.                 }
  633.                 error = lento_unlink(input.name, &input.info);
  634.                 EXIT;
  635.                 return error;
  636.         }
  637.         case PRESTO_VFS_SYMLINK: {
  638.                 int error;
  639.                 struct lento_input_old_new input;
  640.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  641.                 if ( error ) {
  642.                         EXIT;
  643.                         return error;
  644.                 }
  645.                 error = lento_symlink(input.oldname, input.newname,&input.info);
  646.                 EXIT;
  647.                 return error;
  648.         }
  649.         case PRESTO_VFS_MKDIR: {
  650.                 int error;
  651.                 struct lento_input_mode input;
  652.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  653.                 if ( error ) {
  654.                         EXIT;
  655.                         return error;
  656.                 }
  657.                 error = lento_mkdir(input.name, input.mode, &input.info);
  658.                 EXIT;
  659.                 return error;
  660.         }
  661.         case PRESTO_VFS_RMDIR: {
  662.                 int error;
  663.                 struct lento_input input;
  664.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  665.                 if ( error ) {
  666.                         EXIT;
  667.                         return error;
  668.                 }
  669.                 error = lento_rmdir(input.name, &input.info);
  670.                 EXIT;
  671.                 return error;
  672.         }
  673.         case PRESTO_VFS_MKNOD: {
  674.                 int error;
  675.                 struct lento_input_dev input;
  676.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  677.                 if ( error ) {
  678.                         EXIT;
  679.                         return error;
  680.                 }
  681.                 error = lento_mknod(input.name, input.mode,
  682.                                     MKDEV(input.major,input.minor),&input.info);
  683.                 EXIT;
  684.                 return error;
  685.         }
  686.         case PRESTO_VFS_RENAME: {
  687.                 int error;
  688.                 struct lento_input_old_new input;
  689.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  690.                 if ( error ) {
  691.                         EXIT;
  692.                         return error;
  693.                 }
  694.                 error = lento_rename(input.oldname, input.newname, &input.info);
  695.                 EXIT;
  696.                 return error;
  697.         }
  698. #ifdef CONFIG_FS_EXT_ATTR
  699.         /* IOCTL to create/modify an extended attribute */
  700.         case PRESTO_VFS_SETEXTATTR: {
  701.                 int error;
  702.                 struct lento_input_ext_attr input;
  703.                 char *name;
  704.                 char *buffer;
  705.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  706.                 if ( error ) { 
  707.                     EXIT;
  708.                     return error;
  709.                 }
  710.                 /* Now setup the input parameters */
  711.                 PRESTO_ALLOC(name, char *, input.name_len+1);
  712.                 /* We need null terminated strings for attr names */
  713.                 name[input.name_len] = '';
  714.                 error=copy_from_user(name, input.name, input.name_len);
  715.                 if ( error ) { 
  716.                     EXIT;
  717.                     PRESTO_FREE(name,input.name_len+1);
  718.                     return error;
  719.                 }
  720.                 PRESTO_ALLOC(buffer, char *, input.buffer_len+1);
  721.                 error=copy_from_user(buffer, input.buffer, input.buffer_len);
  722.                 if ( error ) { 
  723.                     EXIT;
  724.                     PRESTO_FREE(name,input.name_len+1);
  725.                     PRESTO_FREE(buffer,input.buffer_len+1);
  726.                     return error;
  727.                 }
  728.                 /* Make null terminated for easy printing */
  729.                 buffer[input.buffer_len]='';
  730.  
  731.                 CDEBUG(D_PSDEV," setextattr params: name %s, valuelen %d,"
  732.                        " value %s, attr flags %x, mode %o, slot offset %d,"
  733.                        " recno %d, kml offset %lu, flags %x, time %dn", 
  734.                        name, input.buffer_len, buffer, input.flags, input.mode,
  735.                        input.info.slot_offset, input.info.recno,
  736.                        (unsigned long) input.info.kml_offset, input.info.flags,
  737.                        input.info.updated_time);
  738.                 error=lento_set_ext_attr
  739.                       (input.path,name,buffer,input.buffer_len,
  740.                        input.flags, input.mode, &input.info);
  741.                 PRESTO_FREE(name,input.name_len+1);
  742.                 PRESTO_FREE(buffer,input.buffer_len+1);
  743.                 EXIT;
  744.                 return error;
  745.         }
  746.         /* IOCTL to delete an extended attribute */
  747.         case PRESTO_VFS_DELEXTATTR: {
  748.                 int error;
  749.                 struct lento_input_ext_attr input;
  750.                 char *name;
  751.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  752.                 if ( error ) { 
  753.                     EXIT;
  754.                     return error;
  755.                 }
  756.                 /* Now setup the input parameters */
  757.                 PRESTO_ALLOC(name, char *, input.name_len+1);
  758.                 /* We need null terminated strings for attr names */
  759.                 name[input.name_len] = '';
  760.                 error=copy_from_user(name, input.name, input.name_len);
  761.                 if ( error ) { 
  762.                     EXIT;
  763.                     PRESTO_FREE(name,input.name_len+1);
  764.                     return error;
  765.                 }
  766.                 CDEBUG(D_PSDEV," delextattr params: name %s,"
  767.                        " attr flags %x, mode %o, slot offset %d, recno %d,"
  768.                        " kml offset %lu, flags %x, time %dn", 
  769.                        name, input.flags, input.mode,
  770.                        input.info.slot_offset, input.info.recno,
  771.                        (unsigned long) input.info.kml_offset, input.info.flags,
  772.                        input.info.updated_time);
  773.                 error=lento_set_ext_attr
  774.                       (input.path,name,NULL,0,input.flags,
  775.                        input.mode,&input.info);
  776.                 PRESTO_FREE(name,input.name_len+1);
  777.                 EXIT;
  778.                 return error;
  779.         }
  780. #endif
  781.         case PRESTO_VFS_IOPEN: {
  782.                 struct lento_input_iopen input;
  783.                 int error;
  784.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  785.                 if ( error ) {
  786.                         EXIT;
  787.                         return error;
  788.                 }
  789.                 input.fd = lento_iopen(input.name, (ino_t)input.ino,
  790.                                        input.generation, input.flags);
  791.                 CDEBUG(D_PIOCTL, "lento_iopen file descriptor: %dn", input.fd);
  792.                 if (input.fd < 0) {
  793.                         EXIT;
  794.                         return input.fd;
  795.                 }
  796.                 EXIT;
  797.                 return copy_to_user((char *)arg, &input, sizeof(input));
  798.         }
  799.         case PRESTO_VFS_CLOSE: {
  800.                 int error;
  801.                 struct lento_input_close input;
  802.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  803.                 if ( error ) {
  804.                         EXIT;
  805.                         return error;
  806.                 }
  807.                 CDEBUG(D_PIOCTL, "lento_close file descriptor: %dn", input.fd);
  808.                 error = lento_close(input.fd, &input.info);
  809.                 EXIT;
  810.                 return error;
  811.         }
  812.         case PRESTO_BACKFETCH_LML: {
  813.                 char *user_path;
  814.                 int error;
  815.                 struct lml_arg {
  816.                         char *path;
  817.                         __u32 path_len;
  818.                         __u64 remote_ino;
  819.                         __u32 remote_generation;
  820.                         __u32 remote_version;
  821.                         struct presto_version remote_file_version;
  822.                 } input;
  823.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  824.                 if ( error ) {
  825.                         EXIT;
  826.                         return error;
  827.                 }
  828.                 user_path = input.path;
  829.                 PRESTO_ALLOC(input.path, char *, input.path_len + 1);
  830.                 if ( !input.path ) {
  831.                         EXIT;
  832.                         return -ENOMEM;
  833.                 }
  834.                 error = copy_from_user(input.path, user_path, input.path_len);
  835.                 if ( error ) {
  836.                         EXIT;
  837.                         PRESTO_FREE(input.path, input.path_len + 1);
  838.                         return error;
  839.                 }
  840.                 input.path[input.path_len] = '';
  841.                 CDEBUG(D_DOWNCALL, "lml name: %sn", input.path);
  842.                 
  843.                 return lento_write_lml(input.path, 
  844.                                        input.remote_ino, 
  845.                                        input.remote_generation,
  846.                                        input.remote_version,
  847.                                        &input.remote_file_version); 
  848.         }
  849.                 
  850.         case PRESTO_CANCEL_LML: {
  851.                 char *user_path;
  852.                 int error;
  853.                 struct lml_arg {
  854.                         char *path;
  855.                         __u64 lml_offset; 
  856.                         __u32 path_len;
  857.                         __u64 remote_ino;
  858.                         __u32 remote_generation;
  859.                         __u32 remote_version;
  860.                         struct lento_vfs_context info;
  861.                 } input;
  862.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  863.                 if ( error ) {
  864.                         EXIT;
  865.                         return error;
  866.                 }
  867.                 user_path = input.path;
  868.                 PRESTO_ALLOC(input.path, char *, input.path_len + 1);
  869.                 if ( !input.path ) {
  870.                         EXIT;
  871.                         return -ENOMEM;
  872.                 }
  873.                 error = copy_from_user(input.path, user_path, input.path_len);
  874.                 if ( error ) {
  875.                         EXIT;
  876.                         PRESTO_FREE(input.path, input.path_len + 1);
  877.                         return error;
  878.                 }
  879.                 input.path[input.path_len] = '';
  880.                 CDEBUG(D_DOWNCALL, "lml name: %sn", input.path);
  881.                 
  882.                 return lento_cancel_lml(input.path, 
  883.                                         input.lml_offset, 
  884.                                         input.remote_ino, 
  885.                                         input.remote_generation,
  886.                                         input.remote_version,
  887.                                         &input.info); 
  888.         }
  889.         case PRESTO_COMPLETE_CLOSES: {
  890.                 char *user_path;
  891.                 int error;
  892.                 struct lml_arg {
  893.                         char *path;
  894.                         __u32 path_len;
  895.                 } input;
  896.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  897.                 if ( error ) {
  898.                         EXIT;
  899.                         return error;
  900.                 }
  901.                 user_path = input.path;
  902.                 PRESTO_ALLOC(input.path, char *, input.path_len + 1);
  903.                 if ( !input.path ) {
  904.                         EXIT;
  905.                         return -ENOMEM;
  906.                 }
  907.                 error = copy_from_user(input.path, user_path, input.path_len);
  908.                 if ( error ) {
  909.                         EXIT;
  910.                         PRESTO_FREE(input.path, input.path_len + 1);
  911.                         return error;
  912.                 }
  913.                 input.path[input.path_len] = '';
  914.                 CDEBUG(D_DOWNCALL, "lml name: %sn", input.path);
  915.                 
  916.                 error = lento_complete_closes(input.path);
  917.                 PRESTO_FREE(input.path, input.path_len + 1);
  918.                 return error;
  919.         }
  920.         case PRESTO_RESET_FSET: {
  921.                 char *user_path;
  922.                 int error;
  923.                 struct lml_arg {
  924.                         char *path;
  925.                         __u32 path_len;
  926.                         __u64 offset;
  927.                         __u32 recno;
  928.                 } input;
  929.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  930.                 if ( error ) {
  931.                         EXIT;
  932.                         return error;
  933.                 }
  934.                 user_path = input.path;
  935.                 PRESTO_ALLOC(input.path, char *, input.path_len + 1);
  936.                 if ( !input.path ) {
  937.                         EXIT;
  938.                         return -ENOMEM;
  939.                 }
  940.                 error = copy_from_user(input.path, user_path, input.path_len);
  941.                 if ( error ) {
  942.                         EXIT;
  943.                         PRESTO_FREE(input.path, input.path_len + 1);
  944.                         return error;
  945.                 }
  946.                 input.path[input.path_len] = '';
  947.                 CDEBUG(D_DOWNCALL, "lml name: %sn", input.path);
  948.                 
  949.                 return lento_reset_fset(input.path, input.offset, input.recno); 
  950.         }
  951.                 
  952.         case PRESTO_MARK: {
  953.                 char *user_path;
  954.                 int res = 0;  /* resulting flags - returned to user */
  955.                 int error;
  956.                 struct {
  957.                         int  mark_what;
  958.                         int  and_flag;
  959.                         int  or_flag;
  960.                         int path_len;
  961.                         char *path;
  962.                 } input;
  963.                 error = copy_from_user(&input, (char *)arg, sizeof(input));
  964.                 if ( error ) {
  965.                         EXIT;
  966.                         return error;
  967.                 }
  968.                 user_path = input.path;
  969.                 PRESTO_ALLOC(input.path, char *, input.path_len + 1);
  970.                 if ( !input.path ) {
  971.                         EXIT;
  972.                         return -ENOMEM;
  973.                 }
  974.                 error = copy_from_user(input.path, user_path, input.path_len);
  975.                 if ( error ) {
  976.                         EXIT;
  977.                         PRESTO_FREE(input.path, input.path_len + 1);
  978.                         return error;
  979.                 }
  980.                 input.path[input.path_len] = '';
  981.                 CDEBUG(D_DOWNCALL, "mark name: %s, and: %x, or: %x, what %dn",
  982.                        input.path, input.and_flag, input.or_flag, 
  983.                        input.mark_what);
  984.                 switch (input.mark_what) {
  985.                 case MARK_DENTRY:               
  986.                         error = presto_mark_dentry(input.path,
  987.                                                    input.and_flag,
  988.                                                    input.or_flag, &res);
  989.                         break;
  990.                 case MARK_FSET:
  991.                         error = presto_mark_fset(input.path,
  992.                                                    input.and_flag,
  993.                                                    input.or_flag, &res);
  994.                         break;
  995.                 case MARK_CACHE:
  996.                         error = presto_mark_cache(input.path,
  997.                                                    input.and_flag,
  998.                                                    input.or_flag, &res);
  999.                         break;
  1000.                 case MARK_GETFL: {
  1001.                         int fflags, cflags;
  1002.                         input.and_flag = 0xffffffff;
  1003.                         input.or_flag = 0; 
  1004.                         error = presto_mark_dentry(input.path,
  1005.                                                    input.and_flag,
  1006.                                                    input.or_flag, &res);
  1007.                         if (error) 
  1008.                                 break;
  1009.                         error = presto_mark_fset(input.path,
  1010.                                                    input.and_flag,
  1011.                                                    input.or_flag, &fflags);
  1012.                         if (error) 
  1013.                                 break;
  1014.                         error = presto_mark_cache(input.path,
  1015.                                                    input.and_flag,
  1016.                                                    input.or_flag, &cflags);
  1017.                         if (error) 
  1018.                                 break;
  1019.                         input.and_flag = fflags;
  1020.                         input.or_flag = cflags;
  1021.                  break;
  1022.                 }
  1023.                 default:
  1024.                         error = -EINVAL;
  1025.                 }
  1026.                 PRESTO_FREE(input.path, input.path_len + 1);
  1027.                 if (error == -EBUSY) {
  1028.                         input.and_flag = error;
  1029.                         error = 0;
  1030.                 }
  1031.                 if (error) { 
  1032.                         EXIT;
  1033.                         return error;
  1034.                 }
  1035.                 /* return the correct cookie to wait for */
  1036.                 input.mark_what = res;
  1037.                 return copy_to_user((char *)arg, &input, sizeof(input));
  1038.         }
  1039. #ifdef  CONFIG_KREINT
  1040.         case PRESTO_REINT_BEGIN:
  1041.                 return begin_kml_reint (file, arg);
  1042.         case PRESTO_DO_REINT:
  1043.                 return do_kml_reint (file, arg);
  1044.         case PRESTO_REINT_END:
  1045.                 return end_kml_reint (file, arg);
  1046. #endif
  1047.         case PRESTO_RELEASE_PERMIT: {
  1048.                 int error;
  1049.                 char *user_path;
  1050.                 struct {
  1051.                         int  cookie;
  1052.                         int path_len;
  1053.                         char *path;
  1054.                 } permit;
  1055.                 
  1056.                 error = copy_from_user(&permit, (char *)arg, sizeof(permit));
  1057.                 if ( error ) {
  1058.                         EXIT;
  1059.                         return error;
  1060.                         }
  1061.                 user_path = permit.path;
  1062.                 
  1063.                 PRESTO_ALLOC(permit.path, char *, permit.path_len + 1);
  1064.                 if ( !permit.path ) {
  1065.                         EXIT;
  1066.                         return -ENOMEM;
  1067.                 }
  1068.                 error = copy_from_user(permit.path, user_path, permit.path_len);
  1069.                 if ( error ) {
  1070.                         EXIT;
  1071.                         PRESTO_FREE(permit.path, permit.path_len + 1);
  1072.                         return error;
  1073.                 }
  1074.                 permit.path[permit.path_len] = '';
  1075.                 
  1076.                 CDEBUG(D_DOWNCALL, "release permit: %s, in cookie=%dn",
  1077.                        permit.path, permit.cookie);
  1078.                 error = presto_permit_downcall(permit.path, &permit.cookie);
  1079.                 
  1080.                 PRESTO_FREE(permit.path, permit.path_len + 1);
  1081.                 if (error) {
  1082.                         EXIT;
  1083.                         return error;
  1084.                 }
  1085.                 /* return the correct cookie to wait for */
  1086.                 return copy_to_user((char *)arg, &permit, sizeof(permit));
  1087.         }
  1088.         
  1089.         default:
  1090.                 CDEBUG(D_PSDEV, "bad ioctl 0x%x, n", cmd);
  1091.                 CDEBUG(D_PSDEV, "valid are 0x%Zx - 0x%Zx, 0x%Zx - 0x%Zx n",
  1092.                         PRESTO_GETMOUNT, PRESTO_GET_KMLSIZE,
  1093.                         PRESTO_VFS_SETATTR, PRESTO_VFS_IOPEN);
  1094.                 EXIT;
  1095.         }
  1096.         return -EINVAL;
  1097. }
  1098. static int presto_psdev_open(struct inode * inode, struct file * file)
  1099. {
  1100.          struct upc_comm *upccom;
  1101.          ENTRY;
  1102.          if ( ! (upccom = presto_psdev_f2u(file)) ) {
  1103.                  kdev_t dev = file->f_dentry->d_inode->i_rdev;
  1104.                  printk("InterMezzo: %s, bad device %sn",
  1105.                         __FUNCTION__, kdevname(dev));
  1106.                  EXIT;
  1107.                  return -EINVAL;
  1108.          }
  1109.         MOD_INC_USE_COUNT;
  1110.         CDEBUG(D_PSDEV, "Psdev_open: uc_pid: %d, caller: %d, flags: %dn",
  1111.                upccom->uc_pid, current->pid, file->f_flags);
  1112.         EXIT;
  1113.         return 0;
  1114. }
  1115. static int presto_psdev_release(struct inode * inode, struct file * file)
  1116. {
  1117.         struct upc_comm *upccom;
  1118.         struct upc_req *req;
  1119.         struct list_head *lh;
  1120.         ENTRY;
  1121.         if ( ! (upccom = presto_psdev_f2u(file)) ) {
  1122.                 kdev_t dev = file->f_dentry->d_inode->i_rdev;
  1123.                 printk("InterMezzo: %s, bad device %sn",
  1124.                        __FUNCTION__, kdevname(dev));
  1125.         }
  1126.         if ( upccom->uc_pid != current->pid ) {
  1127.                 printk("psdev_release: Not lento.n");
  1128.                 MOD_DEC_USE_COUNT;
  1129.                 return 0;
  1130.         }
  1131.         MOD_DEC_USE_COUNT;
  1132.         CDEBUG(D_PSDEV, "Lento: pid %dn", current->pid);
  1133.         upccom->uc_pid = 0;
  1134.         /* Wake up clients so they can return. */
  1135.         CDEBUG(D_PSDEV, "Wake up clients sleeping for pending.n");
  1136.         lh = &upccom->uc_pending;
  1137.         while ( (lh = lh->next) != &upccom->uc_pending) {
  1138.                 req = list_entry(lh, struct upc_req, rq_chain);
  1139.                 /* Async requests stay around for a new lento */
  1140.                 if (req->rq_flags & REQ_ASYNC) {
  1141.                         continue;
  1142.                 }
  1143.                 /* the sleeper will free the req and data */
  1144.                 req->rq_flags |= REQ_DEAD; 
  1145.                 wake_up(&req->rq_sleep);
  1146.         }
  1147.         CDEBUG(D_PSDEV, "Wake up clients sleeping for processingn");
  1148.         lh = &upccom->uc_processing;
  1149.         while ( (lh = lh->next) != &upccom->uc_processing) {
  1150.                 req = list_entry(lh, struct upc_req, rq_chain);
  1151.                 /* freeing of req and data is done by the sleeper */
  1152.                 req->rq_flags |= REQ_DEAD; 
  1153.                 wake_up(&req->rq_sleep);
  1154.         }
  1155.         CDEBUG(D_PSDEV, "Done.n");
  1156.         EXIT;
  1157.         return 0;
  1158. }
  1159. static struct file_operations presto_psdev_fops = {
  1160.         read:    presto_psdev_read,
  1161.         write:   presto_psdev_write,
  1162.         poll:    presto_psdev_poll,
  1163.         ioctl:   presto_psdev_ioctl,
  1164.         open:    presto_psdev_open,
  1165.         release: presto_psdev_release
  1166. };
  1167. int  presto_psdev_init(void)
  1168. {
  1169.         int i;
  1170. #ifdef PRESTO_DEVEL
  1171.         if (register_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev_devel",
  1172.                            &presto_psdev_fops)) {
  1173.                 printk(KERN_ERR "presto_psdev: unable to get major %dn",
  1174.                        PRESTO_PSDEV_MAJOR);
  1175.                 return -EIO;
  1176.         }
  1177. #else
  1178.         if (register_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev",
  1179.                            &presto_psdev_fops)) {
  1180.                 printk("presto_psdev: unable to get major %dn",
  1181.                        PRESTO_PSDEV_MAJOR);
  1182.                 return -EIO;
  1183.         }
  1184. #endif
  1185.         memset(&upc_comms, 0, sizeof(upc_comms));
  1186.         for ( i = 0 ; i < MAX_PRESTODEV ; i++ ) {
  1187.                 char *name;
  1188.                 struct upc_comm *psdev = &upc_comms[i];
  1189.                 INIT_LIST_HEAD(&psdev->uc_pending);
  1190.                 INIT_LIST_HEAD(&psdev->uc_processing);
  1191.                 INIT_LIST_HEAD(&psdev->uc_cache_list);
  1192.                 init_waitqueue_head(&psdev->uc_waitq);
  1193.                 psdev->uc_hard = 0;
  1194.                 psdev->uc_no_filter = 0;
  1195.                 psdev->uc_no_journal = 0;
  1196.                 psdev->uc_no_upcall = 0;
  1197.                 psdev->uc_timeout = 30;
  1198.                 psdev->uc_errorval = 0;
  1199.                 psdev->uc_minor = i;
  1200.                 PRESTO_ALLOC(name, char *, strlen(PRESTO_PSDEV_NAME "256")+1);
  1201.                 if (!name) { 
  1202.                         printk("Unable to allocate memory for device namen");
  1203.                         continue;
  1204.                 }
  1205.                 sprintf(name, PRESTO_PSDEV_NAME "%d", i); 
  1206.                 psdev->uc_devname = name;
  1207.         }
  1208.         return 0;
  1209. }
  1210. void presto_psdev_cleanup(void)
  1211. {
  1212.         int i;
  1213.         for ( i = 0 ; i < MAX_PRESTODEV ; i++ ) {
  1214.                 struct upc_comm *psdev = &upc_comms[i];
  1215.                 struct list_head *lh;
  1216.                 if ( ! list_empty(&psdev->uc_pending)) { 
  1217.                         printk("Weird, tell Peter: module cleanup and pending list not empty dev %dn", i);
  1218.                 }
  1219.                 if ( ! list_empty(&psdev->uc_processing)) { 
  1220.                         printk("Weird, tell Peter: module cleanup and processing list not empty dev %dn", i);
  1221.                 }
  1222.                 if ( ! list_empty(&psdev->uc_cache_list)) { 
  1223.                         printk("Weird, tell Peter: module cleanup and cache listnot empty dev %dn", i);
  1224.                 }
  1225.                 if (psdev->uc_devname) {
  1226.                         PRESTO_FREE(psdev->uc_devname,
  1227.                                     strlen(PRESTO_PSDEV_NAME "256")+1);
  1228.                 }
  1229.                 lh = psdev->uc_pending.next;
  1230.                 while ( lh != &psdev->uc_pending) {
  1231.                         struct upc_req *req;
  1232.                         req = list_entry(lh, struct upc_req, rq_chain);
  1233.                         lh = lh->next;
  1234.                         if ( req->rq_flags & REQ_ASYNC ) {
  1235.                                 list_del(&(req->rq_chain));
  1236.                                 CDEBUG(D_UPCALL, "free pending upcall type %dn",
  1237.                                        req->rq_opcode);
  1238.                                 PRESTO_FREE(req->rq_data, req->rq_bufsize);
  1239.                                 PRESTO_FREE(req, sizeof(struct upc_req));
  1240.                         } else {
  1241.                                 req->rq_flags |= REQ_DEAD; 
  1242.                                 wake_up(&req->rq_sleep);
  1243.                         }
  1244.                 }
  1245.                 lh = &psdev->uc_processing;
  1246.                 while ( (lh = lh->next) != &psdev->uc_processing ) {
  1247.                         struct upc_req *req;
  1248.                         req = list_entry(lh, struct upc_req, rq_chain);
  1249.                         list_del(&(req->rq_chain));
  1250.                         req->rq_flags |= REQ_DEAD; 
  1251.                         wake_up(&req->rq_sleep);
  1252.                 }
  1253.         }
  1254. }
  1255. /*
  1256.  * lento_upcall and lento_downcall routines
  1257.  */
  1258. static inline unsigned long lento_waitfor_upcall(struct upc_req *req,
  1259.                                                  int minor)
  1260. {
  1261.         DECLARE_WAITQUEUE(wait, current);
  1262.         unsigned long posttime;
  1263.         req->rq_posttime = posttime = jiffies;
  1264.         add_wait_queue(&req->rq_sleep, &wait);
  1265.         for (;;) {
  1266.                 if ( upc_comms[minor].uc_hard == 0 )
  1267.                         current->state = TASK_INTERRUPTIBLE;
  1268.                 else
  1269.                         current->state = TASK_UNINTERRUPTIBLE;
  1270.                 /* got a reply */
  1271.                 if ( req->rq_flags & (REQ_WRITE | REQ_DEAD) )
  1272.                         break;
  1273.                 if ( !upc_comms[minor].uc_hard && signal_pending(current) ) {
  1274.                         /* if this process really wants to die, let it go */
  1275.                         if (sigismember(&(current->pending.signal), SIGKILL)||
  1276.                             sigismember(&(current->pending.signal), SIGINT) )
  1277.                                 break;
  1278.                         /* signal is present: after timeout always return
  1279.                            really smart idea, probably useless ... */
  1280.                         if ( time_after(jiffies, req->rq_posttime +
  1281.                              upc_comms[minor].uc_timeout * HZ) )
  1282.                                 break;
  1283.                 }
  1284.                 schedule();
  1285.         }
  1286.       list_del(&req->rq_chain); 
  1287.       INIT_LIST_HEAD(&req->rq_chain); 
  1288.         remove_wait_queue(&req->rq_sleep, &wait);
  1289.         current->state = TASK_RUNNING;
  1290.         CDEBUG(D_SPECIAL, "posttime: %ld, returned: %ldn",
  1291.                posttime, jiffies-posttime);
  1292.         return  (jiffies - posttime);
  1293. }
  1294. /*
  1295.  * lento_upcall will return an error in the case of
  1296.  * failed communication with Lento _or_ will peek at Lento
  1297.  * reply and return Lento's error.
  1298.  *
  1299.  * As lento has 2 types of errors, normal errors (positive) and internal
  1300.  * errors (negative), normal errors are negated, while internal errors
  1301.  * are all mapped to -EINTR, while showing a nice warning message. (jh)
  1302.  *
  1303.  * lento_upcall will always free buffer, either directly, when an upcall
  1304.  * is read (in presto_psdev_read), when the filesystem is unmounted, or
  1305.  * when the module is unloaded.
  1306.  */
  1307. int lento_upcall(int minor, int bufsize, int *rep_size, union up_args *buffer,
  1308.                  int async, struct upc_req *rq)
  1309. {
  1310.         unsigned long runtime;
  1311.         struct upc_comm *upc_commp;
  1312.         union down_args *out;
  1313.         struct upc_req *req;
  1314.         int error = 0;
  1315.         ENTRY;
  1316.         upc_commp = &(upc_comms[minor]);
  1317.         if (upc_commp->uc_no_upcall) {
  1318.                 EXIT;
  1319.                 goto exit_buf;
  1320.         }
  1321.         if (!upc_commp->uc_pid && !async) {
  1322.                 EXIT;
  1323.                 error = -ENXIO;
  1324.                 goto exit_buf;
  1325.         }
  1326.         /* Format the request message. */
  1327.         CDEBUG(D_UPCALL, "buffer at %p, size %dn", buffer, bufsize);
  1328.         PRESTO_ALLOC(req, struct upc_req *, sizeof(struct upc_req));
  1329.         if ( !req ) {
  1330.                 EXIT;
  1331.                 error = -ENOMEM;
  1332.                 goto exit_buf;
  1333.         }
  1334.         req->rq_data = (void *)buffer;
  1335.         req->rq_flags = 0;
  1336.         req->rq_bufsize = bufsize;
  1337.         req->rq_rep_size = 0;
  1338.         req->rq_opcode = ((union up_args *)buffer)->uh.opcode;
  1339.         req->rq_unique = ++upc_commp->uc_seq;
  1340.         init_waitqueue_head(&req->rq_sleep);
  1341.         /* Fill in the common input args. */
  1342.         ((union up_args *)buffer)->uh.unique = req->rq_unique;
  1343.         /* Append msg to pending queue and poke Lento. */
  1344.         list_add(&req->rq_chain, upc_commp->uc_pending.prev);
  1345.         CDEBUG(D_UPCALL,
  1346.                "Proc %d waking Lento %d for(opc,uniq) =(%d,%d) msg at %p.n",
  1347.                current->pid, upc_commp->uc_pid, req->rq_opcode,
  1348.                req->rq_unique, req);
  1349.         wake_up_interruptible(&upc_commp->uc_waitq);
  1350.         if ( async ) {
  1351.                 req->rq_flags = REQ_ASYNC;
  1352.                 if( rq != NULL ) {
  1353.                         *rq = *req; /* struct copying */
  1354.                 }
  1355.                 /* req, rq_data are freed in presto_psdev_read for async */
  1356.                 EXIT;
  1357.                 return 0;
  1358.         }
  1359.         /* We can be interrupted while we wait for Lento to process
  1360.          * our request.  If the interrupt occurs before Lento has read
  1361.          * the request, we dequeue and return. If it occurs after the
  1362.          * read but before the reply, we dequeue, send a signal
  1363.          * message, and return. If it occurs after the reply we ignore
  1364.          * it. In no case do we want to restart the syscall.  If it
  1365.          * was interrupted by a lento shutdown (psdev_close), return
  1366.          * ENODEV.  */
  1367.         /* Go to sleep.  Wake up on signals only after the timeout. */
  1368.         runtime = lento_waitfor_upcall(req, minor);
  1369.         CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %dn",
  1370.                req->rq_opcode, jiffies - req->rq_posttime,
  1371.                req->rq_unique, req->rq_rep_size);
  1372.         CDEBUG(D_UPCALL,
  1373.                "..process %d woken up by Lento for req at 0x%p, data at %pn",
  1374.                current->pid, req, req->rq_data);
  1375.         if (upc_commp->uc_pid) {      /* i.e. Lento is still alive */
  1376.           /* Op went through, interrupt or not we go on */
  1377.             if (req->rq_flags & REQ_WRITE) {
  1378.                     out = (union down_args *)req->rq_data;
  1379.                     /* here we map positive Lento errors to kernel errors */
  1380.                     if ( out->dh.result < 0 ) {
  1381.                             printk("Tell Peter: Lento returns negative error %d, for oc %d!n",
  1382.                                    out->dh.result, out->dh.opcode);
  1383.                           out->dh.result = EINVAL;
  1384.                     }
  1385.                     error = -out->dh.result;
  1386.                     CDEBUG(D_UPCALL, "upcall: (u,o,r) (%d, %d, %d) out at %pn",
  1387.                            out->dh.unique, out->dh.opcode, out->dh.result, out);
  1388.                     *rep_size = req->rq_rep_size;
  1389.                     EXIT;
  1390.                     goto exit_req;
  1391.             }
  1392.             /* Interrupted before lento read it. */
  1393.             if ( !(req->rq_flags & REQ_READ) && signal_pending(current)) {
  1394.                     CDEBUG(D_UPCALL,
  1395.                            "Interrupt before read: (op,un)=(%d,%d), flags %xn",
  1396.                            req->rq_opcode, req->rq_unique, req->rq_flags);
  1397.                     /* perhaps the best way to convince the app to give up? */
  1398.                     error = -EINTR;
  1399.                     EXIT;
  1400.                     goto exit_req;
  1401.             }
  1402.             /* interrupted after Lento did its read, send signal */
  1403.             if ( (req->rq_flags & REQ_READ) && signal_pending(current) ) {
  1404.                     union up_args *sigargs;
  1405.                     struct upc_req *sigreq;
  1406.                     CDEBUG(D_UPCALL,"Sending for: op = %d.%d, flags = %xn",
  1407.                            req->rq_opcode, req->rq_unique, req->rq_flags);
  1408.                     error = -EINTR;
  1409.                     /* req, rq_data are freed in presto_psdev_read for async */
  1410.                     PRESTO_ALLOC(sigreq, struct upc_req *,
  1411.                                  sizeof (struct upc_req));
  1412.                     if (!sigreq) {
  1413.                             error = -ENOMEM;
  1414.                             EXIT;
  1415.                             goto exit_req;
  1416.                     }
  1417.                     PRESTO_ALLOC((sigreq->rq_data), char *,
  1418.                                  sizeof(struct lento_up_hdr));
  1419.                     if (!(sigreq->rq_data)) {
  1420.                             PRESTO_FREE(sigreq, sizeof (struct upc_req));
  1421.                             error = -ENOMEM;
  1422.                             EXIT;
  1423.                             goto exit_req;
  1424.                     }
  1425.                     sigargs = (union up_args *)sigreq->rq_data;
  1426.                     sigargs->uh.opcode = LENTO_SIGNAL;
  1427.                     sigargs->uh.unique = req->rq_unique;
  1428.                     sigreq->rq_flags = REQ_ASYNC;
  1429.                     sigreq->rq_opcode = sigargs->uh.opcode;
  1430.                     sigreq->rq_unique = sigargs->uh.unique;
  1431.                     sigreq->rq_bufsize = sizeof(struct lento_up_hdr);
  1432.                     sigreq->rq_rep_size = 0;
  1433.                     CDEBUG(D_UPCALL,
  1434.                            "presto_upcall: enqueing signal msg (%d, %d)n",
  1435.                            sigreq->rq_opcode, sigreq->rq_unique);
  1436.                     /* insert at head of queue! */
  1437.                     list_add(&sigreq->rq_chain, &upc_commp->uc_pending);
  1438.                     wake_up_interruptible(&upc_commp->uc_waitq);
  1439.             } else {
  1440.                   printk("Lento: Strange interruption - tell Peter.n");
  1441.                     error = -EINTR;
  1442.             }
  1443.         } else {        /* If lento died i.e. !UC_OPEN(upc_commp) */
  1444.                 printk("presto_upcall: Lento dead on (op,un) (%d.%d) flags %dn",
  1445.                        req->rq_opcode, req->rq_unique, req->rq_flags);
  1446.                 error = -ENODEV;
  1447.         }
  1448. exit_req:
  1449.         PRESTO_FREE(req, sizeof(struct upc_req));
  1450. exit_buf:
  1451.         PRESTO_FREE(buffer, bufsize);
  1452.         return error;
  1453. }