vfs_node.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008 Jakub Jermar
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00038 #include "vfs.h"
00039 #include <stdlib.h>
00040 #include <str.h>
00041 #include <fibril_synch.h>
00042 #include <adt/hash_table.h>
00043 #include <assert.h>
00044 #include <async.h>
00045 #include <errno.h>
00046 
00048 FIBRIL_MUTEX_INITIALIZE(nodes_mutex);
00049 
00050 #define NODES_BUCKETS_LOG       8
00051 #define NODES_BUCKETS           (1 << NODES_BUCKETS_LOG)
00052 
00054 hash_table_t nodes;
00055 
00056 #define KEY_FS_HANDLE   0
00057 #define KEY_DEV_HANDLE  1
00058 #define KEY_INDEX       2
00059 
00060 static hash_index_t nodes_hash(unsigned long []);
00061 static int nodes_compare(unsigned long [], hash_count_t, link_t *);
00062 static void nodes_remove_callback(link_t *);
00063 
00065 hash_table_operations_t nodes_ops = {
00066         .hash = nodes_hash,
00067         .compare = nodes_compare,
00068         .remove_callback = nodes_remove_callback
00069 };
00070 
00075 bool vfs_nodes_init(void)
00076 {
00077         return hash_table_create(&nodes, NODES_BUCKETS, 3, &nodes_ops);
00078 }
00079 
00080 static inline void _vfs_node_addref(vfs_node_t *node)
00081 {
00082         node->refcnt++;
00083 }
00084 
00089 void vfs_node_addref(vfs_node_t *node)
00090 {
00091         fibril_mutex_lock(&nodes_mutex);
00092         _vfs_node_addref(node);
00093         fibril_mutex_unlock(&nodes_mutex);
00094 }
00095 
00102 void vfs_node_delref(vfs_node_t *node)
00103 {
00104         bool free_vfs_node = false;
00105         bool free_fs_node = false;
00106 
00107         fibril_mutex_lock(&nodes_mutex);
00108         if (node->refcnt-- == 1) {
00109                 /*
00110                  * We are dropping the last reference to this node.
00111                  * Remove it from the VFS node hash table.
00112                  */
00113                 unsigned long key[] = {
00114                         [KEY_FS_HANDLE] = node->fs_handle,
00115                         [KEY_DEV_HANDLE] = node->devmap_handle,
00116                         [KEY_INDEX] = node->index
00117                 };
00118                 hash_table_remove(&nodes, key, 3);
00119                 free_vfs_node = true;
00120                 if (!node->lnkcnt)
00121                         free_fs_node = true;
00122         }
00123         fibril_mutex_unlock(&nodes_mutex);
00124 
00125         if (free_fs_node) {
00126                 /* 
00127                  * The node is not visible in the file system namespace.
00128                  * Free up its resources.
00129                  */
00130                 int phone = vfs_grab_phone(node->fs_handle);
00131                 sysarg_t rc;
00132                 rc = async_req_2_0(phone, VFS_OUT_DESTROY,
00133                     (sysarg_t)node->devmap_handle, (sysarg_t)node->index);
00134                 assert(rc == EOK);
00135                 vfs_release_phone(node->fs_handle, phone);
00136         }
00137         if (free_vfs_node)
00138                 free(node);
00139 }
00140 
00148 void vfs_node_forget(vfs_node_t *node)
00149 {
00150         fibril_mutex_lock(&nodes_mutex);
00151         unsigned long key[] = {
00152                 [KEY_FS_HANDLE] = node->fs_handle,
00153                 [KEY_DEV_HANDLE] = node->devmap_handle,
00154                 [KEY_INDEX] = node->index
00155         };
00156         hash_table_remove(&nodes, key, 3);
00157         fibril_mutex_unlock(&nodes_mutex);
00158         free(node);
00159 }
00160 
00173 vfs_node_t *vfs_node_get(vfs_lookup_res_t *result)
00174 {
00175         unsigned long key[] = {
00176                 [KEY_FS_HANDLE] = result->triplet.fs_handle,
00177                 [KEY_DEV_HANDLE] = result->triplet.devmap_handle,
00178                 [KEY_INDEX] = result->triplet.index
00179         };
00180         link_t *tmp;
00181         vfs_node_t *node;
00182 
00183         fibril_mutex_lock(&nodes_mutex);
00184         tmp = hash_table_find(&nodes, key);
00185         if (!tmp) {
00186                 node = (vfs_node_t *) malloc(sizeof(vfs_node_t));
00187                 if (!node) {
00188                         fibril_mutex_unlock(&nodes_mutex);
00189                         return NULL;
00190                 }
00191                 memset(node, 0, sizeof(vfs_node_t));
00192                 node->fs_handle = result->triplet.fs_handle;
00193                 node->devmap_handle = result->triplet.devmap_handle;
00194                 node->index = result->triplet.index;
00195                 node->size = result->size;
00196                 node->lnkcnt = result->lnkcnt;
00197                 node->type = result->type;
00198                 link_initialize(&node->nh_link);
00199                 fibril_rwlock_initialize(&node->contents_rwlock);
00200                 hash_table_insert(&nodes, key, &node->nh_link);
00201         } else {
00202                 node = hash_table_get_instance(tmp, vfs_node_t, nh_link);
00203                 if (node->type == VFS_NODE_UNKNOWN &&
00204                     result->type != VFS_NODE_UNKNOWN) {
00205                         /* Upgrade the node type. */
00206                         node->type = result->type;
00207                 }
00208         }
00209 
00210         assert(node->size == result->size || node->type != VFS_NODE_FILE);
00211         assert(node->lnkcnt == result->lnkcnt);
00212         assert(node->type == result->type || result->type == VFS_NODE_UNKNOWN);
00213 
00214         _vfs_node_addref(node);
00215         fibril_mutex_unlock(&nodes_mutex);
00216 
00217         return node;
00218 }
00219 
00228 void vfs_node_put(vfs_node_t *node)
00229 {
00230         vfs_node_delref(node);
00231 }
00232 
00233 hash_index_t nodes_hash(unsigned long key[])
00234 {
00235         hash_index_t a = key[KEY_FS_HANDLE] << (NODES_BUCKETS_LOG / 4);
00236         hash_index_t b = (a | key[KEY_DEV_HANDLE]) << (NODES_BUCKETS_LOG / 2);
00237         
00238         return (b | key[KEY_INDEX]) & (NODES_BUCKETS - 1);
00239 }
00240 
00241 int nodes_compare(unsigned long key[], hash_count_t keys, link_t *item)
00242 {
00243         vfs_node_t *node = hash_table_get_instance(item, vfs_node_t, nh_link);
00244         return (node->fs_handle == (fs_handle_t) key[KEY_FS_HANDLE]) &&
00245             (node->devmap_handle == key[KEY_DEV_HANDLE]) &&
00246             (node->index == key[KEY_INDEX]);
00247 }
00248 
00249 void nodes_remove_callback(link_t *item)
00250 {
00251 }
00252 
00253 struct refcnt_data {
00255         unsigned refcnt;
00256         fs_handle_t fs_handle;
00257         devmap_handle_t devmap_handle;
00258 };
00259 
00260 static void refcnt_visitor(link_t *item, void *arg)
00261 {
00262         vfs_node_t *node = hash_table_get_instance(item, vfs_node_t, nh_link);
00263         struct refcnt_data *rd = (void *) arg;
00264 
00265         if ((node->fs_handle == rd->fs_handle) &&
00266             (node->devmap_handle == rd->devmap_handle))
00267                 rd->refcnt += node->refcnt;
00268 }
00269 
00270 unsigned
00271 vfs_nodes_refcount_sum_get(fs_handle_t fs_handle, devmap_handle_t devmap_handle)
00272 {
00273         struct refcnt_data rd = {
00274                 .refcnt = 0,
00275                 .fs_handle = fs_handle,
00276                 .devmap_handle = devmap_handle
00277         };
00278 
00279         fibril_mutex_lock(&nodes_mutex);
00280         hash_table_apply(&nodes, refcnt_visitor, &rd);
00281         fibril_mutex_unlock(&nodes_mutex);
00282 
00283         return rd.refcnt;
00284 }
00285 

Generated on Thu Jun 2 07:45:50 2011 for HelenOS/USB by  doxygen 1.4.7