~jsvoboda/helenos/dnsr

« back to all changes in this revision

Viewing changes to uspace/srv/fs/ext2fs/ext2fs_ops.c

  • Committer: Jiri Svoboda
  • Date: 2012-11-11 21:31:03 UTC
  • mfrom: (1527.1.178 mainline)
  • Revision ID: jiri@wiwaxia-20121111213103-314bmkettwvlwj97
MergeĀ mainlineĀ changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
38
38
#include "ext2fs.h"
39
39
#include "../../vfs/vfs.h"
40
40
#include <libfs.h>
41
 
#include <libblock.h>
 
41
#include <block.h>
42
42
#include <libext2.h>
43
43
#include <ipc/services.h>
44
44
#include <ipc/loc.h>
48
48
#include <str.h>
49
49
#include <byteorder.h>
50
50
#include <adt/hash_table.h>
 
51
#include <adt/hash.h>
51
52
#include <adt/list.h>
52
53
#include <assert.h>
53
54
#include <fibril_synch.h>
61
62
 
62
63
#define EXT2FS_NODE(node)       ((node) ? (ext2fs_node_t *) (node)->data : NULL)
63
64
#define EXT2FS_DBG(format, ...) {if (false) printf("ext2fs: %s: " format "\n", __FUNCTION__, ##__VA_ARGS__);}
64
 
#define OPEN_NODES_KEYS 2
65
 
#define OPEN_NODES_DEV_HANDLE_KEY 0
66
 
#define OPEN_NODES_INODE_KEY 1
67
 
#define OPEN_NODES_BUCKETS 256
68
65
 
69
66
typedef struct ext2fs_instance {
70
67
        link_t link;
77
74
        ext2fs_instance_t *instance;
78
75
        ext2_inode_ref_t *inode_ref;
79
76
        fs_node_t *fs_node;
80
 
        link_t link;
 
77
        ht_link_t link;
81
78
        unsigned int references;
82
79
} ext2fs_node_t;
83
80
 
121
118
static hash_table_t open_nodes;
122
119
static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
123
120
 
124
 
/* Hash table interface for open nodes hash table */
125
 
static hash_index_t open_nodes_hash(unsigned long key[])
126
 
{
127
 
        /* TODO: This is very simple and probably can be improved */
128
 
        return key[OPEN_NODES_INODE_KEY] % OPEN_NODES_BUCKETS;
129
 
}
130
 
 
131
 
static int open_nodes_compare(unsigned long key[], hash_count_t keys, 
132
 
    link_t *item)
133
 
{
134
 
        ext2fs_node_t *enode = hash_table_get_instance(item, ext2fs_node_t, link);
135
 
        assert(keys > 0);
136
 
        if (enode->instance->service_id !=
137
 
            ((service_id_t) key[OPEN_NODES_DEV_HANDLE_KEY])) {
138
 
                return false;
139
 
        }
140
 
        if (keys == 1) {
141
 
                return true;
142
 
        }
143
 
        assert(keys == 2);
144
 
        return (enode->inode_ref->index == key[OPEN_NODES_INODE_KEY]);
145
 
}
146
 
 
147
 
static void open_nodes_remove_cb(link_t *link)
148
 
{
149
 
        /* We don't use remove callback for this hash table */
150
 
}
151
 
 
152
 
