HelenOS sources
This source file includes following definitions.
- vfs_nodes_init
- _vfs_node_addref
- vfs_node_addref
- vfs_node_delref
- vfs_node_forget
- vfs_node_get
- vfs_node_peek
- vfs_node_put
- refcnt_visitor
- vfs_nodes_refcount_sum_get
- vfs_open_node_remote
- nodes_key_hash
- nodes_hash
- nodes_key_equal
- node_triplet
- vfs_node_has_children
#include "vfs.h"
#include <stdlib.h>
#include <str.h>
#include <fibril_synch.h>
#include <adt/hash_table.h>
#include <adt/hash.h>
#include <assert.h>
#include <async.h>
#include <errno.h>
#include <macros.h>
FIBRIL_MUTEX_INITIALIZE(nodes_mutex);
#define NODES_BUCKETS_LOG 8
#define NODES_BUCKETS (1 << NODES_BUCKETS_LOG)
hash_table_t nodes;
#define KEY_FS_HANDLE 0
#define KEY_DEV_HANDLE 1
#define KEY_INDEX 2
static size_t nodes_key_hash(const void *);
static size_t nodes_hash(const ht_link_t *);
static bool nodes_key_equal(const void *, const ht_link_t *);
static vfs_triplet_t node_triplet(vfs_node_t *node);
const hash_table_ops_t nodes_ops = {
.hash = nodes_hash,
.key_hash = nodes_key_hash,
.key_equal = nodes_key_equal,
.equal = NULL,
.remove_callback = NULL,
};
bool vfs_nodes_init(void)
{
return hash_table_create(&nodes, 0, 0, &nodes_ops);
}
static inline void _vfs_node_addref(vfs_node_t *node)
{
node->refcnt++;
}
void vfs_node_addref(vfs_node_t *node)
{
fibril_mutex_lock(&nodes_mutex);
_vfs_node_addref(node);
fibril_mutex_unlock(&nodes_mutex);
}
void vfs_node_delref(vfs_node_t *node)
{
bool free_node = false;
fibril_mutex_lock(&nodes_mutex);
node->refcnt--;
if (node->refcnt == 0) {
hash_table_remove_item(&nodes, &node->nh_link);
free_node = true;
}
fibril_mutex_unlock(&nodes_mutex);
if (free_node) {
async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
async_msg_2(exch, VFS_OUT_DESTROY, (sysarg_t) node->service_id,
(sysarg_t)node->index);
vfs_exchange_release(exch);
free(node);
}
}
void vfs_node_forget(vfs_node_t *node)
{
fibril_mutex_lock(&nodes_mutex);
hash_table_remove_item(&nodes, &node->nh_link);
fibril_mutex_unlock(&nodes_mutex);
free(node);
}
vfs_node_t *vfs_node_get(vfs_lookup_res_t *result)
{
vfs_node_t *node;
fibril_mutex_lock(&nodes_mutex);
ht_link_t *tmp = hash_table_find(&nodes, &result->triplet);
if (!tmp) {
node = (vfs_node_t *) malloc(sizeof(vfs_node_t));
if (!node) {
fibril_mutex_unlock(&nodes_mutex);
return NULL;
}
memset(node, 0, sizeof(vfs_node_t));
node->fs_handle = result->triplet.fs_handle;
node->service_id = result->triplet.service_id;
node->index = result->triplet.index;
node->size = result->size;
node->type = result->type;
fibril_rwlock_initialize(&node->contents_rwlock);
hash_table_insert(&nodes, &node->nh_link);
} else {
node = hash_table_get_inst(tmp, vfs_node_t, nh_link);
}
_vfs_node_addref(node);
fibril_mutex_unlock(&nodes_mutex);
return node;
}
vfs_node_t *vfs_node_peek(vfs_lookup_res_t *result)
{
vfs_node_t *node = NULL;
fibril_mutex_lock(&nodes_mutex);
ht_link_t *tmp = hash_table_find(&nodes, &result->triplet);
if (tmp) {
node = hash_table_get_inst(tmp, vfs_node_t, nh_link);
_vfs_node_addref(node);
}
fibril_mutex_unlock(&nodes_mutex);
return node;
}
void vfs_node_put(vfs_node_t *node)
{
vfs_node_delref(node);
}
struct refcnt_data {
unsigned refcnt;
fs_handle_t fs_handle;
service_id_t service_id;
};
static bool refcnt_visitor(ht_link_t *item, void *arg)
{
vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
struct refcnt_data *rd = (void *) arg;
if ((node->fs_handle == rd->fs_handle) &&
(node->service_id == rd->service_id))
rd->refcnt += node->refcnt;
return true;
}
unsigned
vfs_nodes_refcount_sum_get(fs_handle_t fs_handle, service_id_t service_id)
{
struct refcnt_data rd = {
.refcnt = 0,
.fs_handle = fs_handle,
.service_id = service_id
};
fibril_mutex_lock(&nodes_mutex);
hash_table_apply(&nodes, refcnt_visitor, &rd);
fibril_mutex_unlock(&nodes_mutex);
return rd.refcnt;
}
errno_t vfs_open_node_remote(vfs_node_t *node)
{
async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
ipc_call_t answer;
aid_t req = async_send_2(exch, VFS_OUT_OPEN_NODE,
(sysarg_t) node->service_id, (sysarg_t) node->index, &answer);
vfs_exchange_release(exch);
errno_t rc;
async_wait_for(req, &rc);
return rc;
}
static size_t nodes_key_hash(const void *key)
{
const vfs_triplet_t *tri = key;
size_t hash = hash_combine(tri->fs_handle, tri->index);
return hash_combine(hash, tri->service_id);
}
static size_t nodes_hash(const ht_link_t *item)
{
vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
vfs_triplet_t tri = node_triplet(node);
return nodes_key_hash(&tri);
}
static bool nodes_key_equal(const void *key, const ht_link_t *item)
{
const vfs_triplet_t *tri = key;
vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
return node->fs_handle == tri->fs_handle &&
node->service_id == tri->service_id && node->index == tri->index;
}
static inline vfs_triplet_t node_triplet(vfs_node_t *node)
{
vfs_triplet_t tri = {
.fs_handle = node->fs_handle,
.service_id = node->service_id,
.index = node->index
};
return tri;
}
bool vfs_node_has_children(vfs_node_t *node)
{
async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
errno_t rc = async_req_2_0(exch, VFS_OUT_IS_EMPTY, node->service_id,
node->index);
vfs_exchange_release(exch);
return rc == ENOTEMPTY;
}
HelenOS homepage, sources at GitHub