source: mainline/uspace/srv/vfs/vfs_node.c@ 3061bc1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3061bc1 was 1b20da0, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on non-empty lines, in certain file types.

Command used: tools/srepl '\([^[:space:]]\)\s\+$' '\1' -- *.c *.h *.py *.sh *.s *.S *.ag

  • 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
29/** @addtogroup fs
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
[062d900]62static size_t nodes_key_hash(void *);
63static size_t nodes_hash(const ht_link_t *);
64static bool nodes_key_equal(void *, const ht_link_t *);
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;
[79ae36dd]110
[553492be]111 fibril_mutex_lock(&nodes_mutex);
[79ae36dd]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 */
[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 /*
[61042de]128 * VFS_OUT_DESTROY will free up the file's resources if there
129 * are no more hard links.
[f17667a]130 */
[79ae36dd]131
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;
[062d900]241
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
262/** Perform a remote node open operation.
263 *
264 * @return EOK on success or an error code from errno.h.
265 *
266 */
[b7fd2a0]267errno_t vfs_open_node_remote(vfs_node_t *node)
[44451ee]268{
269 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
270
271 ipc_call_t answer;
272 aid_t req = async_send_2(exch, VFS_OUT_OPEN_NODE,
[42a619b]273 (sysarg_t) node->service_id, (sysarg_t) node->index, &answer);
[44451ee]274
275 vfs_exchange_release(exch);
276
[b7fd2a0]277 errno_t rc;
[44451ee]278 async_wait_for(req, &rc);
279
280 return rc;
281}
282
[062d900]283
284static size_t nodes_key_hash(void *key)
285{
286 vfs_triplet_t *tri = key;
287 size_t hash = hash_combine(tri->fs_handle, tri->index);
288 return hash_combine(hash, tri->service_id);
289}
290
291static size_t nodes_hash(const ht_link_t *item)
292{
293 vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
294 vfs_triplet_t tri = node_triplet(node);
295 return nodes_key_hash(&tri);
296}
297
298static bool nodes_key_equal(void *key, const ht_link_t *item)
299{
300 vfs_triplet_t *tri = key;
301 vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
[61042de]302 return node->fs_handle == tri->fs_handle &&
303 node->service_id == tri->service_id && node->index == tri->index;
[062d900]304}
305
306static inline vfs_triplet_t node_triplet(vfs_node_t *node)
307{
308 vfs_triplet_t tri = {
309 .fs_handle = node->fs_handle,
310 .service_id = node->service_id,
311 .index = node->index
312 };
313
314 return tri;
315}
316
[5bcd5b7]317bool vfs_node_has_children(vfs_node_t *node)
318{
319 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
[b7fd2a0]320 errno_t rc = async_req_2_0(exch, VFS_OUT_IS_EMPTY, node->service_id,
[61042de]321 node->index);
[5bcd5b7]322 vfs_exchange_release(exch);
323 return rc == ENOTEMPTY;
324}
325
[ec01adf]326/**
327 * @}
[05b9912]328 */
Note: See TracBrowser for help on using the repository browser.