Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2592 → Rev 2593

/trunk/uspace/srv/vfs/vfs.c
100,6 → 100,8
case VFS_READ:
case VFS_WRITE:
case VFS_SEEK:
case VFS_UNLINK:
case VFS_RENAME:
default:
ipc_answer_fast_0(callid, ENOTSUP);
break;
/trunk/uspace/srv/vfs/vfs_unlink.c
0,0 → 1,49
/*
* Copyright (c) 2007 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup fs
* @{
*/
 
/**
* @file vfs_unlink.c
* @brief
*/
 
#include <atomic.h>
#include <futex.h>
 
/**
* This futex serializes concurrent VFS_CREATE, VFS_OPEN and VFS_UNLINK
* operations.
*/
atomic_t unlink_futex = FUTEX_INITIALIZER;
 
/**
* @}
*/
/trunk/uspace/srv/vfs/vfs_open.c
38,58 → 38,14
#include <ipc/ipc.h>
#include <async.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <bool.h>
#include <futex.h>
#include <libadt/list.h>
#include <sys/types.h>
#include <stdlib.h>
#include "vfs.h"
 
/** Per-connection futex protecting the files array. */
__thread atomic_t files_futex = FUTEX_INITIALIZER;
 
/**
* This is a per-connection table of open files.
* Our assumption is that each client opens only one connection and therefore
* there is one table of open files per task. However, this may not be the case
* and the client can open more connections to VFS. In that case, there will be
* several tables and several file handle name spaces per task. Besides of this,
* the functionality will stay unchanged. So unless the client knows what it is
* doing, it should open one connection to VFS only.
*
* Allocation of the open files table is deferred until the client makes the
* first VFS_OPEN operation.
*/
__thread vfs_file_t *files = NULL;
 
/** Initialize the table of open files. */
static bool vfs_conn_open_files_init(void)
{
/*
* Optimized fast path that will never go to sleep unnecessarily.
* The assumption is that once files is non-zero, it will never be zero
* again.
*/
if (files)
return true;
futex_down(&files_futex);
if (!files) {
files = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t));
if (!files) {
futex_up(&files_futex);
return false;
}
memset(files, 0, MAX_OPEN_FILES * sizeof(vfs_file_t));
}
futex_up(&files_futex);
return true;
}
 
