source: mainline/uspace/srv/vfs/vfs_node.c@ b7c62a9

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b7c62a9 was b7c62a9, checked in by Jiri Zarevucky <zarevucky.jiri@…>, 12 years ago

Make the server oblivious to the link count. It is just another source of potential problems. Also clean up some confusion with file types and node refcount.

  • Property mode set to 100644
File size: 7.8 KB
RevLine 
[ec01adf]1/*
[eb27ce5a]2 * Copyright (c) 2008 Jakub Jermar
[ec01adf]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 vfs_node.c
35 * @brief Various operations on VFS nodes have their home in this file.
36 */
37
38#include "vfs.h"
[b818cff]39#include <stdlib.h>
[19f857a]40#include <str.h>
[1e4cada]41#include <fibril_synch.h>
[d9c8c81]42#include <adt/hash_table.h>
[062d900]43#include <adt/hash.h>
[7fff5eab]44#include <assert.h>
[f17667a]45#include <async.h>
46#include <errno.h>
[b818cff]47
[553492be]48/** Mutex protecting the VFS node hash table. */
49FIBRIL_MUTEX_INITIALIZE(nodes_mutex);
[b818cff]50
51#define NODES_BUCKETS_LOG 8
52#define NODES_BUCKETS (1 << NODES_BUCKETS_LOG)
53
54/** VFS node hash table containing all active, in-memory VFS nodes. */
55hash_table_t nodes;
56
57#define KEY_FS_HANDLE 0
58#define KEY_DEV_HANDLE 1
59#define KEY_INDEX 2
60
[062d900]61static size_t nodes_key_hash(void *);
62static size_t nodes_hash(const ht_link_t *);
63static bool nodes_key_equal(void *, const ht_link_t *);
64static vfs_triplet_t node_triplet(vfs_node_t *node);
[b818cff]65
66/** VFS node hash table operations. */
[062d900]67hash_table_ops_t nodes_ops = {
[b818cff]68 .hash = nodes_hash,
[062d900]69 .key_hash = nodes_key_hash,
70 .key_equal = nodes_key_equal,
[4e00f87]71 .equal = NULL,
72 .remove_callback = NULL,
[b818cff]73};
74
75/** Initialize the VFS node hash table.
76 *
77 * @return Return true on success, false on failure.
78 */
79bool vfs_nodes_init(void)
80{
[062d900]81 return hash_table_create(&nodes, 0, 0, &nodes_ops);
[b818cff]82}
83
84static inline void _vfs_node_addref(vfs_node_t *node)
85{
86 node->refcnt++;
87}
[ec01adf]88
[320c884]89/** Increment reference count of a VFS node.
90 *
91 * @param node VFS node that will have its refcnt incremented.
92 */
93void vfs_node_addref(vfs_node_t *node)
94{
[553492be]95 fibril_mutex_lock(&nodes_mutex);
[b818cff]96 _vfs_node_addref(node);
[553492be]97 fibril_mutex_unlock(&nodes_mutex);
[320c884]98}
99
100/** Decrement reference count of a VFS node.
101 *
102 * This function handles the case when the reference count drops to zero.
103 *
104 * @param node VFS node that will have its refcnt decremented.
105 */
106void vfs_node_delref(vfs_node_t *node)
107{
[b7c62a9]108 bool free_node = false;
[79ae36dd]109
[553492be]110 fibril_mutex_lock(&nodes_mutex);
[79ae36dd]111
[b7c62a9]112 node->refcnt--;
113 if (node->refcnt == 0) {
[79ae36dd]114
[f17667a]115 /*
116 * We are dropping the last reference to this node.
117 * Remove it from the VFS node hash table.
118 */
[79ae36dd]119
[062d900]120 hash_table_remove_item(&nodes, &node->nh_link);
[b7c62a9]121 free_node = true;
[b818cff]122 }
[79ae36dd]123
[553492be]124 fibril_mutex_unlock(&nodes_mutex);
[79ae36dd]125
[b7c62a9]126 if (free_node) {
[79ae36dd]127 /*
[b7c62a9]128 * DESTROY will free up the file's resources if there are no more hard links.
[f17667a]129 */
[79ae36dd]130
131 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
[b7c62a9]132 async_msg_2(exch, VFS_OUT_DESTROY,
133 (sysarg_t) node->service_id, (sysarg_t)node->index);
[79ae36dd]134 vfs_exchange_release(exch);
[b7c62a9]135
[f17667a]136 free(node);
[b7c62a9]137 }
[320c884]138}
139
[c4aca2c]140/** Forget node.
141 *
142 * This function will remove the node from the node hash table and deallocate
143 * its memory, regardless of the node's reference count.
144 *
145 * @param node Node to be forgotten.
146 */
147void vfs_node_forget(vfs_node_t *node)
148{
149 fibril_mutex_lock(&nodes_mutex);
[062d900]150 hash_table_remove_item(&nodes, &node->nh_link);
[c4aca2c]151 fibril_mutex_unlock(&nodes_mutex);
152 free(node);
153}
154
[320c884]155/** Find VFS node.
156 *
157 * This function will try to lookup the given triplet in the VFS node hash
158 * table. In case the triplet is not found there, a new VFS node is created.
159 * In any case, the VFS node will have its reference count incremented. Every
160 * node returned by this call should be eventually put back by calling
161 * vfs_node_put() on it.
162 *
[eb27ce5a]163 * @param result Populated lookup result structure.
[320c884]164 *
165 * @return VFS node corresponding to the given triplet.
166 */
[eb27ce5a]167vfs_node_t *vfs_node_get(vfs_lookup_res_t *result)
[ec01adf]168{
[b818cff]169 vfs_node_t *node;
170
[553492be]171 fibril_mutex_lock(&nodes_mutex);
[062d900]172 ht_link_t *tmp = hash_table_find(&nodes, &result->triplet);
[b818cff]173 if (!tmp) {
174 node = (vfs_node_t *) malloc(sizeof(vfs_node_t));
175 if (!node) {
[553492be]176 fibril_mutex_unlock(&nodes_mutex);
[b818cff]177 return NULL;
178 }
179 memset(node, 0, sizeof(vfs_node_t));
[eb27ce5a]180 node->fs_handle = result->triplet.fs_handle;
[15f3c3f]181 node->service_id = result->triplet.service_id;
[eb27ce5a]182 node->index = result->triplet.index;
183 node->size = result->size;
[b17186d]184 node->type = result->type;
[230260ac]185 fibril_rwlock_initialize(&node->contents_rwlock);
[062d900]186 hash_table_insert(&nodes, &node->nh_link);
[b818cff]187 } else {
[062d900]188 node = hash_table_get_inst(tmp, vfs_node_t, nh_link);
[b818cff]189 }
[7fff5eab]190
[b818cff]191 _vfs_node_addref(node);
[553492be]192 fibril_mutex_unlock(&nodes_mutex);
[b818cff]193
194 return node;
[320c884]195}
196
197/** Return VFS node when no longer needed by the caller.
198 *
199 * This function will remove the reference on the VFS node created by
200 * vfs_node_get(). This function can only be called as a closing bracket to the
201 * preceding vfs_node_get() call.
202 *
203 * @param node VFS node being released.
204 */
205void vfs_node_put(vfs_node_t *node)
206{
207 vfs_node_delref(node);
[ec01adf]208}
209
[319f4fb]210struct refcnt_data {
211 /** Sum of all reference counts for this file system instance. */
212 unsigned refcnt;
213 fs_handle_t fs_handle;
[15f3c3f]214 service_id_t service_id;
[319f4fb]215};
216
[062d900]217static bool refcnt_visitor(ht_link_t *item, void *arg)
[319f4fb]218{
[062d900]219 vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
[319f4fb]220 struct refcnt_data *rd = (void *) arg;
221
222 if ((node->fs_handle == rd->fs_handle) &&
[15f3c3f]223 (node->service_id == rd->service_id))
[319f4fb]224 rd->refcnt += node->refcnt;
[062d900]225
226 return true;
[319f4fb]227}
228
229unsigned
[15f3c3f]230vfs_nodes_refcount_sum_get(fs_handle_t fs_handle, service_id_t service_id)
[319f4fb]231{
232 struct refcnt_data rd = {
233 .refcnt = 0,
234 .fs_handle = fs_handle,
[15f3c3f]235 .service_id = service_id
[319f4fb]236 };
237
238 fibril_mutex_lock(&nodes_mutex);
239 hash_table_apply(&nodes, refcnt_visitor, &rd);
240 fibril_mutex_unlock(&nodes_mutex);
241
242 return rd.refcnt;
243}
244
[44451ee]245
246/** Perform a remote node open operation.
247 *
248 * @return EOK on success or an error code from errno.h.
249 *
250 */
251int vfs_open_node_remote(vfs_node_t *node)
252{
253 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
254
255 ipc_call_t answer;
256 aid_t req = async_send_2(exch, VFS_OUT_OPEN_NODE,
[42a619b]257 (sysarg_t) node->service_id, (sysarg_t) node->index, &answer);
[44451ee]258
259 vfs_exchange_release(exch);
260
261 sysarg_t rc;
262 async_wait_for(req, &rc);
263
264 return rc;
265}
266
[062d900]267
268static size_t nodes_key_hash(void *key)
269{
270 vfs_triplet_t *tri = key;
271 size_t hash = hash_combine(tri->fs_handle, tri->index);
272 return hash_combine(hash, tri->service_id);
273}
274
275static size_t nodes_hash(const ht_link_t *item)
276{
277 vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
278 vfs_triplet_t tri = node_triplet(node);
279 return nodes_key_hash(&tri);
280}
281
282static bool nodes_key_equal(void *key, const ht_link_t *item)
283{
284 vfs_triplet_t *tri = key;
285 vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
286 return node->fs_handle == tri->fs_handle
287 && node->service_id == tri->service_id
288 && node->index == tri->index;
289}
290
291static inline vfs_triplet_t node_triplet(vfs_node_t *node)
292{
293 vfs_triplet_t tri = {
294 .fs_handle = node->fs_handle,
295 .service_id = node->service_id,
296 .index = node->index
297 };
298
299 return tri;
300}
301
[ec01adf]302/**
303 * @}
[05b9912]304 */
Note: See TracBrowser for help on using the repository browser.