Subversion Repositories HelenOS

Rev

Rev 4581 | 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;
  296.     memset(&stat, 0, sizeof(struct stat));
  297.  
  298.     stat.fs_handle = devfs_reg.fs_handle;
  299.     stat.dev_handle = dev_handle;
  300.     stat.index = index;
  301.     stat.lnkcnt = 1;
  302.     stat.is_file = (index != 0);
  303.     stat.size = 0;
  304.    
  305.     if (index != 0) {
  306.         unsigned long key[] = {
  307.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  308.         };
  309.        
  310.         fibril_mutex_lock(&devices_mutex);
  311.         link_t *lnk = hash_table_find(&devices, key);
  312.         if (lnk != NULL)
  313.             stat.devfs_stat.device = (dev_handle_t)index;
  314.         fibril_mutex_unlock(&devices_mutex);
  315.     }
  316.  
  317.     ipc_data_read_finalize(callid, &stat, sizeof(struct stat));
  318.     ipc_answer_0(rid, EOK);
  319. }
  320.  
  321. void devfs_read(ipc_callid_t rid, ipc_call_t *request)
  322. {
  323.     fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
  324.     off_t pos = (off_t) IPC_GET_ARG3(*request);
  325.    
  326.     if (index != 0) {
  327.         unsigned long key[] = {
  328.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  329.         };
  330.        
  331.         fibril_mutex_lock(&devices_mutex);
  332.         link_t *lnk = hash_table_find(&devices, key);
  333.         if (lnk == NULL) {
  334.             fibril_mutex_unlock(&devices_mutex);
  335.             ipc_answer_0(rid, ENOENT);
  336.             return;
  337.         }
  338.        
  339.         device_t *dev = hash_table_get_instance(lnk, device_t, link);
  340.        
  341.         ipc_callid_t callid;
  342.         if (!ipc_data_read_receive(&callid, NULL)) {
  343.             fibril_mutex_unlock(&devices_mutex);
  344.             ipc_answer_0(callid, EINVAL);
  345.             ipc_answer_0(rid, EINVAL);
  346.             return;
  347.         }
  348.        
  349.         /* Make a request at the driver */
  350.         ipc_call_t answer;
  351.         aid_t msg = async_send_3(dev->phone, IPC_GET_METHOD(*request),
  352.             IPC_GET_ARG1(*request), IPC_GET_ARG2(*request),
  353.             IPC_GET_ARG3(*request), &answer);
  354.        
  355.         /* Forward the IPC_M_DATA_READ request to the driver */
  356.         ipc_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
  357.         fibril_mutex_unlock(&devices_mutex);
  358.        
  359.         /* Wait for reply from the driver. */
  360.         ipcarg_t rc;
  361.         async_wait_for(msg, &rc);
  362.         size_t bytes = IPC_GET_ARG1(answer);
  363.        
  364.         /* Driver reply is the final result of the whole operation */
  365.         ipc_answer_1(rid, rc, bytes);
  366.     } else {
  367.         ipc_callid_t callid;
  368.         size_t size;
  369.         if (!ipc_data_read_receive(&callid, &size)) {
  370.             ipc_answer_0(callid, EINVAL);
  371.             ipc_answer_0(rid, EINVAL);
  372.             return;
  373.         }
  374.        
  375.         size_t count = devmap_device_get_count();
  376.         dev_desc_t *desc = malloc(count * sizeof(dev_desc_t));
  377.         if (desc == NULL) {
  378.             ipc_answer_0(callid, ENOMEM);
  379.             ipc_answer_1(rid, ENOMEM, 0);
  380.             return;
  381.         }
  382.        
  383.         size_t max = devmap_device_get_devices(count, desc);
  384.        
  385.         if (pos < max) {
  386.             ipc_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
  387.         } else {
  388.             ipc_answer_0(callid, ENOENT);
  389.             ipc_answer_1(rid, ENOENT, 0);
  390.             return;
  391.         }
  392.        
  393.         free(desc);
  394.        
  395.         ipc_answer_1(rid, EOK, 1);
  396.     }
  397. }
  398.  
  399. void devfs_write(ipc_callid_t rid, ipc_call_t *request)
  400. {
  401.     fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
  402.     off_t pos = (off_t) IPC_GET_ARG3(*request);
  403.    
  404.     if (index != 0) {
  405.         unsigned long key[] = {
  406.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  407.         };
  408.        
  409.         fibril_mutex_lock(&devices_mutex);
  410.         link_t *lnk = hash_table_find(&devices, key);
  411.         if (lnk == NULL) {
  412.             fibril_mutex_unlock(&devices_mutex);
  413.             ipc_answer_0(rid, ENOENT);
  414.             return;
  415.         }
  416.        
  417.         device_t *dev = hash_table_get_instance(lnk, device_t, link);
  418.        
  419.         ipc_callid_t callid;
  420.         if (!ipc_data_write_receive(&callid, NULL)) {
  421.             fibril_mutex_unlock(&devices_mutex);
  422.             ipc_answer_0(callid, EINVAL);
  423.             ipc_answer_0(rid, EINVAL);
  424.             return;
  425.         }
  426.        
  427.         /* Make a request at the driver */
  428.         ipc_call_t answer;
  429.         aid_t msg = async_send_3(dev->phone, IPC_GET_METHOD(*request),
  430.             IPC_GET_ARG1(*request), IPC_GET_ARG2(*request),
  431.             IPC_GET_ARG3(*request), &answer);
  432.        
  433.         /* Forward the IPC_M_DATA_WRITE request to the driver */
  434.         ipc_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
  435.        
  436.         fibril_mutex_unlock(&devices_mutex);
  437.        
  438.         /* Wait for reply from the driver. */
  439.         ipcarg_t rc;
  440.         async_wait_for(msg, &rc);
  441.         size_t bytes = IPC_GET_ARG1(answer);
  442.        
  443.         /* Driver reply is the final result of the whole operation */
  444.         ipc_answer_1(rid, rc, bytes);
  445.     } else {
  446.         /* Read-only filesystem */
  447.         ipc_answer_0(rid, ENOTSUP);
  448.     }
  449. }
  450.  
  451. void devfs_truncate(ipc_callid_t rid, ipc_call_t *request)
  452. {
  453.     ipc_answer_0(rid, ENOTSUP);
  454. }
  455.  
  456. void devfs_close(ipc_callid_t rid, ipc_call_t *request)
  457. {
  458.     fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
  459.    
  460.     if (index != 0) {
  461.         unsigned long key[] = {
  462.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  463.         };
  464.        
  465.         fibril_mutex_lock(&devices_mutex);
  466.         link_t *lnk = hash_table_find(&devices, key);
  467.         if (lnk == NULL) {
  468.             fibril_mutex_unlock(&devices_mutex);
  469.             ipc_answer_0(rid, ENOENT);
  470.             return;
  471.         }
  472.        
  473.         device_t *dev = hash_table_get_instance(lnk, device_t, link);
  474.         dev->refcount--;
  475.        
  476.         if (dev->refcount == 0) {
  477.             ipc_hangup(dev->phone);
  478.             hash_table_remove(&devices, key, DEVICES_KEYS);
  479.         }
  480.        
  481.         fibril_mutex_unlock(&devices_mutex);
  482.        
  483.         ipc_answer_0(rid, EOK);
  484.     } else
  485.         ipc_answer_0(rid, ENOTSUP);
  486. }
  487.  
  488. void devfs_sync(ipc_callid_t rid, ipc_call_t *request)
  489. {
  490.     fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
  491.    
  492.     if (index != 0) {
  493.         unsigned long key[] = {
  494.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  495.         };
  496.        
  497.         fibril_mutex_lock(&devices_mutex);
  498.         link_t *lnk = hash_table_find(&devices, key);
  499.         if (lnk == NULL) {
  500.             fibril_mutex_unlock(&devices_mutex);
  501.             ipc_answer_0(rid, ENOENT);
  502.             return;
  503.         }
  504.        
  505.         device_t *dev = hash_table_get_instance(lnk, device_t, link);
  506.        
  507.         /* Make a request at the driver */
  508.         ipc_call_t answer;
  509.         aid_t msg = async_send_2(dev->phone, IPC_GET_METHOD(*request),
  510.             IPC_GET_ARG1(*request), IPC_GET_ARG2(*request), &answer);
  511.        
  512.         fibril_mutex_unlock(&devices_mutex);
  513.        
  514.         /* Wait for reply from the driver */
  515.         ipcarg_t rc;
  516.         async_wait_for(msg, &rc);
  517.        
  518.         /* Driver reply is the final result of the whole operation */
  519.         ipc_answer_0(rid, rc);
  520.     } else
  521.         ipc_answer_0(rid, ENOTSUP);
  522. }
  523.  
  524. void devfs_destroy(ipc_callid_t rid, ipc_call_t *request)
  525. {
  526.     ipc_answer_0(rid, ENOTSUP);
  527. }
  528.  
  529. /**
  530.  * @}
  531.  */
  532.