void vfs_open(ipc_callid_t rid, ipc_call_t *request)
{
if (!vfs_conn_open_files_init()) {
if (!vfs_files_init()) {
ipc_answer_fast_0(rid, ENOMEM);
return;
}
127,7 → 83,7
}
 
int rc;
if (rc = ipc_data_deliver(callid, &call, path, size)) {
if ((rc = ipc_data_deliver(callid, &call, path, size))) {
ipc_answer_fast_0(rid, rc);
free(path);
return;
134,11 → 90,19
}
/*
* Avoid the race condition in which the file can be deleted before we
* find/create-and-lock the VFS node corresponding to the looked-up
* triplet.
*/
futex_down(&unlink_futex);
 
/*
* The path is now populated and we can call vfs_lookup_internal().
*/
vfs_triplet_t triplet;
rc = vfs_lookup_internal(path, size, &triplet, NULL);
if (rc) {
futex_up(&unlink_futex);
ipc_answer_fast_0(rid, rc);
free(path);
return;
150,7 → 114,35
free(path);
 
vfs_node_t *node = vfs_node_get(&triplet);
// TODO: not finished
futex_up(&unlink_futex);
 
/*
* Get ourselves a file descriptor and the corresponding vfs_file_t
* structure.
*/
int fd = vfs_fd_alloc();
if (fd < 0) {
vfs_node_put(node);
ipc_answer_fast_0(rid, fd);
return;
}
vfs_file_t *file = vfs_file_get(fd);
file->node = node;
 
/*
* The following increase in reference count is for the fact that the
* file is being opened and that a file structure is pointing to it.
* It is necessary so that the file will not disappear when
* vfs_node_put() is called. The reference will be dropped by the
* respective VFS_CLOSE.
*/
vfs_node_addref(node);
vfs_node_put(node);
 
/*
* Success! Return the new file descriptor to the client.
*/
ipc_answer_fast_1(rid, EOK, fd);
}
 
/**
/trunk/uspace/srv/vfs/vfs.h
56,6 → 56,8
VFS_READ,
VFS_WRITE,
VFS_SEEK,
VFS_RENAME,
VFS_UNLINK,
VFS_LAST, /* keep this the last member of the enum */
} vfs_request_t;
 
130,7 → 132,8
*/
typedef struct {
VFS_TRIPLET; /**< Identity of the node. */
atomic_t refcnt; /**< Usage counter. */
unsigned refcnt; /**< Usage counter. */
link_t nh_link; /**< Node hash-table link. */
} vfs_node_t;
 
/**
141,7 → 144,7
vfs_node_t *node;
/** Number of file handles referencing this file. */
atomic_t refcnt;
unsigned refcnt;
 
/** Current position in the file. */
off_t pos;
166,6 → 169,8
extern uint8_t *plb; /**< Path Lookup Buffer */
extern link_t plb_head; /**< List of active PLB entries. */
 
extern atomic_t unlink_futex; /**< VFS_{CREATE|OPEN|UNLINK} serialization. */
 
extern int vfs_grab_phone(int);
extern void vfs_release_phone(int);
 
172,8 → 177,22
extern int fs_name_to_handle(char *, bool);
 
extern int vfs_lookup_internal(char *, size_t, vfs_triplet_t *, vfs_pair_t *);
 
 
extern vfs_node_t *vfs_node_get(vfs_triplet_t *);
extern void vfs_node_put(vfs_node_t *);
 
extern bool vfs_files_init(void);
extern vfs_file_t *vfs_file_get(int);
extern int vfs_fd_alloc(void);
extern void vfs_fd_free(int);
 
extern void vfs_file_addref(vfs_file_t *);
extern void vfs_file_delref(vfs_file_t *);
 
extern void vfs_node_addref(vfs_node_t *);
extern void vfs_node_delref(vfs_node_t *);
 
#define MAX_OPEN_FILES 128
 
extern void vfs_register(ipc_callid_t, ipc_call_t *);
/trunk/uspace/srv/vfs/vfs_node.c
37,11 → 37,57
 
#include "vfs.h"
 
/** Increment reference count of a VFS node.
*
* @param node VFS node that will have its refcnt incremented.
*/
void vfs_node_addref(vfs_node_t *node)
{
/* TODO */
}
 
/** Decrement reference count of a VFS node.
*
* This function handles the case when the reference count drops to zero.
*
* @param node VFS node that will have its refcnt decremented.
*/
void vfs_node_delref(vfs_node_t *node)
{
/* TODO */
}
 
/** Find VFS node.
*
* This function will try to lookup the given triplet in the VFS node hash
* table. In case the triplet is not found there, a new VFS node is created.
* In any case, the VFS node will have its reference count incremented. Every
* node returned by this call should be eventually put back by calling
* vfs_node_put() on it.
*
* @param triplet Triplet encoding the identity of the VFS node.
*
* @return VFS node corresponding to the given triplet.
*/
vfs_node_t *vfs_node_get(vfs_triplet_t *triplet)
{
return NULL; // TODO: not implemented
/* TODO */
return NULL;
}
 
/** Return VFS node when no longer needed by the caller.
*
* This function will remove the reference on the VFS node created by
* vfs_node_get(). This function can only be called as a closing bracket to the
* preceding vfs_node_get() call.
*
* @param node VFS node being released.
*/
void vfs_node_put(vfs_node_t *node)
{
vfs_node_delref(node);
}
 
/**
* @}
*/
/trunk/uspace/srv/vfs/Makefile
43,10 → 43,12
SOURCES = \
vfs.c \
vfs_node.c \
vfs_file.c \
vfs_register.c \
vfs_lookup.c \
vfs_mount.c \
vfs_open.c
vfs_open.c \
vfs_unlink.c
 
OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
 
/trunk/uspace/srv/vfs/vfs_file.c
0,0 → 1,152
/*
* Copyright (c) 2007 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/** @addtogroup fs
* @{
*/
 
/**
* @file vfs_file.c
* @brief Various operations on files have their home in this file.
*/
 
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <bool.h>
#include "vfs.h"
 
/**
* This is a per-connection table of open files.
* Our assumption is that each client opens only one connection and therefore
* there is one table of open files per task. However, this may not be the case
* and the client can open more connections to VFS. In that case, there will be
* several tables and several file handle name spaces per task. Besides of this,
* the functionality will stay unchanged. So unless the client knows what it is
* doing, it should open one connection to VFS only.
*
* Allocation of the open files table is deferred until the client makes the
* first VFS_OPEN operation.
*
* This resource being per-connection and, in the first place, per-fibril, we
* don't need to protect it by a futex.
*/
__thread vfs_file_t **files = NULL;
 
/** Initialize the table of open files. */
bool vfs_files_init(void)
{
if (!files) {
files = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *));
if (!files)
return false;
memset(files, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
}
return true;
}
 
/** Allocate a file descriptor.
*
* @return First available file descriptor or a negative error
* code.
*/
int vfs_fd_alloc(void)
{
int i;
 
for (i = 0; i < MAX_OPEN_FILES; i++) {
if (!files[i]) {
files[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
if (!files[i])
return ENOMEM;
memset(files[i], 0, sizeof(vfs_file_t));
vfs_file_addref(files[i]);
return i;
}
}
return EMFILE;
}
 
/** Release file descriptor.
*
* @param fd File descriptor being released.
*/
void vfs_fd_free(int fd)
{
assert(files[fd] != NULL);
vfs_file_delref(files[fd]);
files[fd] = NULL;
}
 
/** Increment reference count of VFS file structure.
*
* @param file File structure that will have reference count
* incremented.
*/
void vfs_file_addref(vfs_file_t *file)
{
/*
* File structures are per-connection, so no-one, except the current
* fibril, should have a reference to them. This is the reason we don't
* do any synchronization here.
*/
file->refcnt++;
}
 
/** Decrement reference count of VFS file structure.
*
* @param file File structure that will have reference count
* decremented.
*/
void vfs_file_delref(vfs_file_t *file)
{
if (file->refcnt-- == 1) {
/*
* Lost last reference to a file, need to drop our reference
* to the underlying VFS node.
*/
vfs_node_delref(file->node);
free(file);
}
}
 
/** Find VFS file structure for a given file descriptor.
*
* @param fd File descriptor.
*
* @return VFS file structure corresponding to fd.
*/
vfs_file_t *vfs_file_get(int fd)
{
return files[fd];
}
 
/**
* @}
*/