Subversion Repositories HelenOS

Rev

Rev 4587 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2009 Martin Decky
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup fs
  30.  * @{
  31.  */
  32.  
  33. /**
  34.  * @file devfs_ops.c
  35.  * @brief Implementation of VFS operations for the devfs file system server.
  36.  */
  37.  
  38. #include <ipc/ipc.h>
  39. #include <bool.h>
  40. #include <errno.h>
  41. #include <malloc.h>
  42. #include <string.h>
  43. #include <libfs.h>
  44. #include <fibril_sync.h>
  45. #include <adt/hash_table.h>
  46. #include <sys/stat.h>
  47. #include "devfs.h"
  48. #include "devfs_ops.h"
  49.  
  50. #define PLB_GET_CHAR(pos)  (devfs_reg.plb_ro[pos % PLB_SIZE])
  51.  
  52. /** Opened devices structure */
  53. typedef struct {
  54.     dev_handle_t handle;
  55.     int phone;
  56.     size_t refcount;
  57.     link_t link;
  58. } device_t;
  59.  
  60. /** Hash table of opened devices */
  61. static hash_table_t devices;
  62.  
  63. /** Hash table mutex */
  64. static FIBRIL_MUTEX_INITIALIZE(devices_mutex);
  65.  
  66. #define DEVICES_KEYS        1
  67. #define DEVICES_KEY_HANDLE  0
  68. #define DEVICES_BUCKETS     256
  69.  
  70. /* Implementation of hash table interface for the nodes hash table. */
  71. static hash_index_t devices_hash(unsigned long key[])
  72. {
  73.     return key[DEVICES_KEY_HANDLE] % DEVICES_BUCKETS;
  74. }
  75.  
  76. static int devices_compare(unsigned long key[], hash_count_t keys, link_t *item)
  77. {
  78.     device_t *dev = hash_table_get_instance(item, device_t, link);
  79.     return (dev->handle == (dev_handle_t) key[DEVICES_KEY_HANDLE]);
  80. }
  81.  
  82. static void devices_remove_callback(link_t *item)
  83. {
  84.     free(hash_table_get_instance(item, device_t, link));
  85. }
  86.  
  87. static hash_table_operations_t devices_ops = {
  88.     .hash = devices_hash,
  89.     .compare = devices_compare,
  90.     .remove_callback = devices_remove_callback
  91. };
  92.  
  93. bool devfs_init(void)
  94. {
  95.     if (!hash_table_create(&devices, DEVICES_BUCKETS,
  96.         DEVICES_KEYS, &devices_ops))
  97.         return false;
  98.    
  99.     if (devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING) < 0)
  100.         return false;
  101.    
  102.     return true;
  103. }
  104.  
  105. void devfs_mounted(ipc_callid_t rid, ipc_call_t *request)
  106. {
  107.     /* Accept the mount options */
  108.     ipc_callid_t callid;
  109.     size_t size;
  110.     if (!ipc_data_write_receive(&callid, &size)) {
  111.         ipc_answer_0(callid, EINVAL);
  112.         ipc_answer_0(rid, EINVAL);
  113.         return;
  114.     }
  115.    
  116.     char *opts = malloc(size + 1);
  117.     if (!opts) {
  118.         ipc_answer_0(callid, ENOMEM);
  119.         ipc_answer_0(rid, ENOMEM);
  120.         return;
  121.     }
  122.    
  123.     ipcarg_t retval = ipc_data_write_finalize(callid, opts, size);
  124.     if (retval != EOK) {
  125.         ipc_answer_0(rid, retval);
  126.         free(opts);
  127.         return;
  128.     }
  129.    
  130.     free(opts);
  131.    
  132.     ipc_answer_3(rid, EOK, 0, 0, 0);
  133. }
  134.  
  135. void devfs_mount(ipc_callid_t rid, ipc_call_t *request)
  136. {
  137.     ipc_answer_0(rid, ENOTSUP);
  138. }
  139.  
  140. void devfs_lookup(ipc_callid_t rid, ipc_call_t *request)
  141. {
  142.     ipcarg_t first = IPC_GET_ARG1(*request);
  143.     ipcarg_t last = IPC_GET_ARG2(*request);
  144.     dev_handle_t dev_handle = IPC_GET_ARG3(*request);
  145.     ipcarg_t lflag = IPC_GET_ARG4(*request);
  146.     fs_index_t index = IPC_GET_ARG5(*request);
  147.    
  148.     /* Hierarchy is flat, no altroot is supported */
  149.     if (index != 0) {
  150.         ipc_answer_0(rid, ENOENT);
  151.         return;
  152.     }
  153.    
  154.     if ((lflag & L_LINK) || (lflag & L_UNLINK)) {
  155.         ipc_answer_0(rid, ENOTSUP);
  156.         return;
  157.     }
  158.    
  159.     /* Eat slash */
  160.     if (PLB_GET_CHAR(first) == '/') {
  161.         first++;
  162.         first %= PLB_SIZE;
  163.     }
  164.    
  165.     if (first >= last) {
  166.         /* Root entry */
  167.         if (!(lflag & L_FILE))
  168.             ipc_answer_5(rid, EOK, devfs_reg.fs_handle, dev_handle, 0, 0, 0);
  169.         else
  170.             ipc_answer_0(rid, ENOENT);
  171.     } else {
  172.         if (!(lflag & L_DIRECTORY)) {
  173.             size_t len;
  174.             if (last >= first)
  175.                 len = last - first + 1;
  176.             else
  177.                 len = first + PLB_SIZE - last + 1;
  178.            
  179.             char *name = (char *) malloc(len + 1);
  180.             if (name == NULL) {
  181.                 ipc_answer_0(rid, ENOMEM);
  182.                 return;
  183.             }
  184.            
  185.             size_t i;
  186.             for (i = 0; i < len; i++)
  187.                 name[i] = PLB_GET_CHAR(first + i);
  188.            
  189.             name[len] = 0;
  190.            
  191.             dev_handle_t handle;
  192.             if (devmap_device_get_handle(name, &handle, 0) != EOK) {
  193.                 free(name);
  194.                 ipc_answer_0(rid, ENOENT);
  195.                 return;
  196.             }
  197.            
  198.             if (lflag & L_OPEN) {
  199.                 unsigned long key[] = {
  200.                     [DEVICES_KEY_HANDLE] = (unsigned long) handle
  201.                 };
  202.                
  203.                 fibril_mutex_lock(&devices_mutex);
  204.                 link_t *lnk = hash_table_find(&devices, key);
  205.                 if (lnk == NULL) {
  206.                     int phone = devmap_device_connect(handle, 0);
  207.                     if (phone < 0) {
  208.                         fibril_mutex_unlock(&devices_mutex);
  209.                         free(name);
  210.                         ipc_answer_0(rid, ENOENT);
  211.                         return;
  212.                     }
  213.                    
  214.                     device_t *dev = (device_t *) malloc(sizeof(device_t));
  215.                     if (dev == NULL) {
  216.                         fibril_mutex_unlock(&devices_mutex);
  217.                         free(name);
  218.                         ipc_answer_0(rid, ENOMEM);
  219.                         return;
  220.                     }
  221.                    
  222.                     dev->handle = handle;
  223.                     dev->phone = phone;
  224.                     dev->refcount = 1;
  225.                    
  226.                     hash_table_insert(&devices, key, &dev->link);
  227.                 } else {
  228.                     device_t *dev = hash_table_get_instance(lnk, device_t, link);
  229.                     dev->refcount++;
  230.                 }
  231.                 fibril_mutex_unlock(&devices_mutex);
  232.             }
  233.            
  234.             free(name);
  235.            
  236.             ipc_answer_5(rid, EOK, devfs_reg.fs_handle, dev_handle, handle, 0, 1);
  237.         } else
  238.             ipc_answer_0(rid, ENOENT);
  239.     }
  240. }
  241.  
  242. void devfs_open_node(ipc_callid_t rid, ipc_call_t *request)
  243. {
  244.     dev_handle_t handle = IPC_GET_ARG2(*request);
  245.    
  246.     unsigned long key[] = {
  247.         [DEVICES_KEY_HANDLE] = (unsigned long) handle
  248.     };
  249.    
  250.     fibril_mutex_lock(&devices_mutex);
  251.     link_t *lnk = hash_table_find(&devices, key);
  252.     if (lnk == NULL) {
  253.         int phone = devmap_device_connect(handle, 0);
  254.         if (phone < 0) {
  255.             fibril_mutex_unlock(&devices_mutex);
  256.             ipc_answer_0(rid, ENOENT);
  257.             return;
  258.         }
  259.        
  260.         device_t *dev = (device_t *) malloc(sizeof(device_t));
  261.         if (dev == NULL) {
  262.             fibril_mutex_unlock(&devices_mutex);
  263.             ipc_answer_0(rid, ENOMEM);
  264.             return;
  265.         }
  266.        
  267.         dev->handle = handle;
  268.         dev->phone = phone;
  269.         dev->refcount = 1;
  270.        
  271.         hash_table_insert(&devices, key, &dev->link);
  272.     } else {
  273.         device_t *dev = hash_table_get_instance(lnk, device_t, link);
  274.         dev->refcount++;
  275.     }
  276.     fibril_mutex_unlock(&devices_mutex);
  277.    
  278.     ipc_answer_3(rid, EOK, 0, 1, L_FILE);
  279. }
  280.  
  281. void devfs_stat(ipc_callid_t rid, ipc_call_t *request)
  282. {
  283.     dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
  284.     fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
  285.    
  286.     ipc_callid_t callid;
  287.     size_t size;
  288.     if (!ipc_data_read_receive(&callid, &size) ||
  289.         size < sizeof(struct stat)) {
  290.         ipc_answer_0(callid, EINVAL);
  291.         ipc_answer_0(rid, EINVAL);
  292.         return;
  293.     }
  294.  
  295.     struct stat *stat = malloc(sizeof(struct stat));
  296.     if (!stat) {
  297.         ipc_answer_0(callid, ENOMEM);
  298.         ipc_answer_0(rid, ENOMEM);
  299.         return;
  300.     }
  301.     memset(stat, 0, sizeof(struct stat));
  302.  
  303.     stat->fs_handle = devfs_reg.fs_handle;
  304.     stat->dev_handle = dev_handle;
  305.     stat->index = index;
  306.     stat->lnkcnt = 1;
  307.     stat->is_file = (index != 0);
  308.     stat->size = 0;
  309.    
  310.     if (index != 0) {
  311.         unsigned long key[] = {
  312.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  313.         };
  314.        
  315.         fibril_mutex_lock(&devices_mutex);
  316.         link_t *lnk = hash_table_find(&devices, key);
  317.         if (lnk != NULL)
  318.             stat->devfs_stat.device = (dev_handle_t)index;
  319.         fibril_mutex_unlock(&devices_mutex);
  320.     }
  321.  
  322.     ipc_data_read_finalize(callid, stat, sizeof(struct stat));
  323.     ipc_answer_0(rid, EOK);
  324.  
  325.     free(stat);
  326. }
  327.  
  328. void devfs_read(ipc_callid_t rid, ipc_call_t *request)
  329. {
  330.     fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
  331.     off_t pos = (off_t) IPC_GET_ARG3(*request);
  332.    
  333.     if (index != 0) {
  334.         unsigned long key[] = {
  335.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  336.         };
  337.        
  338.         fibril_mutex_lock(&devices_mutex);
  339.         link_t *lnk = hash_table_find(&devices, key);
  340.         if (lnk == NULL) {
  341.             fibril_mutex_unlock(&devices_mutex);
  342.             ipc_answer_0(rid, ENOENT);
  343.             return;
  344.         }
  345.        
  346.         device_t *dev = hash_table_get_instance(lnk, device_t, link);
  347.        
  348.         ipc_callid_t callid;
  349.         if (!ipc_data_read_receive(&callid, NULL)) {
  350.             fibril_mutex_unlock(&devices_mutex);
  351.             ipc_answer_0(callid, EINVAL);
  352.             ipc_answer_0(rid, EINVAL);
  353.             return;
  354.         }
  355.        
  356.         /* Make a request at the driver */
  357.         ipc_call_t answer;
  358.         aid_t msg = async_send_3(dev->phone, IPC_GET_METHOD(*request),
  359.             IPC_GET_ARG1(*request), IPC_GET_ARG2(*request),
  360.             IPC_GET_ARG3(*request), &answer);
  361.        
  362.         /* Forward the IPC_M_DATA_READ request to the driver */
  363.         ipc_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
  364.         fibril_mutex_unlock(&devices_mutex);
  365.        
  366.         /* Wait for reply from the driver. */
  367.         ipcarg_t rc;
  368.         async_wait_for(msg, &rc);
  369.         size_t bytes = IPC_GET_ARG1(answer);
  370.        
  371.         /* Driver reply is the final result of the whole operation */
  372.         ipc_answer_1(rid, rc, bytes);
  373.     } else {
  374.         ipc_callid_t callid;
  375.         size_t size;
  376.         if (!ipc_data_read_receive(&callid, &size)) {
  377.             ipc_answer_0(callid, EINVAL);
  378.             ipc_answer_0(rid, EINVAL);
  379.             return;
  380.         }
  381.        
  382.         size_t count = devmap_device_get_count();
  383.         dev_desc_t *desc = malloc(count * sizeof(dev_desc_t));
  384.         if (desc == NULL) {
  385.             ipc_answer_0(callid, ENOMEM);
  386.             ipc_answer_1(rid, ENOMEM, 0);
  387.             return;
  388.         }
  389.        
  390.         size_t max = devmap_device_get_devices(count, desc);
  391.        
  392.         if (pos < max) {
  393.             ipc_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
  394.         } else {
  395.             ipc_answer_0(callid, ENOENT);
  396.             ipc_answer_1(rid, ENOENT, 0);
  397.             return;
  398.         }
  399.        
  400.         free(desc);
  401.        
  402.         ipc_answer_1(rid, EOK, 1);
  403.     }
  404. }
  405.  
  406. void devfs_write(ipc_callid_t rid, ipc_call_t *request)
  407. {
  408.     fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
  409.     off_t pos = (off_t) IPC_GET_ARG3(*request);
  410.    
  411.     if (index != 0) {
  412.         unsigned long key[] = {
  413.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  414.         };
  415.        
  416.         fibril_mutex_lock(&devices_mutex);
  417.         link_t *lnk = hash_table_find(&devices, key);
  418.         if (lnk == NULL) {
  419.             fibril_mutex_unlock(&devices_mutex);
  420.             ipc_answer_0(rid, ENOENT);
  421.             return;
  422.         }
  423.        
  424.         device_t *dev = hash_table_get_instance(lnk, device_t, link);
  425.        
  426.         ipc_callid_t callid;
  427.         if (!ipc_data_write_receive(&callid, NULL)) {
  428.             fibril_mutex_unlock(&devices_mutex);
  429.             ipc_answer_0(callid, EINVAL);
  430.             ipc_answer_0(rid, EINVAL);
  431.             return;
  432.         }
  433.        
  434.         /* Make a request at the driver */
  435.         ipc_call_t answer;
  436.         aid_t msg = async_send_3(dev->phone, IPC_GET_METHOD(*request),
  437.             IPC_GET_ARG1(*request), IPC_GET_ARG2(*request),
  438.             IPC_GET_ARG3(*request), &answer);
  439.        
  440.         /* Forward the IPC_M_DATA_WRITE request to the driver */
  441.         ipc_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
  442.        
  443.         fibril_mutex_unlock(&devices_mutex);
  444.        
  445.         /* Wait for reply from the driver. */
  446.         ipcarg_t rc;
  447.         async_wait_for(msg, &rc);
  448.         size_t bytes = IPC_GET_ARG1(answer);
  449.        
  450.         /* Driver reply is the final result of the whole operation */
  451.         ipc_answer_1(rid, rc, bytes);
  452.     } else {
  453.         /* Read-only filesystem */
  454.         ipc_answer_0(rid, ENOTSUP);
  455.     }
  456. }
  457.  
  458. void devfs_truncate(ipc_callid_t rid, ipc_call_t *request)
  459. {
  460.     ipc_answer_0(rid, ENOTSUP);
  461. }
  462.  
  463. void devfs_close(ipc_callid_t rid, ipc_call_t *request)
  464. {
  465.     fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
  466.    
  467.     if (index != 0) {
  468.         unsigned long key[] = {
  469.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  470.         };
  471.        
  472.         fibril_mutex_lock(&devices_mutex);
  473.         link_t *lnk = hash_table_find(&devices, key);
  474.         if (lnk == NULL) {
  475.             fibril_mutex_unlock(&devices_mutex);
  476.             ipc_answer_0(rid, ENOENT);
  477.             return;
  478.         }
  479.        
  480.         device_t *dev = hash_table_get_instance(lnk, device_t, link);
  481.         dev->refcount--;
  482.        
  483.         if (dev->refcount == 0) {
  484.             ipc_hangup(dev->phone);
  485.             hash_table_remove(&devices, key, DEVICES_KEYS);
  486.         }
  487.        
  488.         fibril_mutex_unlock(&devices_mutex);
  489.        
  490.         ipc_answer_0(rid, EOK);
  491.     } else
  492.         ipc_answer_0(rid, ENOTSUP);
  493. }
  494.  
  495. void devfs_sync(ipc_callid_t rid, ipc_call_t *request)
  496. {
  497.     fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
  498.    
  499.     if (index != 0) {
  500.         unsigned long key[] = {
  501.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  502.         };
  503.        
  504.         fibril_mutex_lock(&devices_mutex);
  505.         link_t *lnk = hash_table_find(&devices, key);
  506.         if (lnk == NULL) {
  507.             fibril_mutex_unlock(&devices_mutex);
  508.             ipc_answer_0(rid, ENOENT);
  509.             return;
  510.         }
  511.        
  512.         device_t *dev = hash_table_get_instance(lnk, device_t, link);
  513.        
  514.         /* Make a request at the driver */
  515.         ipc_call_t answer;
  516.         aid_t msg = async_send_2(dev->phone, IPC_GET_METHOD(*request),
  517.             IPC_GET_ARG1(*request), IPC_GET_ARG2(*request), &answer);
  518.        
  519.         fibril_mutex_unlock(&devices_mutex);
  520.        
  521.         /* Wait for reply from the driver */
  522.         ipcarg_t rc;
  523.         async_wait_for(msg, &rc);
  524.        
  525.         /* Driver reply is the final result of the whole operation */
  526.         ipc_answer_0(rid, rc);
  527.     } else
  528.         ipc_answer_0(rid, ENOTSUP);
  529. }
  530.  
  531. void devfs_destroy(ipc_callid_t rid, ipc_call_t *request)
  532. {
  533.     ipc_answer_0(rid, ENOTSUP);
  534. }
  535.  
  536. /**
  537.  * @}
  538.  */
  539.