source: mainline/uspace/srv/vfs/vfs_node.c@ 1701a24d

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

Add support for server-side mounts.

  • Property mode set to 100644
File size: 8.7 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>
[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) {
[79ae36dd]115
[f17667a]116 /*
117 * We are dropping the last reference to this node.
118 * Remove it from the VFS node hash table.
119 */
[79ae36dd]120
[062d900]121 hash_table_remove_item(&nodes, &node->nh_link);
[b7c62a9]122 free_node = true;
[b818cff]123 }
[79ae36dd]124
[553492be]125 fibril_mutex_unlock(&nodes_mutex);
[79ae36dd]126
[b7c62a9]127 if (free_node) {
[79ae36dd]128 /*
[b7c62a9]129 * DESTROY will free up the file's resources if there are no more hard links.
[f17667a]130 */
[79ae36dd]131
132 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
[b7c62a9]133 async_msg_2(exch, VFS_OUT_DESTROY,
134 (sysarg_t) node->service_id, (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);
206 }
207 fibril_mutex_unlock(&nodes_mutex);
208
209 return node;
210}
211
[320c884]212/** Return VFS node when no longer needed by the caller.
213 *
214 * This function will remove the reference on the VFS node created by
215 * vfs_node_get(). This function can only be called as a closing bracket to the
216 * preceding vfs_node_get() call.
217 *
218 * @param node VFS node being released.
219 */
220void vfs_node_put(vfs_node_t *node)
221{
222 vfs_node_delref(node);
[ec01adf]223}
224
[319f4fb]225struct refcnt_data {
226 /** Sum of all reference counts for this file system instance. */
227 unsigned refcnt;
228 fs_handle_t fs_handle;
[15f3c3f]229 service_id_t service_id;
[319f4fb]230};
231
[062d900]232static bool refcnt_visitor(ht_link_t *item, void *arg)
[319f4fb]233{
[062d900]234 vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
[319f4fb]235 struct refcnt_data *rd = (void *) arg;
236
237 if ((node->fs_handle == rd->fs_handle) &&
[15f3c3f]238 (node->service_id == rd->service_id))
[319f4fb]239 rd->refcnt += node->refcnt;
[062d900]240
241 return true;
[319f4fb]242}
243
244unsigned
[15f3c3f]245vfs_nodes_refcount_sum_get(fs_handle_t fs_handle, service_id_t service_id)
[319f4fb]246{
247 struct refcnt_data rd = {
248 .refcnt = 0,
249 .fs_handle = fs_handle,
[15f3c3f]250 .service_id = service_id
[319f4fb]251 };
252
253 fibril_mutex_lock(&nodes_mutex);
254 hash_table_apply(&nodes, refcnt_visitor, &rd);
255 fibril_mutex_unlock(&nodes_mutex);
256
257 return rd.refcnt;
258}
259
[44451ee]260
261/** Perform a remote node open operation.
262 *
263 * @return EOK on success or an error code from errno.h.
264 *
265 */
266int vfs_open_node_remote(vfs_node_t *node)
267{
268 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
269
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);
[44451ee]273
274 vfs_exchange_release(exch);
275
276 sysarg_t rc;
277 async_wait_for(req, &rc);
278
279 return rc;
280}
281
[062d900]282
283static size_t nodes_key_hash(void *key)
284{
285 vfs_triplet_t *tri = key;
286 size_t hash = hash_combine(tri->fs_handle, tri->index);
287 return hash_combine(hash, tri->service_id);
288}
289
290static size_t nodes_hash(const ht_link_t *item)
291{
292 vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
293 vfs_triplet_t tri = node_triplet(node);
294 return nodes_key_hash(&tri);
295}
296
297static bool nodes_key_equal(void *key, const ht_link_t *item)
298{
299 vfs_triplet_t *tri = key;
300 vfs_node_t *node = hash_table_get_inst(item, vfs_node_t, nh_link);
301 return node->fs_handle == tri->fs_handle
302 && node->service_id == tri->service_id
303 && 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
[677745a]317int64_t vfs_node_get_size(vfs_node_t *node)
318{
319 if (node->size == -1) {
320 sysarg_t sz1 = 0;
321 sysarg_t sz2 = 0;
322
323 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
324 (void) async_req_2_2(exch, VFS_OUT_GET_SIZE,
325 node->service_id, node->index, &sz1, &sz2);
326 vfs_exchange_release(exch);
327
328 node->size = MERGE_LOUP32(sz1, sz2);
329 }
330 return node->size;
331}
332
[5bcd5b7]333bool vfs_node_has_children(vfs_node_t *node)
334{
335 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
336 int rc = async_req_2_0(exch, VFS_OUT_IS_EMPTY, node->service_id, node->index);
337 vfs_exchange_release(exch);
338 return rc == ENOTEMPTY;
339}
340
[ec01adf]341/**
342 * @}
[05b9912]343 */
Note: See TracBrowser for help on using the repository browser.