source: mainline/uspace/srv/vfs/vfs_node.c@ 3be9d10

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

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 8.4 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
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"
39#include <stdlib.h>
40#include <str.h>
41#include <fibril_synch.h>
42#include <adt/hash_table.h>
43#include <adt/hash.h>
44#include <assert.h>
45#include <async.h>
46#include <errno.h>
47#include <macros.h>
48
49/** Mutex protecting the VFS node hash table. */
50FIBRIL_MUTEX_INITIALIZE(nodes_mutex);
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
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);
66
67/** VFS node hash table operations. */
68hash_table_ops_t nodes_ops = {
69 .hash = nodes_hash,
70 .key_hash = nodes_key_hash,
71 .key_equal = nodes_key_equal,
72 .equal = NULL,
73 .remove_callback = NULL,
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{
82 return hash_table_create(&nodes, 0, 0, &nodes_ops);
83}
84
85static inline void _vfs_node_addref(vfs_node_t *node)
86{
87 node->refcnt++;
88}
89
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{
96 fibril_mutex_lock(&nodes_mutex);
97 _vfs_node_addref(node);
98 fibril_mutex_unlock(&nodes_mutex);
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{
109 bool free_node = false;
110
111 fibril_mutex_lock(&nodes_mutex);
112
113 node->refcnt--;
114 if (node->refcnt == 0) {
115 /*
116 * We are dropping the last reference to this node.
117 * Remove it from the VFS node hash table.
118 */
119
120 hash_table_remove_item(&nodes, &node->nh_link);
121 free_node = true;
122 }
123
124 fibril_mutex_unlock(&nodes_mutex);
125
126 if (free_node) {
127 /*
128 * VFS_OUT_DESTROY will free up the file's resources if there
129 * are no more hard links.
130 */
131
132 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
133 async_msg_2(exch, VFS_OUT_DESTROY, (sysarg_t) node->service_id,
134 (sysarg_t)node->index);
135 vfs_exchange_release(exch);
136
137 free(node);
138 }
139}
140
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);
151 hash_table_remove_item(&nodes, &node->nh_link);
152 fibril_mutex_unlock(&nodes_mutex);
153 free(node);
154}
155
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 *
164 * @param result Populated lookup result structure.
165 *
166 * @return VFS node corresponding to the given triplet.
167 */
168vfs_node_t *vfs_node_get(vfs_lookup_res_t *result)
169{
170 vfs_node_t *node;
171
172 fibril_mutex_lock(&nodes_mutex);
173 ht_link_t *tmp = hash_table_find(&nodes, &result->triplet);
174 if (!tmp) {
175 node = (vfs_node_t *) malloc(sizeof(vfs_node_t));
176 if (!node) {
177 fibril_mutex_unlock(&nodes_mutex);
178 return NULL;
179 }
180 memset(node, 0, sizeof(vfs_node_t));
181 node->fs_handle = result->triplet.fs_handle;
182 node->service_id = result->triplet.service_id;
183 node->index = result->triplet.index;
184 node->size = result->size;
185 node->type = result->type;
186 fibril_rwlock_initialize(&node->contents_rwlock);
187 hash_table_insert(&nodes, &node->nh_link);
188 } else {
189 node = hash_table_get_inst(tmp, vfs_node_t, nh_link);
190 }
191
192 _vfs_node_addref(node);
193 fibril_mutex_unlock(&nodes_mutex);
194
195 return node;
196}
197
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);
206 _vfs_node_addref(node);
207 }
208 fibril_mutex_unlock(&nodes_mutex);
209
210 return node;
211}
212
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);
224}
225
226struct refcnt_data {
227 /** Sum of all reference counts for this file system instance. */
228 unsigned refcnt;
229 fs_handle_t fs_handle;
230 service_id_t service_id;
231};
232
233static bool refcnt_visitor(ht_link_t *item, void *arg)
234{
235 vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
236 struct refcnt_data *rd = (void *) arg;
237
238 if ((node->fs_handle == rd->fs_handle) &&
239 (node->service_id == rd->service_id))
240 rd->refcnt += node->refcnt;
241
242 return true;
243}
244
245unsigned
246vfs_nodes_refcount_sum_get(fs_handle_t fs_handle, service_id_t service_id)
247{
248 struct refcnt_data rd = {
249 .refcnt = 0,
250 .fs_handle = fs_handle,
251 .service_id = service_id
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
261
262/** Perform a remote node open operation.
263 *
264 * @return EOK on success or an error code from errno.h.
265 *
266 */
267errno_t vfs_open_node_remote(vfs_node_t *node)
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,
273 (sysarg_t) node->service_id, (sysarg_t) node->index, &answer);
274
275 vfs_exchange_release(exch);
276
277 errno_t rc;
278 async_wait_for(req, &rc);
279
280 return rc;
281}
282
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);
302 return node->fs_handle == tri->fs_handle &&
303 node->service_id == tri->service_id && node->index == tri->index;
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
317bool vfs_node_has_children(vfs_node_t *node)
318{
319 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
320 errno_t rc = async_req_2_0(exch, VFS_OUT_IS_EMPTY, node->service_id,
321 node->index);
322 vfs_exchange_release(exch);
323 return rc == ENOTEMPTY;
324}
325
326/**
327 * @}
328 */
Note: See TracBrowser for help on using the repository browser.