static hash_table_operations_t open_nodes_ops = {
 
121
/* 
 
122
 * Hash table interface for open nodes hash table 
 
123
 */
 
124
 
 
125
typedef struct {
 
126
        service_id_t service_id;
 
127
        fs_index_t index;
 
128
} node_key_t;
 
129
 
 
130
static size_t open_nodes_key_hash(void *key)
 
131
{
 
132
        node_key_t *node_key = (node_key_t*)key;
 
133
        return hash_combine(node_key->service_id, node_key->index);
 
134
}
 
135
 
 
136
static size_t open_nodes_hash(const ht_link_t *item)
 
137
{
 
138
        ext2fs_node_t *enode = hash_table_get_inst(item, ext2fs_node_t, link);
 
139
 
 
140
        assert(enode->instance);
 
141
        assert(enode->inode_ref);
 
142
        
 
143
        return hash_combine(enode->instance->service_id, enode->inode_ref->index);
 
144
}
 
145
 
 
146
static bool open_nodes_key_equal(void *key, const ht_link_t *item)
 
147
{
 
148
        node_key_t *node_key = (node_key_t*)key;
 
149
        ext2fs_node_t *enode = hash_table_get_inst(item, ext2fs_node_t, link);
 
150
        
 
151
        return node_key->service_id == enode->instance->service_id
 
152
                && node_key->index == enode->inode_ref->index;
 
153
}
 
154
 
 
155
static hash_table_ops_t open_nodes_ops = {
153
156
        .hash = open_nodes_hash,
154
 
        .compare = open_nodes_compare,
155
 
        .remove_callback = open_nodes_remove_cb,
 
157
        .key_hash = open_nodes_key_hash,
 
158
        .key_equal = open_nodes_key_equal,
 
159
        .equal = NULL,
 
160
        .remove_callback = NULL,
156
161
};
157
162
 
158
163
/**
160
165
 */
161
166
int ext2fs_global_init(void)
162
167
{
163
 
        if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
164
 
            OPEN_NODES_KEYS, &open_nodes_ops)) {
 
168
        if (!hash_table_create(&open_nodes, 0, 0, &open_nodes_ops)) {
165
169
                return ENOMEM;
166
170
        }
167
171
        return EOK;
315
319
        fibril_mutex_lock(&open_nodes_lock);
316
320
        
317
321
        /* Check if the node is not already open */
318
 
        unsigned long key[] = {
319
 
                [OPEN_NODES_DEV_HANDLE_KEY] = inst->service_id,
320
 
                [OPEN_NODES_INODE_KEY] = index,
 
322
        node_key_t key = {
 
323
                .service_id = inst->service_id,
 
324
                .index = index
321
325
        };
322
 
        link_t *already_open = hash_table_find(&open_nodes, key);
 
326
        ht_link_t *already_open = hash_table_find(&open_nodes, &key);
323
327
 
324
328
        if (already_open) {
325
 
                enode = hash_table_get_instance(already_open, ext2fs_node_t, link);
 
329
                enode = hash_table_get_inst(already_open, ext2fs_node_t, link);
326
330
                *rfn = enode->fs_node;
327
331
                enode->references++;
328
332
 
356
360
        enode->instance = inst;
357
361
        enode->references = 1;
358
362
        enode->fs_node = node;
359
 
        link_initialize(&enode->link);
360
363
        
361
364
        node->data = enode;
362
365
        *rfn = node;
363
366
        
364
 
        hash_table_insert(&open_nodes, key, &enode->link);
 
367
        hash_table_insert(&open_nodes, &enode->link);
365
368
        inst->open_nodes_count++;
366
369
        
367
370
        EXT2FS_DBG("inode: %u", inode_ref->index);
407
410
 
408
411
int ext2fs_node_put_core(ext2fs_node_t *enode)
409
412
{
410
 
        int rc;
 
413
        node_key_t key = {
 
414
                .service_id = enode->instance->service_id,
 
415
                .index = enode->inode_ref->index
 
416
        };
411
417
 
412
 
        unsigned long key[] = {
413
 
                [OPEN_NODES_DEV_HANDLE_KEY] = enode->instance->service_id,
414
 
                [OPEN_NODES_INODE_KEY] = enode->inode_ref->index,
415
 
        };
416
 
        hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS);
 
418
        hash_table_remove(&open_nodes, &key);
 
419
        
417
420
        assert(enode->instance->open_nodes_count > 0);
418
421
        enode->instance->open_nodes_count--;
419
422
 
420
 
        rc = ext2_filesystem_put_inode_ref(enode->inode_ref);
 
423
        int rc = ext2_filesystem_put_inode_ref(enode->inode_ref);
421
424
        if (rc != EOK) {
422
425
                EXT2FS_DBG("ext2_filesystem_put_inode_ref failed");
423
426
                return rc;