00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
00111
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
00128
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
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