home *** CD-ROM | disk | FTP | other *** search
/ ftp.parl.clemson.edu / 2015-02-07.ftp.parl.clemson.edu.tar / ftp.parl.clemson.edu / pub / pvfs2 / orangefs-2.8.3-20110323.tar.gz / orangefs-2.8.3-20110323.tar / orangefs / src / io / dev / pint-dev.c < prev    next >
C/C++ Source or Header  |  2010-06-04  |  23KB  |  859 lines

  1. /*
  2.  * (C) 2001 Clemson University and The University of Chicago
  3.  *
  4.  * Changes by Acxiom Corporation to add protocol version to kernel
  5.  * communication, Copyright ⌐ Acxiom Corporation, 2005.
  6.  *
  7.  * See COPYING in top-level directory.
  8.  */
  9.  
  10. #include <stdlib.h>
  11. #include <unistd.h>
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <fcntl.h>
  15. #include <errno.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <inttypes.h>
  19. #include <sys/ioctl.h>
  20. #include <sys/poll.h>
  21. #include <sys/uio.h>
  22. #include <assert.h>
  23. #include <sys/mman.h>
  24.  
  25. #include "pint-mem.h"
  26. #include "pvfs2-types.h"
  27. #include "pvfs2-debug.h"
  28. #include "gossip.h"
  29. #include "pint-dev.h"
  30. #include "pvfs2-dev-proto.h"
  31. #include "pvfs2-internal.h"
  32.  
  33. #ifdef WITH_LINUX_KMOD
  34. static int setup_dev_entry(
  35.     const char *dev_name);
  36.  
  37. static int parse_devices(
  38.     const char *targetfile,
  39.     const char *devname, 
  40.     int *majornum);
  41. #endif  /* WITH_LINUX_KMOD */
  42.  
  43.  
  44. static int pdev_fd = -1;
  45. static int32_t pdev_magic;
  46. #ifdef WITH_LINUX_KMOD
  47. static int32_t pdev_max_upsize;
  48.  
  49. #endif  /* WITH_LINUX_KMOD */
  50. static int32_t pdev_max_downsize;
  51.  
  52. int32_t pvfs2_bufmap_total_size, pvfs2_bufmap_desc_size;
  53. int32_t pvfs2_bufmap_desc_count, pvfs2_bufmap_desc_shift;
  54.  
  55. /* PINT_dev_initialize()
  56.  *
  57.  * initializes the device management interface
  58.  *
  59.  * returns 0 on success, -PVFS_error on failure
  60.  */
  61. int PINT_dev_initialize(
  62.     const char *dev_name,
  63.     int flags)
  64. {
  65. #ifdef WITH_LINUX_KMOD
  66.     int ret = -1;
  67.     char *debug_string = getenv("PVFS2_KMODMASK");
  68.     uint64_t debug_mask = 0;
  69.     dev_mask_info_t mask_info;
  70.  
  71.     if (!debug_string)
  72.     {
  73.         debug_string = "none";
  74.     }
  75.  
  76.     /* we have to be root to access the device */
  77.     if ((getuid() != 0) && (geteuid() != 0))
  78.     {
  79.         gossip_err("Error: must be root to open pvfs2 device.\n");
  80.         return (-(PVFS_EPERM|PVFS_ERROR_DEV));
  81.     }
  82.  
  83.     /* setup /dev/ entry if needed */
  84.     ret = setup_dev_entry(dev_name);
  85.     if (ret < 0)
  86.     {
  87.         return (-(PVFS_ENODEV|PVFS_ERROR_DEV));
  88.     }
  89.  
  90.     /* try to open the device */
  91.     pdev_fd = open(dev_name, (O_RDWR | O_NONBLOCK));
  92.     if (pdev_fd < 0)
  93.     {
  94.         switch(errno)
  95.         {
  96.             case EACCES:
  97.                 return(-(PVFS_EPERM|PVFS_ERROR_DEV));
  98.             case ENOENT:
  99.                 return(-(PVFS_ENOENT|PVFS_ERROR_DEV));
  100.             default:
  101.                 return(-(PVFS_ENODEV|PVFS_ERROR_DEV));
  102.         }
  103.     }
  104.  
  105.     /* run some ioctls to find out device parameters */
  106.     ret = ioctl(pdev_fd, PVFS_DEV_GET_MAGIC, &pdev_magic);
  107.     if (ret < 0)
  108.     {
  109.         gossip_err("Error: ioctl() PVFS_DEV_GET_MAGIC failure.\n");
  110.         close(pdev_fd);
  111.         return(-(PVFS_ENODEV|PVFS_ERROR_DEV));
  112.     }
  113.  
  114.     ret = ioctl(pdev_fd, PVFS_DEV_GET_MAX_UPSIZE, &pdev_max_upsize);
  115.     if (ret < 0)
  116.     {
  117.         gossip_err("Error: ioctl() PVFS_DEV_GET_MAX_UPSIZE failure.\n");
  118.         close(pdev_fd);
  119.         return(-(PVFS_ENODEV|PVFS_ERROR_DEV));
  120.     }
  121.  
  122.     ret = ioctl(pdev_fd, PVFS_DEV_GET_MAX_DOWNSIZE, &pdev_max_downsize);
  123.     if (ret < 0)
  124.     {
  125.         gossip_err("Error: ioctl() PVFS_DEV_GET_MAX_DOWNSIZE failure.\n");
  126.         close(pdev_fd);
  127.         return(-(PVFS_ENODEV|PVFS_ERROR_DEV));
  128.     }
  129.  
  130.     /* push the kernel debug mask into the kernel, set gossip_debug_mask in the
  131.      * kernel and initialize the kernel debug string used by 
  132.      * /proc/sys/pvfs2/kernel-debug.
  133.     */
  134.     mask_info.mask_type  = KERNEL_MASK;
  135.     mask_info.mask_value = PVFS_kmod_eventlog_to_mask(debug_string);
  136.     ret = ioctl(pdev_fd, PVFS_DEV_DEBUG, &mask_info);
  137.     if (ret < 0)
  138.     {
  139.         gossip_err("Error: ioctl() PVFS_DEV_DEBUG failure (kernel debug mask to"
  140.                    " %x)\n"
  141.                   ,(unsigned int)debug_mask);
  142.         close(pdev_fd);
  143.         return -(PVFS_ENODEV|PVFS_ERROR_DEV);
  144.     }
  145.  
  146.     /* push the client debug mask into the kernel and initialize the client 
  147.      * debug string used by /proc/sys/pvfs2/client-debug.  
  148.     */
  149.     mask_info.mask_type  = CLIENT_MASK;
  150.     mask_info.mask_value = gossip_debug_mask;
  151.     ret = ioctl(pdev_fd, PVFS_DEV_DEBUG, &mask_info);
  152.     if (ret < 0)
  153.     {
  154.         gossip_err("Error: ioctl() PVFS_DEV_DEBUG failure (client debug mask to"
  155.                    " %x)\n"
  156.                   ,(unsigned int)gossip_debug_mask);
  157.         close(pdev_fd);
  158.         return -(PVFS_ENODEV|PVFS_ERROR_DEV);
  159.     }
  160. #endif  /* WITH_LINUX_KMOD */
  161.     return 0;
  162. }
  163.  
  164. /* PINT_dev_finalize()
  165.  *
  166.  * shuts down the device management interface
  167.  *
  168.  * no return value
  169.  */
  170. void PINT_dev_finalize(void)
  171. {
  172.     if (pdev_fd > -1)
  173.     {
  174.         close(pdev_fd);
  175.         pdev_fd = -1;
  176.     }
  177. }
  178.  
  179. /* PINT_dev_get_mapped_regions()
  180.  *
  181.  * creates a set of memory buffers that are shared between user space and 
  182.  * kernel space
  183.  *
  184.  * returns 0 on success, -PVFS_error on failure
  185.  */
  186. int PINT_dev_get_mapped_regions(int ndesc, struct PVFS_dev_map_desc *desc,
  187.                                 struct PINT_dev_params *params)
  188. {
  189. #ifdef WITH_LINUX_KMOD
  190.     int i, ret = -1;
  191.     uint64_t page_size = sysconf(_SC_PAGE_SIZE), total_size;
  192.     void *ptr = NULL;
  193.     int ioctl_cmd[2] = {PVFS_DEV_MAP, 0};
  194.     int debug_on = 0;
  195.     uint64_t debug_mask = 0;
  196.  
  197.     for (i = 0; i < ndesc; i++)
  198.     {
  199.         total_size = params[i].dev_buffer_size * params[i].dev_buffer_count;
  200.         if (total_size < 0) 
  201.         {
  202.             gossip_err("Error:please provide sane values for device parameters.\n");
  203.             break;
  204.         }
  205.         if (total_size % page_size != 0) 
  206.         {
  207.             gossip_err("Error: total device buffer size must be a multiple of system page size.\n");
  208.             break;
  209.         }
  210.         if (total_size >= PVFS2_BUFMAP_MAX_TOTAL_SIZE)
  211.         {
  212.             gossip_err(
  213.                 "Error: total size (%llu) of device "
  214.                 "buffer must be < %llu MB.\n",
  215.                 llu(total_size), llu(PVFS2_BUFMAP_MAX_TOTAL_SIZE));
  216.             break;
  217.         }
  218.         if (params[i].dev_buffer_size & (params[i].dev_buffer_size - 1))
  219.         {
  220.             gossip_err("Error: descriptor size must be a power of 2 (%llu)\n",
  221.                         llu(params[i].dev_buffer_size));
  222.             break;
  223.         }
  224.         /* we would like to use a memaligned region that is a multiple
  225.          * of the system page size
  226.          */
  227.         ptr = PINT_mem_aligned_alloc(total_size, page_size);
  228.         if (!ptr)
  229.         {
  230.             desc[i].ptr = NULL;
  231.             break;
  232.         }
  233.  
  234. #ifdef REDHAT_RELEASE_9
  235.         /* fixes a corruption issue on linux 2.4 kernels where the buffers are
  236.          * not being pinned in memory properly 
  237.          */
  238.         if(mlock( (const char *) ptr, total_size) != 0)
  239.         { 
  240.            gossip_err("Error: FAILED to mlock shared buffer\n");
  241.            break;
  242.         }
  243. #endif
  244.         desc[i].ptr  = ptr;
  245.         desc[i].total_size = total_size;
  246.         desc[i].size = params[i].dev_buffer_size;
  247.         desc[i].count = params[i].dev_buffer_count;
  248.  
  249.         gossip_get_debug_mask(&debug_on, &debug_mask);
  250.         gossip_set_debug_mask(1, GOSSIP_USER_DEV_DEBUG);
  251.         gossip_debug(GOSSIP_USER_DEV_DEBUG,
  252.             "[INFO]: Mapping pointer %p for I/O.\n", ptr);
  253.         gossip_set_debug_mask(debug_on, debug_mask);
  254.  
  255.         /* ioctl to ask driver to map pages if needed */
  256.         if (ioctl_cmd[i] != 0)
  257.         {
  258.             ret = ioctl(pdev_fd, ioctl_cmd[i], &desc[i]);
  259.             if (ret < 0)
  260.             {
  261.                 break;
  262.             }
  263.             pvfs2_bufmap_desc_count = params[i].dev_buffer_count;
  264.             pvfs2_bufmap_desc_size  = params[i].dev_buffer_size;
  265.             pvfs2_bufmap_total_size = total_size;
  266.             pvfs2_bufmap_desc_shift = LOG2(pvfs2_bufmap_desc_size);
  267.         }
  268.     }
  269.     if (i != ndesc) {
  270.         int j;
  271.         for (j = 0; j < i; j++) {
  272.             if (desc[j].ptr) {
  273.                 PINT_mem_aligned_free(desc[j].ptr);
  274.                 desc[j].ptr = NULL;
  275.             }
  276.         }
  277.         return -(PVFS_ENOMEM|PVFS_ERROR_DEV);
  278.     }
  279. #endif  /* WITH_LINUX_KMOD */
  280.     return 0;
  281. }
  282.  
  283. /* PINT_dev_put_mapped_regions()
  284.  *
  285.  * frees the set of memory buffers that were shared between user space and
  286.  * kernel space.  MUST be called only after device is closed
  287.  * (i.e. PINT_dev_finalize)
  288.  */
  289. void PINT_dev_put_mapped_regions(int ndesc, struct PVFS_dev_map_desc *desc)
  290. {
  291.     void *ptr;
  292.     int i;
  293.     
  294.     assert(desc);
  295.  
  296.     for (i = 0; i < ndesc; i++)
  297.     {
  298.         ptr = (void *) desc[i].ptr;
  299.         assert(ptr);
  300.  
  301. #ifdef REDHAT_RELEASE_9
  302.         /* fixes a corruption issue on linux 2.4 kernels where the buffers are
  303.          * not being pinned in memory properly
  304.          */
  305.         if(munlock( (const char *) ptr, desc[i].total_size) != 0)
  306.         { 
  307.            gossip_err("Error: FAILED to munlock shared buffer\n");
  308.         }
  309. #endif
  310.  
  311.         PINT_mem_aligned_free(ptr);
  312.     }
  313. }
  314.  
  315. /* PINT_dev_get_mapped_buffer()
  316.  *
  317.  * returns a memory buffer of size (pvfs2_bufmap_desc_size)
  318.  * matching the specified buffer_index given a PVFS_dev_map_desc
  319.  *
  320.  * returns a valid desc addr on success, NULL on failure
  321.  */
  322. void *PINT_dev_get_mapped_buffer(
  323.     enum pvfs_bufmap_type bm_type,
  324.     struct PVFS_dev_map_desc *desc,
  325.     int buffer_index)
  326. {
  327.     char *ptr;
  328.     int desc_count, desc_size;
  329.  
  330.     if (bm_type != BM_IO && bm_type != BM_READDIR)
  331.         return NULL;
  332.  
  333.     desc_count = (bm_type == BM_IO) ? 
  334.                 pvfs2_bufmap_desc_count :
  335.                 PVFS2_READDIR_DEFAULT_DESC_COUNT;
  336.     desc_size  = (bm_type == BM_IO) ? 
  337.                 pvfs2_bufmap_desc_size : 
  338.                 PVFS2_READDIR_DEFAULT_DESC_SIZE;
  339.     ptr =  (char *) desc[bm_type].ptr;
  340.     return ((desc && ptr &&
  341.              ((buffer_index > -1) &&
  342.               (buffer_index < desc_count))) ?
  343.             (ptr + (buffer_index * desc_size)) :
  344.             NULL);
  345. }
  346.  
  347. /* PINT_dev_test_unexpected()
  348.  *
  349.  * tests for the presence of unexpected messages
  350.  *
  351.  * returns number of completed unexpected messages on success,
  352.  * -PVFS_error on failure
  353.  */
  354. int PINT_dev_test_unexpected(
  355.         int incount,
  356.         int *outcount,
  357.         struct PINT_dev_unexp_info *info_array,
  358.         int max_idle_time)
  359. {
  360.     int ret = -1;
  361. #ifdef WITH_LINUX_KMOD
  362.     int avail = -1, i = 0;
  363.     struct pollfd pfd;
  364.     int32_t *magic = NULL;
  365.     int32_t *proto_ver = NULL;
  366.     uint64_t *tag = NULL;
  367.     void *buffer = NULL;
  368.     pvfs2_upcall_t *upc = NULL;
  369.  
  370.     if(incount < 1)
  371.     {
  372.         return(-PVFS_EINVAL);
  373.     }
  374.  
  375.     /* prepare to read max upcall size (magic nr and tag included) */
  376.     int read_size = pdev_max_upsize;
  377.     
  378.     *outcount = 0;
  379.  
  380.     pfd.fd = pdev_fd;
  381.     pfd.events = POLLIN;
  382.  
  383.     gossip_debug(GOSSIP_USER_DEV_DEBUG, 
  384.                  "[DEV]: Entered %s: incount: %d, timeout: %d\n",
  385.                  __func__, incount, max_idle_time);
  386.  
  387.     do
  388.     {
  389.         /*
  390.           poll to see if there is anything available on the device if
  391.           we were given a max_idle_time.  if the max_idle_time is 0,
  392.           skip the poll call and immediately try to read the device
  393.         */
  394.         if (max_idle_time)
  395.         {
  396.             do
  397.             {
  398.                 pfd.revents = 0;
  399.                 avail = poll(&pfd, 1, max_idle_time);
  400.  
  401.             } while((avail < 0) && (errno == EINTR));
  402.  
  403.             if (avail < 0)
  404.             {
  405.                 switch(errno)
  406.                 {
  407.                     case EBADF:
  408.                         ret = -(PVFS_EBADF|PVFS_ERROR_DEV);
  409.                     case ENOMEM:
  410.                         ret = -(PVFS_ENOMEM|PVFS_ERROR_DEV);
  411.                     case EFAULT:
  412.                         ret = -(PVFS_EFAULT|PVFS_ERROR_DEV);
  413.                     default:
  414.                         ret = -(PVFS_EIO|PVFS_ERROR_DEV);
  415.                 }
  416.                 goto dev_test_unexp_error;
  417.             }
  418.  
  419.             /* device is emptied */
  420.             if (avail == 0)
  421.             {
  422.                 gossip_debug(GOSSIP_USER_DEV_DEBUG,
  423.                              "[DEV]: Exiting %s: incount: %d, device empty!\n",
  424.                              __func__, incount);
  425.                 return ((*outcount > 0) ? 1 : 0);
  426.             }
  427.  
  428.             if (!(pfd.revents & POLLIN))
  429.             {
  430.                 if (pfd.revents & POLLNVAL)
  431.                 {
  432.                     return -(PVFS_EBADF|PVFS_ERROR_DEV);
  433.                 }
  434.                 continue;
  435.             }
  436.  
  437.             /*
  438.               once we have data to read, set the idle time to zero
  439.               because we don't want to block on subsequent iterations
  440.             */
  441.             max_idle_time = 0;
  442.         }
  443.  
  444.         /* prepare to read max upcall size, plus magic nr and tag */
  445.         buffer = malloc(read_size);
  446.         if (buffer == NULL)
  447.         {
  448.             ret = -(PVFS_ENOMEM|PVFS_ERROR_DEV);
  449.             goto dev_test_unexp_error;
  450.         }
  451.  
  452.         ret = read(pdev_fd, buffer, read_size);
  453.         if (ret < 0)
  454.         {
  455.             /*
  456.               EAGAIN is an error we can ignore in non-blocking mode;
  457.               it just means that the device is emptied
  458.             */
  459.             if (errno == EAGAIN)
  460.             {
  461.                 goto safe_exit;
  462.             }
  463.             ret = -(PVFS_EIO|PVFS_ERROR_DEV);
  464.             goto dev_test_unexp_error;
  465.         }
  466.  
  467.         if (ret == 0)
  468.         {   
  469.             /* assume we are done and return */
  470.           safe_exit:
  471.             free(buffer);
  472.             gossip_debug(GOSSIP_USER_DEV_DEBUG,
  473.                          "[DEV]: %s Exit: "
  474.                          "incount: %d, outcount: %d, bytes available: %d\n",
  475.                          __func__, incount, *outcount, avail);
  476.  
  477.             return ((*outcount > 0) ? 1 : 0);
  478.         }
  479.  
  480.         /* make sure a payload is present */
  481.         if (ret < (sizeof(int32_t) + sizeof(uint64_t) + 1))
  482.         {
  483.             gossip_err("Error: short message from device "
  484.                        "(got %d bytes).\n", ret);
  485.  
  486.             ret = -(PVFS_EIO|PVFS_ERROR_DEV);
  487.             goto dev_test_unexp_error;
  488.         }
  489.  
  490.         proto_ver = (int32_t*)buffer;
  491.         magic = (int32_t*)((unsigned long)buffer + sizeof(int32_t));
  492.         tag = (uint64_t*)((unsigned long)buffer + 2*sizeof(int32_t));
  493.  
  494.         if(*magic != pdev_magic)
  495.         {
  496.             gossip_err("Error: magic numbers do not match.\n");
  497.             ret = -(PVFS_EPROTO|PVFS_ERROR_DEV);
  498.             goto dev_test_unexp_error;
  499.         }
  500.         if(*proto_ver != PVFS_KERNEL_PROTO_VERSION)
  501.         {
  502.             gossip_err("Error: protocol versions do not match.\n");
  503.             gossip_err("Please check that your pvfs2 module "
  504.                        "and pvfs2-client versions are consistent.\n");
  505.             ret = -(PVFS_EPROTO|PVFS_ERROR_DEV);
  506.             goto dev_test_unexp_error;
  507.         }
  508.  
  509.         info_array[*outcount].size =
  510.             (ret - 2*sizeof(int32_t) - sizeof(uint64_t));
  511.  
  512.         /* shift buffer up so caller doesn't see header info */
  513.         info_array[*outcount].buffer = (void*)
  514.             ((unsigned long)buffer + 2*sizeof(int32_t) + sizeof(uint64_t));
  515.         info_array[*outcount].tag = *tag;
  516.  
  517.         upc = (pvfs2_upcall_t *) info_array[*outcount].buffer;
  518.         /* if there is a trailer, allocate a buffer and issue another read */
  519.         if (upc->trailer_size > 0)
  520.         {
  521.             upc->trailer_buf = malloc(upc->trailer_size);
  522.             if (upc->trailer_buf == NULL)
  523.             {
  524.                 ret = -(PVFS_ENOMEM|PVFS_ERROR_DEV);
  525.                 goto dev_test_unexp_error;
  526.             }
  527.             ret = read(pdev_fd, upc->trailer_buf, upc->trailer_size);
  528.             if (ret < 0)
  529.             {
  530.                 ret = -(PVFS_EIO|PVFS_ERROR_DEV);
  531.                 goto dev_test_unexp_error;
  532.             }
  533.         }
  534.  
  535.         (*outcount)++;
  536.  
  537.         /*
  538.           keep going until we fill up the outcount or the device
  539.           empties
  540.         */
  541.  
  542.     } while((*outcount < incount) && avail);
  543.  
  544.     gossip_debug(GOSSIP_USER_DEV_DEBUG,
  545.                  "[DEV]: %s Exit: "
  546.                  "incount: %d, outcount: %d, bytes available: %d\n",
  547.                  __func__, incount, *outcount, avail);
  548.  
  549.     return ((*outcount > 0) ? 1 : 0);
  550.  
  551. dev_test_unexp_error:
  552.  
  553.     /* release resources we created up to this point */
  554.     for(i = 0; i < *outcount; i++)
  555.     {
  556.         upc = (pvfs2_upcall_t *) info_array[i].buffer;
  557.         if (upc->trailer_buf)
  558.         {
  559.             free(upc->trailer_buf);
  560.         }
  561.         if (buffer)
  562.         {
  563.             free(buffer);
  564.         }
  565.     }
  566.  
  567.     *outcount = 0;
  568. #endif  /* WITH_LINUX_KMOD */
  569.     return ret;
  570. }
  571.  
  572. /* PINT_dev_release_unexpected()
  573.  *
  574.  * releases the resources associated with an unexpected device message
  575.  *
  576.  * returns 0 on success, -PVFS_error on failure
  577.  */
  578. int PINT_dev_release_unexpected(
  579.         struct PINT_dev_unexp_info *info)
  580. {
  581.     int ret = -PVFS_EINVAL;
  582.     void *buffer = NULL;
  583.  
  584.     if (info && info->buffer)
  585.     {
  586.         /* index backwards header size off of the buffer before freeing */
  587.         buffer = (void*)((unsigned long)info->buffer - 2*sizeof(int32_t) - 
  588.                          sizeof(uint64_t));
  589.         free(buffer);
  590.  
  591.         ret = 0;
  592.     }
  593.  
  594.     memset(info, 0, sizeof(struct PINT_dev_unexp_info));
  595.     return ret;
  596. }
  597.  
  598. /* PINT_dev_write_list()
  599.  *
  600.  * writes a set of buffers into the device
  601.  *
  602.  * returns 0 on success, -PVFS_error on failure
  603.  */
  604. int PINT_dev_write_list(
  605.     void **buffer_list,
  606.     int *size_list,
  607.     int list_count,
  608.     int total_size,
  609.     enum PINT_dev_buffer_type buffer_type,
  610.     PVFS_id_gen_t tag)
  611. {
  612.     struct iovec io_array[8];
  613.     int io_count = 3;
  614.     int i;
  615.     int ret = -1;
  616.     int32_t proto_ver = PVFS_KERNEL_PROTO_VERSION;
  617.     
  618.     /* lets be reasonable about list size :) */
  619.     /* two vecs are taken up by magic nr and tag */
  620.     if (list_count > 7)
  621.     {
  622.         return (-(PVFS_EINVAL|PVFS_ERROR_DEV));
  623.     }
  624.  
  625.     /* even though we are ignoring the buffer_type for now, 
  626.      * make sure that the caller set it to a sane value 
  627.      */
  628.     if (buffer_type != PINT_DEV_EXT_ALLOC &&
  629.         buffer_type != PINT_DEV_PRE_ALLOC)
  630.     {
  631.         return (-(PVFS_EINVAL|PVFS_ERROR_DEV));
  632.     }
  633.  
  634.     if (size_list[0] > pdev_max_downsize)
  635.     {
  636.         return(-(PVFS_EMSGSIZE|PVFS_ERROR_DEV));
  637.     }
  638.  
  639.     io_array[0].iov_base = &proto_ver;
  640.     io_array[0].iov_len = sizeof(int32_t);
  641.     io_array[1].iov_base = &pdev_magic;
  642.     io_array[1].iov_len = sizeof(int32_t);
  643.     io_array[2].iov_base = &tag;
  644.     io_array[2].iov_len = sizeof(uint64_t);
  645.  
  646.     for (i=0; i<list_count; i++)
  647.     {
  648.         io_array[i+3].iov_base = buffer_list[i];
  649.         io_array[i+3].iov_len = size_list[i];
  650.         io_count++;
  651.     }
  652.  
  653.     ret = writev(pdev_fd, io_array, io_count);
  654.  
  655.     return ((ret < 0) ? -(PVFS_EIO|PVFS_ERROR_DEV) : 0);
  656. }
  657.  
  658. /* PINT_dev_remount()
  659.  *
  660.  * asks the kernel to re-issues upcall mount operations to refill the
  661.  * dynamic mount information to the pvfs2-client-core
  662.  *
  663.  * returns 0 on success, -PVFS_error on failure
  664.  */
  665. int PINT_dev_remount(void)
  666. {
  667.     int ret = -PVFS_EINVAL;
  668.  
  669. #ifdef WITH_LINUX_KMOD
  670.     if (pdev_fd > -1)
  671.     {
  672.         ret = ((ioctl(pdev_fd, PVFS_DEV_REMOUNT_ALL, NULL) < 0) ?
  673.                -PVFS_ERROR_DEV : 0);
  674.         if (ret)
  675.         {
  676.             gossip_err("Error: ioctl PVFS_DEV_REMOUNT_ALL failure\n");
  677.         }
  678.     }
  679. #endif  /* WITH_LINUX_KMOD */
  680.     return ret;
  681. }
  682.  
  683. /* PINT_dev_write()
  684.  *
  685.  * writes a buffer into the device
  686.  *
  687.  * returns 0 on success, -PVFS_error on failure
  688.  */
  689. int PINT_dev_write(void *buffer,
  690.                    int size,
  691.                    enum PINT_dev_buffer_type buffer_type,
  692.                    PVFS_id_gen_t tag)
  693. {
  694.     return PINT_dev_write_list(
  695.         &buffer, &size, 1, size, buffer_type, tag);
  696. }
  697.  
  698. /* PINT_dev_memalloc()
  699.  *
  700.  * allocates a memory buffer optimized for transfer into the device
  701.  *
  702.  * returns pointer to buffer on success, NULL on failure
  703.  */
  704. void *PINT_dev_memalloc(int size)
  705. {
  706.     /* no optimizations yet */
  707.     return malloc(size);
  708. }
  709.  
  710. /* PINT_dev_memfree()
  711.  *
  712.  * frees a memory buffer that was allocated with PINT_dev_memalloc()
  713.  *
  714.  * no return value
  715.  */
  716. void PINT_dev_memfree(void *buffer, int size)
  717. {
  718.     free(buffer);
  719. }
  720.  
  721. #ifdef WITH_LINUX_KMOD
  722. /* setup_dev_entry()
  723.  *
  724.  * sets up the device file
  725.  *
  726.  * returns 0 on success, -1 on failure
  727.  */
  728. static int setup_dev_entry(const char *dev_name)
  729. {
  730.     int majornum = -1;
  731.     int ret = -1;
  732.     struct stat dev_stat;
  733.  
  734.     ret = parse_devices("/proc/devices", "pvfs2-req", &majornum);
  735.     if (ret < 0)
  736.     {
  737.         gossip_err("Error: unable to parse device file.\n");
  738.         return -1;
  739.     }
  740.  
  741.     if (majornum == -1)
  742.     {
  743.         gossip_err("Error: could not setup device %s.\n", dev_name);
  744.         gossip_err("Error: did you remember to load the kernel module?\n");
  745.         return -1;
  746.     }
  747.  
  748.     if (!access(dev_name, F_OK))
  749.     {
  750.         /* device file already exists */
  751.         ret = stat(dev_name, &dev_stat);
  752.         if (ret != 0)
  753.         {
  754.             gossip_err("Error: could not stat %s.\n", dev_name);
  755.             return -1;
  756.         }
  757.  
  758.         if (S_ISCHR(dev_stat.st_mode) &&
  759.             (major(dev_stat.st_rdev) == majornum))
  760.         {
  761.             /*
  762.               the device file already has the correct major number;
  763.               we're done
  764.             */
  765.             return 0;
  766.         }
  767.         else
  768.         {
  769.             /* the device file is incorrect; unlink it */
  770.             ret = unlink(dev_name);
  771.             if (ret != 0)
  772.             {
  773.                 gossip_err("Error: could not unlink old %s\n", dev_name);
  774.                 return -1;
  775.             }
  776.         }
  777.     }
  778.  
  779.     /* if we hit this point, then we need to create a new device file */
  780.     ret = mknod(dev_name, (S_IFCHR | S_IRUSR | S_IWUSR),
  781.                 makedev(majornum, 0));
  782.     if (ret != 0)
  783.     {
  784.         gossip_err("Error: could not create new %s device entry.\n",
  785.                    dev_name);
  786.     }
  787.     return ret;
  788. }
  789.  
  790. /* parse_devices()
  791.  *
  792.  * parses a file in the /proc/devices format looking for an entry for
  793.  * the given "devname".  If found, "majornum" is filled in with the
  794.  * major number of the device.  Else "majornum" is set to -1.
  795.  *
  796.  * returns 0 on successs, -1 on failure
  797.  */
  798. static int parse_devices(
  799.     const char *targetfile,
  800.     const char *devname, 
  801.     int *majornum)
  802. {
  803.     char line_buf[256];
  804.     char dev_buf[256];
  805.     int major_buf = -1;
  806.     FILE *devfile = NULL;
  807.     int ret = -1;
  808.  
  809.     /* initialize for safety */
  810.     *majornum = -1;
  811.  
  812.     /* open up the file to parse */
  813.     devfile = fopen(targetfile, "r");
  814.     if (!devfile)
  815.     {
  816.         gossip_err("Error: could not open %s.\n", targetfile);
  817.         return -1;
  818.     }
  819.  
  820.     /* scan every line until we get a match or end of file */
  821.     while (fgets(line_buf, sizeof(line_buf), devfile))
  822.     {
  823.         /*
  824.           sscanf is safe here as long as the target string is at least
  825.           as large as the source
  826.         */
  827.         ret = sscanf(line_buf, " %d %s ", &major_buf, dev_buf);
  828.         if (ret == 2)
  829.         {
  830.             /*
  831.               this line is the correct format; see if it matches the
  832.               devname
  833.             */
  834.             if (strncmp(devname, dev_buf, sizeof(dev_buf)) == 0)
  835.             {
  836.                 *majornum = major_buf;
  837.                 
  838.                 /*
  839.                   don't break out; it doesn't cost much to scan the
  840.                   whole thing, and we want the last entry if
  841.                   somehow(?)  there are two
  842.                 */
  843.             }
  844.         }
  845.     }
  846.     fclose(devfile);
  847.     return 0;
  848. }
  849. #endif  /* WITH_LINUX_KMOD */
  850.  
  851. /*
  852.  * Local variables:
  853.  *  c-indent-level: 4
  854.  *  c-basic-offset: 4
  855.  * End:
  856.  *
  857.  * vim: ts=8 sts=4 sw=4 expandtab
  858.  */
  859.