source: mainline/uspace/srv/fs/tmpfs/tmpfs_ops.c@ 0ca7286

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0ca7286 was 0ca7286, checked in by Adam Hraska <adam.hraska+hos@…>, 13 years ago

Added resizing to user space (single-threaded) hash_table. Resizes in a way to mitigate effects of bad hash functions. Change of interface affected many files.

  • Property mode set to 100644
File size: 15.8 KB
RevLine 
[d5cdffe]1/*
[41a0d27]2 * Copyright (c) 2008 Jakub Jermar
[d5cdffe]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 * @{
[ed903174]31 */
[d5cdffe]32
33/**
34 * @file tmpfs_ops.c
35 * @brief Implementation of VFS operations for the TMPFS file system
36 * server.
37 */
38
39#include "tmpfs.h"
40#include "../../vfs/vfs.h"
[ed903174]41#include <macros.h>
[9539be6]42#include <stdint.h>
[d5cdffe]43#include <async.h>
44#include <errno.h>
[4b11571]45#include <atomic.h>
46#include <stdlib.h>
[19f857a]47#include <str.h>
[4b11571]48#include <stdio.h>
[5973fd0]49#include <assert.h>
[a4eb8a60]50#include <sys/types.h>
[d9c8c81]51#include <adt/hash_table.h>
[a4eb8a60]52#include <as.h>
[2c448fb]53#include <libfs.h>
[a4eb8a60]54
55#define min(a, b) ((a) < (b) ? (a) : (b))
56#define max(a, b) ((a) > (b) ? (a) : (b))
[d5cdffe]57
[8d049ee0]58/** All root nodes have index 0. */
59#define TMPFS_SOME_ROOT 0
60/** Global counter for assigning node indices. Shared by all instances. */
61fs_index_t tmpfs_next_index = 1;
[adb5fe3]62
[2c448fb]63/*
64 * Implementation of the libfs interface.
65 */
[b5553a2]66
[fdb7795]67/* Forward declarations of static functions. */
[54e4479]68static int tmpfs_match(fs_node_t **, fs_node_t *, const char *);
[15f3c3f]69static int tmpfs_node_get(fs_node_t **, service_id_t, fs_index_t);
[1313ee9]70static int tmpfs_node_open(fs_node_t *);
[54e4479]71static int tmpfs_node_put(fs_node_t *);
[15f3c3f]72static int tmpfs_create_node(fs_node_t **, service_id_t, int);
[54e4479]73static int tmpfs_destroy_node(fs_node_t *);
[b6035ba]74static int tmpfs_link_node(fs_node_t *, fs_node_t *, const char *);
[cf95bc0]75static int tmpfs_unlink_node(fs_node_t *, fs_node_t *, const char *);
[2c448fb]76
77/* Implementation of helper functions. */
[15f3c3f]78static int tmpfs_root_get(fs_node_t **rfn, service_id_t service_id)
[2c448fb]79{
[15f3c3f]80 return tmpfs_node_get(rfn, service_id, TMPFS_SOME_ROOT);
[2c448fb]81}
82
[54e4479]83static int tmpfs_has_children(bool *has_children, fs_node_t *fn)
[2c448fb]84{
[b72efe8]85 *has_children = !list_empty(&TMPFS_NODE(fn)->cs_list);
[54e4479]86 return EOK;
[2c448fb]87}
88
[54e4479]89static fs_index_t tmpfs_index_get(fs_node_t *fn)
[2c448fb]90{
[54e4479]91 return TMPFS_NODE(fn)->index;
[2c448fb]92}
93
[ed903174]94static aoff64_t tmpfs_size_get(fs_node_t *fn)
[2c448fb]95{
[54e4479]96 return TMPFS_NODE(fn)->size;
[2c448fb]97}
98
[54e4479]99static unsigned tmpfs_lnkcnt_get(fs_node_t *fn)
[2c448fb]100{
[54e4479]101 return TMPFS_NODE(fn)->lnkcnt;
[2c448fb]102}
103
[b6035ba]104static bool tmpfs_is_directory(fs_node_t *fn)
[2c448fb]105{
[b6035ba]106 return TMPFS_NODE(fn)->type == TMPFS_DIRECTORY;
[2c448fb]107}
108
[b6035ba]109static bool tmpfs_is_file(fs_node_t *fn)
[2c448fb]110{
[b6035ba]111 return TMPFS_NODE(fn)->type == TMPFS_FILE;
[2c448fb]112}
113
[b33870b]114static service_id_t tmpfs_service_get(fs_node_t *fn)
[1313ee9]115{
116 return 0;
117}
118
[2c448fb]119/** libfs operations */
120libfs_ops_t tmpfs_libfs_ops = {
[54e4479]121 .root_get = tmpfs_root_get,
[2c448fb]122 .match = tmpfs_match,
[a8e9ab8d]123 .node_get = tmpfs_node_get,
[1313ee9]124 .node_open = tmpfs_node_open,
[06901c6b]125 .node_put = tmpfs_node_put,
[2c448fb]126 .create = tmpfs_create_node,
127 .destroy = tmpfs_destroy_node,
128 .link = tmpfs_link_node,
129 .unlink = tmpfs_unlink_node,
[54e4479]130 .has_children = tmpfs_has_children,
[2c448fb]131 .index_get = tmpfs_index_get,
132 .size_get = tmpfs_size_get,
133 .lnkcnt_get = tmpfs_lnkcnt_get,
134 .is_directory = tmpfs_is_directory,
[1313ee9]135 .is_file = tmpfs_is_file,
[b33870b]136 .service_get = tmpfs_service_get
[2c448fb]137};
[fdb7795]138
[cf95bc0]139/** Hash table of all TMPFS nodes. */
140hash_table_t nodes;
[a4eb8a60]141
[e856c34]142#define NODES_KEY_DEV 0
143#define NODES_KEY_INDEX 1
[8d049ee0]144
[cf95bc0]145/* Implementation of hash table interface for the nodes hash table. */
[0ca7286]146static size_t nodes_key_hash(unsigned long key[])
147{
148 /* Based on Effective Java, 2nd Edition. */
149 size_t hash = 17;
150 hash = 37 * hash + key[NODES_KEY_DEV];
151 hash = 37 * hash + key[NODES_KEY_INDEX];
152 return hash;
153}
154
155static size_t nodes_hash(const link_t *item)
[a4eb8a60]156{
[0ca7286]157 tmpfs_node_t *nodep = hash_table_get_instance(item, tmpfs_node_t, nh_link);
158
159 unsigned long key[] = {
160 [NODES_KEY_DEV] = nodep->service_id,
161 [NODES_KEY_INDEX] = nodep->index
162 };
163
164 return nodes_key_hash(key);
[a4eb8a60]165}
166
[0ca7286]167static bool nodes_match(unsigned long key[], size_t keys, const link_t *item)
[a4eb8a60]168{
[cf95bc0]169 tmpfs_node_t *nodep = hash_table_get_instance(item, tmpfs_node_t,
170 nh_link);
[1715b6af]171
172 switch (keys) {
173 case 1:
[15f3c3f]174 return (nodep->service_id == key[NODES_KEY_DEV]);
[1715b6af]175 case 2:
[15f3c3f]176 return ((nodep->service_id == key[NODES_KEY_DEV]) &&
[1715b6af]177 (nodep->index == key[NODES_KEY_INDEX]));
178 default:
[c16013b]179 assert((keys == 1) || (keys == 2));
[1715b6af]180 }
[0055cfd]181
182 return 0;
[a4eb8a60]183}
184
[cf95bc0]185static void nodes_remove_callback(link_t *item)
[a4eb8a60]186{
[9bddf37]187 tmpfs_node_t *nodep = hash_table_get_instance(item, tmpfs_node_t,
188 nh_link);
189
[b72efe8]190 while (!list_empty(&nodep->cs_list)) {
191 tmpfs_dentry_t *dentryp = list_get_instance(
192 list_first(&nodep->cs_list), tmpfs_dentry_t, link);
[9bddf37]193
194 assert(nodep->type == TMPFS_DIRECTORY);
195 list_remove(&dentryp->link);
196 free(dentryp);
197 }
198
199 if (nodep->data) {
200 assert(nodep->type == TMPFS_FILE);
201 free(nodep->data);
202 }
203 free(nodep->bp);
204 free(nodep);
[a4eb8a60]205}
206
[cf95bc0]207/** TMPFS nodes hash table operations. */
[0ca7286]208hash_table_ops_t nodes_ops = {
[cf95bc0]209 .hash = nodes_hash,
[0ca7286]210 .key_hash = nodes_key_hash,
211 .match = nodes_match,
212 .equal = 0,
[cf95bc0]213 .remove_callback = nodes_remove_callback
[a4eb8a60]214};
215
[cf95bc0]216static void tmpfs_node_initialize(tmpfs_node_t *nodep)
[3298ddc]217{
[cf95bc0]218 nodep->bp = NULL;
219 nodep->index = 0;
[15f3c3f]220 nodep->service_id = 0;
[cf95bc0]221 nodep->type = TMPFS_NONE;
222 nodep->lnkcnt = 0;
223 nodep->size = 0;
224 nodep->data = NULL;
225 link_initialize(&nodep->nh_link);
[b72efe8]226 list_initialize(&nodep->cs_list);
[3298ddc]227}
228
[cf95bc0]229static void tmpfs_dentry_initialize(tmpfs_dentry_t *dentryp)
[3298ddc]230{
[cf95bc0]231 link_initialize(&dentryp->link);
232 dentryp->name = NULL;
233 dentryp->node = NULL;
[4b11571]234}
235
[8d049ee0]236bool tmpfs_init(void)
[4b11571]237{
[0ca7286]238 if (!hash_table_create(&nodes, 0, 2, &nodes_ops))
[a4eb8a60]239 return false;
[8d049ee0]240
241 return true;
242}
243
[15f3c3f]244static bool tmpfs_instance_init(service_id_t service_id)
[8d049ee0]245{
[b6035ba]246 fs_node_t *rfn;
[54e4479]247 int rc;
[8d049ee0]248
[15f3c3f]249 rc = tmpfs_create_node(&rfn, service_id, L_DIRECTORY);
[54e4479]250 if (rc != EOK || !rfn)
[3298ddc]251 return false;
[b6035ba]252 TMPFS_NODE(rfn)->lnkcnt = 0; /* FS root is not linked */
[3298ddc]253 return true;
[4b11571]254}
255
[15f3c3f]256static void tmpfs_instance_done(service_id_t service_id)
[e056e820]257{
258 unsigned long key[] = {
[15f3c3f]259 [NODES_KEY_DEV] = service_id
[e056e820]260 };
261 /*
262 * Here we are making use of one special feature of our hash table
263 * implementation, which allows to remove more items based on a partial
264 * key match. In the following, we are going to remove all nodes
265 * matching our device handle. The nodes_remove_callback() function will
266 * take care of resource deallocation.
267 */
268 hash_table_remove(&nodes, key, 1);
269}
270
[54e4479]271int tmpfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
[736c164]272{
[cf95bc0]273 tmpfs_node_t *parentp = TMPFS_NODE(pfn);
[736c164]274
[b72efe8]275 list_foreach(parentp->cs_list, lnk) {
[54e4479]276 tmpfs_dentry_t *dentryp;
277 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
278 if (!str_cmp(dentryp->name, component)) {
279 *rfn = FS_NODE(dentryp->node);
280 return EOK;
281 }
[cf95bc0]282 }
[736c164]283
[54e4479]284 *rfn = NULL;
285 return EOK;
[736c164]286}
287
[15f3c3f]288int tmpfs_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index)
[a8e9ab8d]289{
[8d049ee0]290 unsigned long key[] = {
[15f3c3f]291 [NODES_KEY_DEV] = service_id,
[e856c34]292 [NODES_KEY_INDEX] = index
[8d049ee0]293 };
[cf95bc0]294 link_t *lnk = hash_table_find(&nodes, key);
[54e4479]295 if (lnk) {
296 tmpfs_node_t *nodep;
297 nodep = hash_table_get_instance(lnk, tmpfs_node_t, nh_link);
298 *rfn = FS_NODE(nodep);
299 } else {
300 *rfn = NULL;
301 }
302 return EOK;
[a8e9ab8d]303}
304
[1313ee9]305int tmpfs_node_open(fs_node_t *fn)
306{
307 /* nothing to do */
308 return EOK;
309}
310
[54e4479]311int tmpfs_node_put(fs_node_t *fn)
[06901c6b]312{
313 /* nothing to do */
[54e4479]314 return EOK;
[06901c6b]315}
316
[15f3c3f]317int tmpfs_create_node(fs_node_t **rfn, service_id_t service_id, int lflag)
[b8b23c8]318{
[54e4479]319 fs_node_t *rootfn;
320 int rc;
321
[72bde81]322 assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
323
[cf95bc0]324 tmpfs_node_t *nodep = malloc(sizeof(tmpfs_node_t));
325 if (!nodep)
[54e4479]326 return ENOMEM;
[cf95bc0]327 tmpfs_node_initialize(nodep);
328 nodep->bp = malloc(sizeof(fs_node_t));
329 if (!nodep->bp) {
330 free(nodep);
[54e4479]331 return ENOMEM;
[3298ddc]332 }
[83937ccd]333 fs_node_initialize(nodep->bp);
[cf95bc0]334 nodep->bp->data = nodep; /* link the FS and TMPFS nodes */
[54e4479]335
[15f3c3f]336 rc = tmpfs_root_get(&rootfn, service_id);
[54e4479]337 assert(rc == EOK);
338 if (!rootfn)
[cf95bc0]339 nodep->index = TMPFS_SOME_ROOT;
[8d049ee0]340 else
[cf95bc0]341 nodep->index = tmpfs_next_index++;
[15f3c3f]342 nodep->service_id = service_id;
[72bde81]343 if (lflag & L_DIRECTORY)
[cf95bc0]344 nodep->type = TMPFS_DIRECTORY;
[72bde81]345 else
[cf95bc0]346 nodep->type = TMPFS_FILE;
[72bde81]347
[cf95bc0]348 /* Insert the new node into the nodes hash table. */
[0ca7286]349 hash_table_insert(&nodes, &nodep->nh_link);
[54e4479]350 *rfn = FS_NODE(nodep);
351 return EOK;
352}
353
354int tmpfs_destroy_node(fs_node_t *fn)
355{
356 tmpfs_node_t *nodep = TMPFS_NODE(fn);
357
358 assert(!nodep->lnkcnt);
[b72efe8]359 assert(list_empty(&nodep->cs_list));
[54e4479]360
361 unsigned long key[] = {
[15f3c3f]362 [NODES_KEY_DEV] = nodep->service_id,
[e856c34]363 [NODES_KEY_INDEX] = nodep->index
[54e4479]364 };
365 hash_table_remove(&nodes, key, 2);
366
[9bddf37]367 /*
368 * The nodes_remove_callback() function takes care of the actual
369 * resource deallocation.
370 */
[54e4479]371 return EOK;
[fdb7795]372}
373
[b6035ba]374int tmpfs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
[fdb7795]375{
[cf95bc0]376 tmpfs_node_t *parentp = TMPFS_NODE(pfn);
377 tmpfs_node_t *childp = TMPFS_NODE(cfn);
378 tmpfs_dentry_t *dentryp;
[fdb7795]379
380 assert(parentp->type == TMPFS_DIRECTORY);
381
[cf95bc0]382 /* Check for duplicit entries. */
[b72efe8]383 list_foreach(parentp->cs_list, lnk) {
[cf95bc0]384 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
385 if (!str_cmp(dentryp->name, nm))
386 return EEXIST;
387 }
388
389 /* Allocate and initialize the dentry. */
390 dentryp = malloc(sizeof(tmpfs_dentry_t));
391 if (!dentryp)
[0013b9ce]392 return ENOMEM;
[cf95bc0]393 tmpfs_dentry_initialize(dentryp);
394
395 /* Populate and link the new dentry. */
[92fd52d7]396 size_t size = str_size(nm);
[cf95bc0]397 dentryp->name = malloc(size + 1);
398 if (!dentryp->name) {
399 free(dentryp);
[0013b9ce]400 return ENOMEM;
[3298ddc]401 }
[cf95bc0]402 str_cpy(dentryp->name, size + 1, nm);
403 dentryp->node = childp;
[adc8a63]404 childp->lnkcnt++;
[b72efe8]405 list_append(&dentryp->link, &parentp->cs_list);
[72bde81]406
[0013b9ce]407 return EOK;
[b8b23c8]408}
[4b11571]409
[cf95bc0]410int tmpfs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
[b8b23c8]411{
[cf95bc0]412 tmpfs_node_t *parentp = TMPFS_NODE(pfn);
413 tmpfs_node_t *childp = NULL;
414 tmpfs_dentry_t *dentryp;
[16105cba]415
[7b6d98b]416 if (!parentp)
[16105cba]417 return EBUSY;
[cf95bc0]418
[b72efe8]419 list_foreach(parentp->cs_list, lnk) {
[cf95bc0]420 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
421 if (!str_cmp(dentryp->name, nm)) {
422 childp = dentryp->node;
423 assert(FS_NODE(childp) == cfn);
424 break;
[b72efe8]425 }
[16105cba]426 }
427
[cf95bc0]428 if (!childp)
429 return ENOENT;
430
[b72efe8]431 if ((childp->lnkcnt == 1) && !list_empty(&childp->cs_list))
[cf95bc0]432 return ENOTEMPTY;
[fdb7795]433
[cf95bc0]434 list_remove(&dentryp->link);
435 free(dentryp);
[7b6d98b]436 childp->lnkcnt--;
[adc8a63]437
[16105cba]438 return EOK;
[d5cdffe]439}
440
[efcebe1]441/*
442 * Implementation of the VFS_OUT interface.
443 */
444
445static int
[86ffa27f]446tmpfs_mounted(service_id_t service_id, const char *opts,
[efcebe1]447 fs_index_t *index, aoff64_t *size, unsigned *lnkcnt)
[64b67c3]448{
[fc2e71e]449 fs_node_t *rootfn;
[54e4479]450 int rc;
[472c09d]451
[d42976c]452 /* Check if this device is not already mounted. */
[15f3c3f]453 rc = tmpfs_root_get(&rootfn, service_id);
[fc2e71e]454 if ((rc == EOK) && (rootfn)) {
[0055cfd]455 (void) tmpfs_node_put(rootfn);
[efcebe1]456 return EEXIST;
[fc2e71e]457 }
458
[8d049ee0]459 /* Initialize TMPFS instance. */
[86ffa27f]460 if (!tmpfs_instance_init(service_id))
[efcebe1]461 return ENOMEM;
[f49b0ea]462
[15f3c3f]463 rc = tmpfs_root_get(&rootfn, service_id);
[54e4479]464 assert(rc == EOK);
465 tmpfs_node_t *rootp = TMPFS_NODE(rootfn);
[594303b]466 if (str_cmp(opts, "restore") == 0) {
[86ffa27f]467 if (!tmpfs_restore(service_id))
[efcebe1]468 return ELIMIT;
[f49b0ea]469 }
470
[efcebe1]471 *index = rootp->index;
472 *size = rootp->size;
473 *lnkcnt = rootp->lnkcnt;
[e056e820]474
[efcebe1]475 return EOK;
[3c11713]476}
477
[86ffa27f]478static int tmpfs_unmounted(service_id_t service_id)
[f49b0ea]479{
[86ffa27f]480 tmpfs_instance_done(service_id);
[efcebe1]481 return EOK;
[d5cdffe]482}
483
[86ffa27f]484static int tmpfs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
[efcebe1]485 size_t *rbytes)
[a4eb8a60]486{
487 /*
[cf95bc0]488 * Lookup the respective TMPFS node.
[a4eb8a60]489 */
490 link_t *hlp;
[8d049ee0]491 unsigned long key[] = {
[15f3c3f]492 [NODES_KEY_DEV] = service_id,
[e856c34]493 [NODES_KEY_INDEX] = index
[8d049ee0]494 };
[cf95bc0]495 hlp = hash_table_find(&nodes, key);
[efcebe1]496 if (!hlp)
497 return ENOENT;
[cf95bc0]498 tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
499 nh_link);
[ed903174]500
[a4eb8a60]501 /*
[a92da0a]502 * Receive the read request.
[a4eb8a60]503 */
504 ipc_callid_t callid;
[92fd52d7]505 size_t size;
[0da4e41]506 if (!async_data_read_receive(&callid, &size)) {
[ffa2c8ef]507 async_answer_0(callid, EINVAL);
[efcebe1]508 return EINVAL;
[a4eb8a60]509 }
510
[5973fd0]511 size_t bytes;
[cf95bc0]512 if (nodep->type == TMPFS_FILE) {
[ed903174]513 bytes = min(nodep->size - pos, size);
[0da4e41]514 (void) async_data_read_finalize(callid, nodep->data + pos,
[5973fd0]515 bytes);
516 } else {
[cf95bc0]517 tmpfs_dentry_t *dentryp;
518 link_t *lnk;
[5973fd0]519
[cf95bc0]520 assert(nodep->type == TMPFS_DIRECTORY);
[5973fd0]521
522 /*
523 * Yes, we really use O(n) algorithm here.
524 * If it bothers someone, it could be fixed by introducing a
525 * hash table.
526 */
[b72efe8]527 lnk = list_nth(&nodep->cs_list, pos);
528
529 if (lnk == NULL) {
[ffa2c8ef]530 async_answer_0(callid, ENOENT);
[efcebe1]531 return ENOENT;
[5973fd0]532 }
533
[cf95bc0]534 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
[3298ddc]535
[0da4e41]536 (void) async_data_read_finalize(callid, dentryp->name,
[cf95bc0]537 str_size(dentryp->name) + 1);
[5973fd0]538 bytes = 1;
539 }
[7dab6b8]540
[efcebe1]541 *rbytes = bytes;
542 return EOK;
[a4eb8a60]543}
544
[efcebe1]545static int
[86ffa27f]546tmpfs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
[efcebe1]547 size_t *wbytes, aoff64_t *nsize)
[ee1b8ca]548{
549 /*
[cf95bc0]550 * Lookup the respective TMPFS node.
[ee1b8ca]551 */
552 link_t *hlp;
[8d049ee0]553 unsigned long key[] = {
[15f3c3f]554 [NODES_KEY_DEV] = service_id,
[e856c34]555 [NODES_KEY_INDEX] = index
[8d049ee0]556 };
[cf95bc0]557 hlp = hash_table_find(&nodes, key);
[efcebe1]558 if (!hlp)
559 return ENOENT;
[cf95bc0]560 tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
561 nh_link);
[ee1b8ca]562
563 /*
564 * Receive the write request.
565 */
566 ipc_callid_t callid;
[92fd52d7]567 size_t size;
[0da4e41]568 if (!async_data_write_receive(&callid, &size)) {
[ffa2c8ef]569 async_answer_0(callid, EINVAL);
[efcebe1]570 return EINVAL;
[ee1b8ca]571 }
572
[c1bf5cb]573 /*
574 * Check whether the file needs to grow.
575 */
[cf95bc0]576 if (pos + size <= nodep->size) {
[c1bf5cb]577 /* The file size is not changing. */
[efcebe1]578 (void) async_data_write_finalize(callid, nodep->data + pos,
579 size);
580 goto out;
[c1bf5cb]581 }
[cf95bc0]582 size_t delta = (pos + size) - nodep->size;
[ee1b8ca]583 /*
584 * At this point, we are deliberately extremely straightforward and
[c1bf5cb]585 * simply realloc the contents of the file on every write that grows the
586 * file. In the end, the situation might not be as bad as it may look:
587 * our heap allocator can save us and just grow the block whenever
588 * possible.
[ee1b8ca]589 */
[cf95bc0]590 void *newdata = realloc(nodep->data, nodep->size + delta);
[ee1b8ca]591 if (!newdata) {
[ffa2c8ef]592 async_answer_0(callid, ENOMEM);
[efcebe1]593 size = 0;
594 goto out;
[ee1b8ca]595 }
[0ee4322]596 /* Clear any newly allocated memory in order to emulate gaps. */
[cf95bc0]597 memset(newdata + nodep->size, 0, delta);
598 nodep->size += delta;
599 nodep->data = newdata;
[0da4e41]600 (void) async_data_write_finalize(callid, nodep->data + pos, size);
[efcebe1]601
602out:
603 *wbytes = size;
604 *nsize = nodep->size;
605 return EOK;
[ee1b8ca]606}
607
[86ffa27f]608static int tmpfs_truncate(service_id_t service_id, fs_index_t index,
[efcebe1]609 aoff64_t size)
[0ee4322]610{
611 /*
[cf95bc0]612 * Lookup the respective TMPFS node.
[0ee4322]613 */
[8d049ee0]614 unsigned long key[] = {
[15f3c3f]615 [NODES_KEY_DEV] = service_id,
[e856c34]616 [NODES_KEY_INDEX] = index
[8d049ee0]617 };
[ed903174]618 link_t *hlp = hash_table_find(&nodes, key);
[efcebe1]619 if (!hlp)
620 return ENOENT;
621 tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t, nh_link);
[ed903174]622
[efcebe1]623 if (size == nodep->size)
624 return EOK;
[ed903174]625
[efcebe1]626 if (size > SIZE_MAX)
627 return ENOMEM;
[ed903174]628
[cf95bc0]629 void *newdata = realloc(nodep->data, size);
[efcebe1]630 if (!newdata)
631 return ENOMEM;
[ed903174]632
[cf95bc0]633 if (size > nodep->size) {
634 size_t delta = size - nodep->size;
635 memset(newdata + nodep->size, 0, delta);
[0ee4322]636 }
[ed903174]637
[cf95bc0]638 nodep->size = size;
639 nodep->data = newdata;
[efcebe1]640 return EOK;
[0ee4322]641}
642
[86ffa27f]643static int tmpfs_close(service_id_t service_id, fs_index_t index)
[c20aa06]644{
[efcebe1]645 return EOK;
[c20aa06]646}
647
[86ffa27f]648static int tmpfs_destroy(service_id_t service_id, fs_index_t index)
[f17667a]649{
650 link_t *hlp;
[8d049ee0]651 unsigned long key[] = {
[15f3c3f]652 [NODES_KEY_DEV] = service_id,
[e856c34]653 [NODES_KEY_INDEX] = index
[8d049ee0]654 };
[cf95bc0]655 hlp = hash_table_find(&nodes, key);
[efcebe1]656 if (!hlp)
657 return ENOENT;
[cf95bc0]658 tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
659 nh_link);
[efcebe1]660 return tmpfs_destroy_node(FS_NODE(nodep));
[c20aa06]661}
662
[86ffa27f]663static int tmpfs_sync(service_id_t service_id, fs_index_t index)
[c20aa06]664{
[69a60c4]665 /*
666 * TMPFS keeps its data structures always consistent,
667 * thus the sync operation is a no-op.
668 */
[efcebe1]669 return EOK;
[c20aa06]670}
671
[efcebe1]672vfs_out_ops_t tmpfs_ops = {
673 .mounted = tmpfs_mounted,
674 .unmounted = tmpfs_unmounted,
675 .read = tmpfs_read,
676 .write = tmpfs_write,
677 .truncate = tmpfs_truncate,
678 .close = tmpfs_close,
679 .destroy = tmpfs_destroy,
680 .sync = tmpfs_sync,
681};
682
[d5cdffe]683/**
684 * @}
[c20aa06]685 */
[efcebe1]686
Note: See TracBrowser for help on using the repository browser.