Subversion Repositories HelenOS

Rev

Rev 4561 | Go to most recent revision | 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 "devfs.h"
  47. #include "devfs_ops.h"
  48.  
  49. #define PLB_GET_CHAR(pos)  (devfs_reg.plb_ro[pos % PLB_SIZE])
  50.  
  51. /** Opened devices structure */
  52. typedef struct {
  53.     dev_handle_t handle;
  54.     int phone;
  55.     size_t refcount;
  56.     link_t link;
  57. } device_t;
  58.  
  59. /** Hash table of opened devices */
  60. static hash_table_t devices;
  61.  
  62. /** Hash table mutex */
  63. static FIBRIL_MUTEX_INITIALIZE(devices_mutex);
  64.  
  65. #define DEVICES_KEYS        1
  66. #define DEVICES_KEY_HANDLE  0
  67. #define DEVICES_BUCKETS     256
  68.  
  69. /* Implementation of hash table interface for the nodes hash table. */
  70. static hash_index_t devices_hash(unsigned long key[])
  71. {
  72.     return key[DEVICES_KEY_HANDLE] % DEVICES_BUCKETS;
  73. }
  74.  
  75. static int devices_compare(unsigned long key[], hash_count_t keys, link_t *item)
  76. {
  77.     device_t *dev = hash_table_get_instance(item, device_t, link);
  78.     return (dev->handle == (dev_handle_t) key[DEVICES_KEY_HANDLE]);
  79. }
  80.  
  81. static void devices_remove_callback(link_t *item)
  82. {
  83.     free(hash_table_get_instance(item, device_t, link));
  84. }
  85.  
  86. static hash_table_operations_t devices_ops = {
  87.     .hash = devices_hash,
  88.     .compare = devices_compare,
  89.     .remove_callback = devices_remove_callback
  90. };
  91.  
  92. bool devfs_init(void)
  93. {
  94.     if (!hash_table_create(&devices, DEVICES_BUCKETS,
  95.         DEVICES_KEYS, &devices_ops))
  96.         return false;
  97.    
  98.     if (devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING) < 0)
  99.         return false;
  100.    
  101.     return true;
  102. }
  103.  
  104. void devfs_mounted(ipc_callid_t rid, ipc_call_t *request)
  105. {
  106.     /* Accept the mount options */
  107.     ipc_callid_t callid;
  108.     size_t size;
  109.     if (!ipc_data_write_receive(&callid, &size)) {
  110.         ipc_answer_0(callid, EINVAL);
  111.         ipc_answer_0(rid, EINVAL);
  112.         return;
  113.     }
  114.    
  115.     char *opts = malloc(size + 1);
  116.     if (!opts) {
  117.         ipc_answer_0(callid, ENOMEM);
  118.         ipc_answer_0(rid, ENOMEM);
  119.         return;
  120.     }
  121.    
  122.     ipcarg_t retval = ipc_data_write_finalize(callid, opts, size);
  123.     if (retval != EOK) {
  124.         ipc_answer_0(rid, retval);
  125.         free(opts);
  126.         return;
  127.     }
  128.    
  129.     free(opts);
  130.    
  131.     ipc_answer_3(rid, EOK, 0, 0, 0);
  132. }
  133.  
  134. void devfs_mount(ipc_callid_t rid, ipc_call_t *request)
  135. {
  136.     ipc_answer_0(rid, ENOTSUP);
  137. }
  138.  
  139. void devfs_lookup(ipc_callid_t rid, ipc_call_t *request)
  140. {
  141.     ipcarg_t first = IPC_GET_ARG1(*request);
  142.     ipcarg_t last = IPC_GET_ARG2(*request);
  143.     dev_handle_t dev_handle = IPC_GET_ARG3(*request);
  144.     ipcarg_t lflag = IPC_GET_ARG4(*request);
  145.     fs_index_t index = IPC_GET_ARG5(*request);
  146.    
  147.     /* Hierarchy is flat, no altroot is supported */
  148.     if (index != 0) {
  149.         ipc_answer_0(rid, ENOENT);
  150.         return;
  151.     }
  152.    
  153.     if ((lflag & L_LINK) || (lflag & L_UNLINK)) {
  154.         ipc_answer_0(rid, ENOTSUP);
  155.         return;
  156.     }
  157.    
  158.     /* Eat slash */
  159.     if (PLB_GET_CHAR(first) == '/') {
  160.         first++;
  161.         first %= PLB_SIZE;
  162.     }
  163.    
  164.     if (first >= last) {
  165.         /* Root entry */
  166.         if (lflag & L_DIRECTORY)
  167.             ipc_answer_5(rid, EOK, devfs_reg.fs_handle, dev_handle, 0, 0, 0);
  168.         else
  169.             ipc_answer_0(rid, ENOENT);
  170.     } else {
  171.         if (lflag & L_FILE) {
  172.             size_t len;
  173.             if (last >= first)
  174.                 len = last - first + 1;
  175.             else
  176.                 len = first + PLB_SIZE - last + 1;
  177.            
  178.             char *name = (char *) malloc(len + 1);
  179.             if (name == NULL) {
  180.                 ipc_answer_0(rid, ENOMEM);
  181.                 return;
  182.             }
  183.            
  184.             size_t i;
  185.             for (i = 0; i < len; i++)
  186.                 name[i] = PLB_GET_CHAR(first + i);
  187.            
  188.             name[len] = 0;
  189.            
  190.             dev_handle_t handle;
  191.             if (devmap_device_get_handle(name, &handle, 0) != EOK) {
  192.                 free(name);
  193.                 ipc_answer_0(rid, ENOENT);
  194.                 return;
  195.             }
  196.            
  197.             if (lflag & L_OPEN) {
  198.                 unsigned long key[] = {
  199.                     [DEVICES_KEY_HANDLE] = (unsigned long) handle
  200.                 };
  201.                
  202.                 fibril_mutex_lock(&devices_mutex);
  203.                 link_t *lnk = hash_table_find(&devices, key);
  204.                 if (lnk == NULL) {
  205.                     int phone = devmap_device_connect(handle, 0);
  206.                     if (phone < 0) {
  207.                         fibril_mutex_unlock(&devices_mutex);
  208.                         free(name);
  209.                         ipc_answer_0(rid, ENOENT);
  210.                         return;
  211.                     }
  212.                    
  213.                     device_t *dev = (device_t *) malloc(sizeof(device_t));
  214.                     if (dev == NULL) {
  215.                         fibril_mutex_unlock(&devices_mutex);
  216.                         free(name);
  217.                         ipc_answer_0(rid, ENOMEM);
  218.                         return;
  219.                     }
  220.                    
  221.                     dev->handle = handle;
  222.                     dev->phone = phone;
  223.                     dev->refcount = 1;
  224.                    
  225.                     hash_table_insert(&devices, key, &dev->link);
  226.                 } else {
  227.                     device_t *dev = hash_table_get_instance(lnk, device_t, link);
  228.                     dev->refcount++;
  229.                 }
  230.                 fibril_mutex_unlock(&devices_mutex);
  231.             }
  232.            
  233.             free(name);
  234.            
  235.             ipc_answer_5(rid, EOK, devfs_reg.fs_handle, dev_handle, handle, 0, 1);
  236.         } else
  237.             ipc_answer_0(rid, ENOENT);
  238.     }
  239. }
  240.  
  241. void devfs_open_node(ipc_callid_t rid, ipc_call_t *request)
  242. {
  243.     dev_handle_t handle = IPC_GET_ARG2(*request);
  244.    
  245.     unsigned long key[] = {
  246.         [DEVICES_KEY_HANDLE] = (unsigned long) handle
  247.     };
  248.    
  249.     fibril_mutex_lock(&devices_mutex);
  250.     link_t *lnk = hash_table_find(&devices, key);
  251.     if (lnk == NULL) {
  252.         int phone = devmap_device_connect(handle, 0);
  253.         if (phone < 0) {
  254.             fibril_mutex_unlock(&devices_mutex);
  255.             ipc_answer_0(rid, ENOENT);
  256.             return;
  257.         }
  258.        
  259.         device_t *dev = (device_t *) malloc(sizeof(device_t));
  260.         if (dev == NULL) {
  261.             fibril_mutex_unlock(&devices_mutex);
  262.             ipc_answer_0(rid, ENOMEM);
  263.             return;
  264.         }
  265.        
  266.         dev->handle = handle;
  267.         dev->phone = phone;
  268.         dev->refcount = 1;
  269.        
  270.         hash_table_insert(&devices, key, &dev->link);
  271.     } else {
  272.         device_t *dev = hash_table_get_instance(lnk, device_t, link);
  273.         dev->refcount++;
  274.     }
  275.     fibril_mutex_unlock(&devices_mutex);
  276.    
  277.     ipc_answer_3(rid, EOK, 0, 1, L_FILE);
  278. }
  279.  
  280. void devfs_device(ipc_callid_t rid, ipc_call_t *request)
  281. {
  282.     fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
  283.    
  284.     if (index != 0) {
  285.         unsigned long key[] = {
  286.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  287.         };
  288.        
  289.         fibril_mutex_lock(&devices_mutex);
  290.         link_t *lnk = hash_table_find(&devices, key);
  291.         if (lnk == NULL) {
  292.             fibril_mutex_unlock(&devices_mutex);
  293.             ipc_answer_0(rid, ENOENT);
  294.             return;
  295.         }
  296.         fibril_mutex_unlock(&devices_mutex);
  297.        
  298.         ipc_answer_1(rid, EOK, (ipcarg_t) index);
  299.     } else
  300.         ipc_answer_0(rid, ENOTSUP);
  301. }
  302.  
  303. void devfs_read(ipc_callid_t rid, ipc_call_t *request)
  304. {
  305.     fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
  306.     off_t pos = (off_t) IPC_GET_ARG3(*request);
  307.    
  308.     if (index != 0) {
  309.         unsigned long key[] = {
  310.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  311.         };
  312.        
  313.         fibril_mutex_lock(&devices_mutex);
  314.         link_t *lnk = hash_table_find(&devices, key);
  315.         if (lnk == NULL) {
  316.             fibril_mutex_unlock(&devices_mutex);
  317.             ipc_answer_0(rid, ENOENT);
  318.             return;
  319.         }
  320.        
  321.         device_t *dev = hash_table_get_instance(lnk, device_t, link);
  322.        
  323.         ipc_callid_t callid;
  324.         if (!ipc_data_read_receive(&callid, NULL)) {
  325.             fibril_mutex_unlock(&devices_mutex);
  326.             ipc_answer_0(callid, EINVAL);
  327.             ipc_answer_0(rid, EINVAL);
  328.             return;
  329.         }
  330.        
  331.         /* Make a request at the driver */
  332.         ipc_call_t answer;
  333.         aid_t msg = async_send_3(dev->phone, IPC_GET_METHOD(*request),
  334.             IPC_GET_ARG1(*request), IPC_GET_ARG2(*request),
  335.             IPC_GET_ARG3(*request), &answer);
  336.        
  337.         /* Forward the IPC_M_DATA_READ request to the driver */
  338.         ipc_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
  339.         fibril_mutex_unlock(&devices_mutex);
  340.        
  341.         /* Wait for reply from the driver. */
  342.         ipcarg_t rc;
  343.         async_wait_for(msg, &rc);
  344.         size_t bytes = IPC_GET_ARG1(answer);
  345.        
  346.         /* Driver reply is the final result of the whole operation */
  347.         ipc_answer_1(rid, rc, bytes);
  348.     } else {
  349.         ipc_callid_t callid;
  350.         size_t size;
  351.         if (!ipc_data_read_receive(&callid, &size)) {
  352.             ipc_answer_0(callid, EINVAL);
  353.             ipc_answer_0(rid, EINVAL);
  354.             return;
  355.         }
  356.        
  357.         size_t count = devmap_device_get_count();
  358.         dev_desc_t *desc = malloc(count * sizeof(dev_desc_t));
  359.         if (desc == NULL) {
  360.             ipc_answer_0(callid, ENOMEM);
  361.             ipc_answer_1(rid, ENOMEM, 0);
  362.             return;
  363.         }
  364.        
  365.         size_t max = devmap_device_get_devices(count, desc);
  366.        
  367.         if (pos < max) {
  368.             ipc_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
  369.         } else {
  370.             ipc_answer_0(callid, ENOENT);
  371.             ipc_answer_1(rid, ENOENT, 0);
  372.             return;
  373.         }
  374.        
  375.         free(desc);
  376.        
  377.         ipc_answer_1(rid, EOK, 1);
  378.     }
  379. }
  380.  
  381. void devfs_write(ipc_callid_t rid, ipc_call_t *request)
  382. {
  383.     fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
  384.     off_t pos = (off_t) IPC_GET_ARG3(*request);
  385.    
  386.     if (index != 0) {
  387.         unsigned long key[] = {
  388.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  389.         };
  390.        
  391.         fibril_mutex_lock(&devices_mutex);
  392.         link_t *lnk = hash_table_find(&devices, key);
  393.         if (lnk == NULL) {
  394.             fibril_mutex_unlock(&devices_mutex);
  395.             ipc_answer_0(rid, ENOENT);
  396.             return;
  397.         }
  398.        
  399.         device_t *dev = hash_table_get_instance(lnk, device_t, link);
  400.        
  401.         ipc_callid_t callid;
  402.         if (!ipc_data_write_receive(&callid, NULL)) {
  403.             fibril_mutex_unlock(&devices_mutex);
  404.             ipc_answer_0(callid, EINVAL);
  405.             ipc_answer_0(rid, EINVAL);
  406.             return;
  407.         }
  408.        
  409.         /* Make a request at the driver */
  410.         ipc_call_t answer;
  411.         aid_t msg = async_send_3(dev->phone, IPC_GET_METHOD(*request),
  412.             IPC_GET_ARG1(*request), IPC_GET_ARG2(*request),
  413.             IPC_GET_ARG3(*request), &answer);
  414.        
  415.         /* Forward the IPC_M_DATA_WRITE request to the driver */
  416.         ipc_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
  417.        
  418.         fibril_mutex_unlock(&devices_mutex);
  419.        
  420.         /* Wait for reply from the driver. */
  421.         ipcarg_t rc;
  422.         async_wait_for(msg, &rc);
  423.         size_t bytes = IPC_GET_ARG1(answer);
  424.        
  425.         /* Driver reply is the final result of the whole operation */
  426.         ipc_answer_1(rid, rc, bytes);
  427.     } else {
  428.         /* Read-only filesystem */
  429.         ipc_answer_0(rid, ENOTSUP);
  430.     }
  431. }
  432.  
  433. void devfs_truncate(ipc_callid_t rid, ipc_call_t *request)
  434. {
  435.     ipc_answer_0(rid, ENOTSUP);
  436. }
  437.  
  438. void devfs_close(ipc_callid_t rid, ipc_call_t *request)
  439. {
  440.     fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
  441.    
  442.     if (index != 0) {
  443.         unsigned long key[] = {
  444.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  445.         };
  446.        
  447.         fibril_mutex_lock(&devices_mutex);
  448.         link_t *lnk = hash_table_find(&devices, key);
  449.         if (lnk == NULL) {
  450.             fibril_mutex_unlock(&devices_mutex);
  451.             ipc_answer_0(rid, ENOENT);
  452.             return;
  453.         }
  454.        
  455.         device_t *dev = hash_table_get_instance(lnk, device_t, link);
  456.         dev->refcount--;
  457.        
  458.         if (dev->refcount == 0) {
  459.             ipc_hangup(dev->phone);
  460.             hash_table_remove(&devices, key, DEVICES_KEYS);
  461.         }
  462.        
  463.         fibril_mutex_unlock(&devices_mutex);
  464.        
  465.         ipc_answer_0(rid, EOK);
  466.     } else
  467.         ipc_answer_0(rid, ENOTSUP);
  468. }
  469.  
  470. void devfs_sync(ipc_callid_t rid, ipc_call_t *request)
  471. {
  472.     fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
  473.    
  474.     if (index != 0) {
  475.         unsigned long key[] = {
  476.             [DEVICES_KEY_HANDLE] = (unsigned long) index
  477.         };
  478.        
  479.         fibril_mutex_lock(&devices_mutex);
  480.         link_t *lnk = hash_table_find(&devices, key);
  481.         if (lnk == NULL) {
  482.             fibril_mutex_unlock(&devices_mutex);
  483.             ipc_answer_0(rid, ENOENT);
  484.             return;
  485.         }
  486.        
  487.         device_t *dev = hash_table_get_instance(lnk, device_t, link);
  488.        
  489.         /* Make a request at the driver */
  490.         ipc_call_t answer;
  491.         aid_t msg = async_send_2(dev->phone, IPC_GET_METHOD(*request),
  492.             IPC_GET_ARG1(*request), IPC_GET_ARG2(*request), &answer);
  493.        
  494.         fibril_mutex_unlock(&devices_mutex);
  495.        
  496.         /* Wait for reply from the driver */
  497.         ipcarg_t rc;
  498.         async_wait_for(msg, &rc);
  499.        
  500.         /* Driver reply is the final result of the whole operation */
  501.         ipc_answer_0(rid, rc);
  502.     } else
  503.         ipc_answer_0(rid, ENOTSUP);
  504. }
  505.  
  506. void devfs_destroy(ipc_callid_t rid, ipc_call_t *request)
  507. {
  508.     ipc_answer_0(rid, ENOTSUP);
  509. }
  510.  
  511. /**
  512.  * @}
  513.  */
  514.