Subversion Repositories HelenOS

Rev

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