source: mainline/uspace/srv/vfs/vfs_node.c@ 95658c9

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 95658c9 was 5e801dc, checked in by GitHub <noreply@…>, 6 years ago

Indicate and enforce constness of hash table key in certain functions (#158)

The assumption here is that modifying key in the hash/equal functions in something completely unexpected, and not something you would ever want to do intentionally, so it makes sense to disallow it entirely to get that extra level of checking.

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