Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 4580 → Rev 4581

/branches/network/uspace/srv/vfs/vfs.c
43,7 → 43,6
#include <bool.h>
#include <string.h>
#include <as.h>
#include <libadt/list.h>
#include <atomic.h>
#include "vfs.h"
 
52,7 → 51,7
static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall)
{
bool keep_on_going = true;
 
/*
* The connection was opened via the IPC_CONNECT_ME_TO call.
* This call needs to be answered.
80,28 → 79,9
case IPC_M_PHONE_HUNGUP:
keep_on_going = false;
break;
case IPC_M_CONNECT_ME_TO:
/*
* Connect the client file system to another one.
*/
/* FIXME:
* Prevent ordinary clients from connecting to file
* system servers directly. This should be solved by
* applying some security mechanisms.
*/
fs_handle = IPC_GET_ARG1(call);
phone = vfs_grab_phone(fs_handle);
(void) ipc_forward_fast(callid, phone, 0, 0, 0,
IPC_FF_NONE);
vfs_release_phone(phone);
break;
case VFS_REGISTER:
vfs_register(callid, &call);
/*
* Keep the connection open so that a file system can
* later ask us to connect it to another file system.
* This is necessary to support non-root mounts.
*/
keep_on_going = false;
break;
case VFS_MOUNT:
vfs_mount(callid, &call);
109,6 → 89,9
case VFS_OPEN:
vfs_open(callid, &call);
break;
case VFS_OPEN_NODE:
vfs_open_node(callid, &call);
break;
case VFS_CLOSE:
vfs_close(callid, &call);
break;
133,6 → 116,15
case VFS_RENAME:
vfs_rename(callid, &call);
break;
case VFS_DEVICE:
vfs_device(callid, &call);
break;
case VFS_SYNC:
vfs_sync(callid, &call);
break;
case VFS_NODE:
vfs_node(callid, &call);
break;
default:
ipc_answer_0(callid, ENOTSUP);
break;
147,11 → 139,6
printf(NAME ": HelenOS VFS server\n");
/*
* Initialize the list of registered file systems.
*/
list_initialize(&fs_head);
/*
* Initialize VFS node hash table.
*/
if (!vfs_nodes_init()) {
162,7 → 149,6
/*
* Allocate and initialize the Path Lookup Buffer.
*/
list_initialize(&plb_head);
plb = as_get_mappable_page(PLB_SIZE);
if (!plb) {
printf(NAME ": Cannot allocate a mappable piece of address space\n");
177,10 → 163,10
memset(plb, 0, PLB_SIZE);
/*
* Set a connectio handling function/fibril.
* Set a connection handling function/fibril.
*/
async_set_client_connection(vfs_connection);
 
/*
* Register at the naming service.
*/
/branches/network/uspace/srv/vfs/vfs_ops.c
43,9 → 43,8
#include <stdlib.h>
#include <string.h>
#include <bool.h>
#include <futex.h>
#include <rwlock.h>
#include <libadt/list.h>
#include <fibril_sync.h>
#include <adt/list.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
55,26 → 54,12
/* Forward declarations of static functions. */
static int vfs_truncate_internal(fs_handle_t, dev_handle_t, fs_index_t, size_t);
 
/** Pending mount structure. */
typedef struct {
link_t link;
char *fs_name; /**< File system name */
char *mp; /**< Mount point */
char *opts; /**< Mount options. */
ipc_callid_t callid; /**< Call ID waiting for the mount */
ipc_callid_t rid; /**< Request ID */
dev_handle_t dev_handle; /**< Device handle */
} pending_req_t;
 
LIST_INITIALIZE(pending_req);
 
/**
* This rwlock prevents the race between a triplet-to-VFS-node resolution and a
* concurrent VFS operation which modifies the file system namespace.
*/
RWLOCK_INITIALIZE(namespace_rwlock);
FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock);
 
futex_t rootfs_futex = FUTEX_INITIALIZER;
vfs_pair_t rootfs = {
.fs_handle = 0,
.dev_handle = 0
84,21 → 69,24
fs_handle_t fs_handle, char *mp, char *opts)
{
vfs_lookup_res_t mp_res;
vfs_lookup_res_t mr_res;
vfs_node_t *mp_node = NULL;
vfs_node_t *mr_node;
fs_index_t rindex;
size_t rsize;
unsigned rlnkcnt;
ipcarg_t rc;
int phone;
aid_t msg;
ipc_call_t answer;
 
/* Resolve the path to the mountpoint. */
futex_down(&rootfs_futex);
fibril_rwlock_write_lock(&namespace_rwlock);
if (rootfs.fs_handle) {
/* We already have the root FS. */
rwlock_write_lock(&namespace_rwlock);
if (str_cmp(mp, "/") == 0) {
/* Trying to mount root FS over root FS */
rwlock_write_unlock(&namespace_rwlock);
futex_up(&rootfs_futex);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, EBUSY);
return;
}
106,8 → 94,7
rc = vfs_lookup_internal(mp, L_DIRECTORY, &mp_res, NULL);
if (rc != EOK) {
/* The lookup failed for some reason. */
rwlock_write_unlock(&namespace_rwlock);
futex_up(&rootfs_futex);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, rc);
return;
}
114,8 → 101,7
mp_node = vfs_node_get(&mp_res);
if (!mp_node) {
rwlock_write_unlock(&namespace_rwlock);
futex_up(&rootfs_futex);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, ENOMEM);
return;
}
125,16 → 111,9
* It will be dropped upon the corresponding VFS_UNMOUNT.
* This prevents the mount point from being deleted.
*/
rwlock_write_unlock(&namespace_rwlock);
} else {
/* We still don't have the root file system mounted. */
if (str_cmp(mp, "/") == 0) {
vfs_lookup_res_t mr_res;
vfs_node_t *mr_node;
fs_index_t rindex;
size_t rsize;
unsigned rlnkcnt;
/*
* For this simple, but important case,
* we are almost done.
150,7 → 129,7
if (rc != EOK) {
async_wait_for(msg, NULL);
vfs_release_phone(phone);
futex_up(&rootfs_futex);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, rc);
return;
}
158,7 → 137,7
vfs_release_phone(phone);
if (rc != EOK) {
futex_up(&rootfs_futex);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, rc);
return;
}
176,12 → 155,12
rootfs.fs_handle = fs_handle;
rootfs.dev_handle = dev_handle;
futex_up(&rootfs_futex);
/* Add reference to the mounted root. */
mr_node = vfs_node_get(&mr_res);
assert(mr_node);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, rc);
return;
} else {
189,12 → 168,11
* We can't resolve this without the root filesystem
* being mounted first.
*/
futex_up(&rootfs_futex);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, ENOENT);
return;
}
}
futex_up(&rootfs_futex);
/*
* At this point, we have all necessary pieces: file system and device
201,6 → 179,9
* handles, and we know the mount point VFS node.
*/
int mountee_phone = vfs_grab_phone(fs_handle);
assert(mountee_phone >= 0);
 
phone = vfs_grab_phone(mp_res.triplet.fs_handle);
msg = async_send_4(phone, VFS_MOUNT,
(ipcarg_t) mp_res.triplet.dev_handle,
207,6 → 188,23
(ipcarg_t) mp_res.triplet.index,
(ipcarg_t) fs_handle,
(ipcarg_t) dev_handle, &answer);
/* send connection */
rc = async_req_1_0(phone, IPC_M_CONNECTION_CLONE, mountee_phone);
if (rc != EOK) {
async_wait_for(msg, NULL);
vfs_release_phone(mountee_phone);
vfs_release_phone(phone);
/* Mount failed, drop reference to mp_node. */
if (mp_node)
vfs_node_put(mp_node);
ipc_answer_0(rid, rc);
fibril_rwlock_write_unlock(&namespace_rwlock);
return;
}
 
vfs_release_phone(mountee_phone);
/* send the mount options */
rc = ipc_data_write_start(phone, (void *)opts, str_size(opts));
if (rc != EOK) {
215,6 → 213,7
/* Mount failed, drop reference to mp_node. */
if (mp_node)
vfs_node_put(mp_node);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, rc);
return;
}
221,44 → 220,31
async_wait_for(msg, &rc);
vfs_release_phone(phone);
if (rc != EOK) {
if (rc == EOK) {
rindex = (fs_index_t) IPC_GET_ARG1(answer);
rsize = (size_t) IPC_GET_ARG2(answer);
rlnkcnt = (unsigned) IPC_GET_ARG3(answer);
mr_res.triplet.fs_handle = fs_handle;
mr_res.triplet.dev_handle = dev_handle;
mr_res.triplet.index = rindex;
mr_res.size = rsize;
mr_res.lnkcnt = rlnkcnt;
mr_res.type = VFS_NODE_DIRECTORY;
/* Add reference to the mounted root. */
mr_node = vfs_node_get(&mr_res);
assert(mr_node);
} else {
/* Mount failed, drop reference to mp_node. */
if (mp_node)
vfs_node_put(mp_node);
}
 
ipc_answer_0(rid, rc);
fibril_rwlock_write_unlock(&namespace_rwlock);
}
 
/** Process pending mount requests */
void vfs_process_pending_mount()
{
link_t *cur;
loop:
for (cur = pending_req.next; cur != &pending_req; cur = cur->next) {
pending_req_t *pr = list_get_instance(cur, pending_req_t, link);
fs_handle_t fs_handle = fs_name_to_handle(pr->fs_name, true);
if (!fs_handle)
continue;
/* Acknowledge that we know fs_name. */
ipc_answer_0(pr->callid, EOK);
/* Do the mount */
vfs_mount_internal(pr->rid, pr->dev_handle, fs_handle, pr->mp,
pr->opts);
free(pr->fs_name);
free(pr->mp);
free(pr->opts);
list_remove(cur);
free(pr);
goto loop;
}
}
 
void vfs_mount(ipc_callid_t rid, ipc_call_t *request)
{
/*
412,33 → 398,17
* Check if we know a file system with the same name as is in fs_name.
* This will also give us its file system handle.
*/
fs_handle_t fs_handle = fs_name_to_handle(fs_name, true);
fibril_mutex_lock(&fs_head_lock);
fs_handle_t fs_handle;
recheck:
fs_handle = fs_name_to_handle(fs_name, false);
if (!fs_handle) {
if (flags & IPC_FLAG_BLOCKING) {
pending_req_t *pr;
 
/* Blocking mount, add to pending list */
pr = (pending_req_t *) malloc(sizeof(pending_req_t));
if (!pr) {
ipc_answer_0(callid, ENOMEM);
ipc_answer_0(rid, ENOMEM);
free(mp);
free(fs_name);
free(opts);
return;
}
pr->fs_name = fs_name;
pr->mp = mp;
pr->opts = opts;
pr->callid = callid;
pr->rid = rid;
pr->dev_handle = dev_handle;
link_initialize(&pr->link);
list_append(&pr->link, &pending_req);
return;
fibril_condvar_wait(&fs_head_cv, &fs_head_lock);
goto recheck;
}
fibril_mutex_unlock(&fs_head_lock);
ipc_answer_0(callid, ENOENT);
ipc_answer_0(rid, ENOENT);
free(mp);
446,6 → 416,7
free(opts);
return;
}
fibril_mutex_unlock(&fs_head_lock);
/* Acknowledge that we know fs_name. */
ipc_answer_0(callid, EOK);
463,7 → 434,7
ipc_answer_0(rid, ENOMEM);
return;
}
 
/*
* The POSIX interface is open(path, oflag, mode).
* We can receive oflags and mode along with the VFS_OPEN call; the path
476,29 → 447,30
int oflag = IPC_GET_ARG2(*request);
int mode = IPC_GET_ARG3(*request);
size_t len;
 
/*
* Make sure that we are called with exactly one of L_FILE and
* L_DIRECTORY.
* L_DIRECTORY. Make sure that the user does not pass L_OPEN.
*/
if ((lflag & (L_FILE | L_DIRECTORY)) == 0 ||
(lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) {
if (((lflag & (L_FILE | L_DIRECTORY)) == 0) ||
((lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) ||
((lflag & L_OPEN) != 0)) {
ipc_answer_0(rid, EINVAL);
return;
}
 
if (oflag & O_CREAT)
lflag |= L_CREATE;
if (oflag & O_EXCL)
lflag |= L_EXCLUSIVE;
 
ipc_callid_t callid;
 
if (!ipc_data_write_receive(&callid, &len)) {
ipc_answer_0(callid, EINVAL);
ipc_answer_0(rid, EINVAL);
return;
}
char *path = malloc(len + 1);
if (!path) {
ipc_answer_0(callid, ENOMEM);
505,6 → 477,7
ipc_answer_0(rid, ENOMEM);
return;
}
int rc;
if ((rc = ipc_data_write_finalize(callid, path, len))) {
ipc_answer_0(rid, rc);
519,40 → 492,40
* triplet.
*/
if (lflag & L_CREATE)
rwlock_write_lock(&namespace_rwlock);
fibril_rwlock_write_lock(&namespace_rwlock);
else
rwlock_read_lock(&namespace_rwlock);
 
fibril_rwlock_read_lock(&namespace_rwlock);
/* The path is now populated and we can call vfs_lookup_internal(). */
vfs_lookup_res_t lr;
rc = vfs_lookup_internal(path, lflag, &lr, NULL);
if (rc) {
rc = vfs_lookup_internal(path, lflag | L_OPEN, &lr, NULL);
if (rc != EOK) {
if (lflag & L_CREATE)
rwlock_write_unlock(&namespace_rwlock);
fibril_rwlock_write_unlock(&namespace_rwlock);
else
rwlock_read_unlock(&namespace_rwlock);
fibril_rwlock_read_unlock(&namespace_rwlock);
ipc_answer_0(rid, rc);
free(path);
return;
}
 
/* Path is no longer needed. */
free(path);
 
vfs_node_t *node = vfs_node_get(&lr);
if (lflag & L_CREATE)
rwlock_write_unlock(&namespace_rwlock);
fibril_rwlock_write_unlock(&namespace_rwlock);
else
rwlock_read_unlock(&namespace_rwlock);
 
fibril_rwlock_read_unlock(&namespace_rwlock);
/* Truncate the file if requested and if necessary. */
if (oflag & O_TRUNC) {
rwlock_write_lock(&node->contents_rwlock);
fibril_rwlock_write_lock(&node->contents_rwlock);
if (node->size) {
rc = vfs_truncate_internal(node->fs_handle,
node->dev_handle, node->index, 0);
if (rc) {
rwlock_write_unlock(&node->contents_rwlock);
fibril_rwlock_write_unlock(&node->contents_rwlock);
vfs_node_put(node);
ipc_answer_0(rid, rc);
return;
559,9 → 532,9
}
node->size = 0;
}
rwlock_write_unlock(&node->contents_rwlock);
fibril_rwlock_write_unlock(&node->contents_rwlock);
}
 
/*
* Get ourselves a file descriptor and the corresponding vfs_file_t
* structure.
574,10 → 547,87
}
vfs_file_t *file = vfs_file_get(fd);
file->node = node;
if (oflag & O_APPEND)
if (oflag & O_APPEND)
file->append = true;
/*
* 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_1(rid, EOK, fd);
}
 
void vfs_open_node(ipc_callid_t rid, ipc_call_t *request)
{
// FIXME: check for sanity of the supplied fs, dev and index
if (!vfs_files_init()) {
ipc_answer_0(rid, ENOMEM);
return;
}
/*
* The interface is open_node(fs, dev, index, oflag).
*/
vfs_lookup_res_t lr;
lr.triplet.fs_handle = IPC_GET_ARG1(*request);
lr.triplet.dev_handle = IPC_GET_ARG2(*request);
lr.triplet.index = IPC_GET_ARG3(*request);
int oflag = IPC_GET_ARG4(*request);
fibril_rwlock_read_lock(&namespace_rwlock);
int rc = vfs_open_node_internal(&lr);
if (rc != EOK) {
fibril_rwlock_read_unlock(&namespace_rwlock);
ipc_answer_0(rid, rc);
return;
}
vfs_node_t *node = vfs_node_get(&lr);
fibril_rwlock_read_unlock(&namespace_rwlock);
/* Truncate the file if requested and if necessary. */
if (oflag & O_TRUNC) {
fibril_rwlock_write_lock(&node->contents_rwlock);
if (node->size) {
rc = vfs_truncate_internal(node->fs_handle,
node->dev_handle, node->index, 0);
if (rc) {
fibril_rwlock_write_unlock(&node->contents_rwlock);
vfs_node_put(node);
ipc_answer_0(rid, rc);
return;
}
node->size = 0;
}
fibril_rwlock_write_unlock(&node->contents_rwlock);
}
/*
* 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_0(rid, fd);
return;
}
vfs_file_t *file = vfs_file_get(fd);
file->node = node;
if (oflag & O_APPEND)
file->append = true;
/*
* 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
586,18 → 636,133
*/
vfs_node_addref(node);
vfs_node_put(node);
 
/* Success! Return the new file descriptor to the client. */
ipc_answer_1(rid, EOK, fd);
}
 
void vfs_close(ipc_callid_t rid, ipc_call_t *request)
void vfs_node(ipc_callid_t rid, ipc_call_t *request)
{
int fd = IPC_GET_ARG1(*request);
int rc = vfs_fd_free(fd);
/* Lookup the file structure corresponding to the file descriptor. */
vfs_file_t *file = vfs_file_get(fd);
if (!file) {
ipc_answer_0(rid, ENOENT);
return;
}
ipc_answer_3(rid, EOK, file->node->fs_handle, file->node->dev_handle,
file->node->index);
}
 
void vfs_device(ipc_callid_t rid, ipc_call_t *request)
{
int fd = IPC_GET_ARG1(*request);
/* Lookup the file structure corresponding to the file descriptor. */
vfs_file_t *file = vfs_file_get(fd);
if (!file) {
ipc_answer_0(rid, ENOENT);
return;
}
/*
* Lock the open file structure so that no other thread can manipulate
* the same open file at a time.
*/
fibril_mutex_lock(&file->lock);
int fs_phone = vfs_grab_phone(file->node->fs_handle);
/* Make a VFS_DEVICE request at the destination FS server. */
aid_t msg;
ipc_call_t answer;
msg = async_send_2(fs_phone, IPC_GET_METHOD(*request),
file->node->dev_handle, file->node->index, &answer);
 
/* Wait for reply from the FS server. */
ipcarg_t rc;
async_wait_for(msg, &rc);
 
vfs_release_phone(fs_phone);
fibril_mutex_unlock(&file->lock);
ipc_answer_1(rid, EOK, IPC_GET_ARG1(answer));
}
 
void vfs_sync(ipc_callid_t rid, ipc_call_t *request)
{
int fd = IPC_GET_ARG1(*request);
/* Lookup the file structure corresponding to the file descriptor. */
vfs_file_t *file = vfs_file_get(fd);
if (!file) {
ipc_answer_0(rid, ENOENT);
return;
}
/*
* Lock the open file structure so that no other thread can manipulate
* the same open file at a time.
*/
fibril_mutex_lock(&file->lock);
int fs_phone = vfs_grab_phone(file->node->fs_handle);
/* Make a VFS_SYMC request at the destination FS server. */
aid_t msg;
ipc_call_t answer;
msg = async_send_2(fs_phone, IPC_GET_METHOD(*request),
file->node->dev_handle, file->node->index, &answer);
 
/* Wait for reply from the FS server. */
ipcarg_t rc;
async_wait_for(msg, &rc);
vfs_release_phone(fs_phone);
fibril_mutex_unlock(&file->lock);
ipc_answer_0(rid, rc);
}
 
void vfs_close(ipc_callid_t rid, ipc_call_t *request)
{
int fd = IPC_GET_ARG1(*request);
/* Lookup the file structure corresponding to the file descriptor. */
vfs_file_t *file = vfs_file_get(fd);
if (!file) {
ipc_answer_0(rid, ENOENT);
return;
}
/*
* Lock the open file structure so that no other thread can manipulate
* the same open file at a time.
*/
fibril_mutex_lock(&file->lock);
int fs_phone = vfs_grab_phone(file->node->fs_handle);
/* Make a VFS_CLOSE request at the destination FS server. */
aid_t msg;
ipc_call_t answer;
msg = async_send_2(fs_phone, IPC_GET_METHOD(*request),
file->node->dev_handle, file->node->index, &answer);
 
/* Wait for reply from the FS server. */
ipcarg_t rc;
async_wait_for(msg, &rc);
 
vfs_release_phone(fs_phone);
fibril_mutex_unlock(&file->lock);
int retval = IPC_GET_ARG1(answer);
if (retval != EOK)
ipc_answer_0(rid, retval);
retval = vfs_fd_free(fd);
ipc_answer_0(rid, retval);
}
 
static void vfs_rdwr(ipc_callid_t rid, ipc_call_t *request, bool read)
{
 
640,7 → 805,7
* Lock the open file structure so that no other thread can manipulate
* the same open file at a time.
*/
futex_down(&file->lock);
fibril_mutex_lock(&file->lock);
 
/*
* Lock the file's node so that no other client can read/write to it at
647,9 → 812,9
* the same time.
*/
if (read)
rwlock_read_lock(&file->node->contents_rwlock);
fibril_rwlock_read_lock(&file->node->contents_rwlock);
else
rwlock_write_lock(&file->node->contents_rwlock);
fibril_rwlock_write_lock(&file->node->contents_rwlock);
 
if (file->node->type == VFS_NODE_DIRECTORY) {
/*
657,7 → 822,7
* while we are in readdir().
*/
assert(read);
rwlock_read_lock(&namespace_rwlock);
fibril_rwlock_read_lock(&namespace_rwlock);
}
int fs_phone = vfs_grab_phone(file->node->fs_handle);
677,31 → 842,32
* don't have to bother.
*/
ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
 
/* Wait for reply from the FS server. */
ipcarg_t rc;
async_wait_for(msg, &rc);
vfs_release_phone(fs_phone);
/* Wait for reply from the FS server. */
ipcarg_t rc;
async_wait_for(msg, &rc);
size_t bytes = IPC_GET_ARG1(answer);
 
if (file->node->type == VFS_NODE_DIRECTORY)
rwlock_read_unlock(&namespace_rwlock);
fibril_rwlock_read_unlock(&namespace_rwlock);
/* Unlock the VFS node. */
if (read)
rwlock_read_unlock(&file->node->contents_rwlock);
fibril_rwlock_read_unlock(&file->node->contents_rwlock);
else {
/* Update the cached version of node's size. */
if (rc == EOK)
file->node->size = IPC_GET_ARG2(answer);
rwlock_write_unlock(&file->node->contents_rwlock);
fibril_rwlock_write_unlock(&file->node->contents_rwlock);
}
/* Update the position pointer and unlock the open file. */
if (rc == EOK)
file->pos += bytes;
futex_up(&file->lock);
fibril_mutex_unlock(&file->lock);
/*
* FS server's reply is the final result of the whole operation we
735,40 → 901,40
}
 
off_t newpos;
futex_down(&file->lock);
fibril_mutex_lock(&file->lock);
if (whence == SEEK_SET) {
file->pos = off;
futex_up(&file->lock);
fibril_mutex_unlock(&file->lock);
ipc_answer_1(rid, EOK, off);
return;
}
if (whence == SEEK_CUR) {
if (file->pos + off < file->pos) {
futex_up(&file->lock);
fibril_mutex_unlock(&file->lock);
ipc_answer_0(rid, EOVERFLOW);
return;
}
file->pos += off;
newpos = file->pos;
futex_up(&file->lock);
fibril_mutex_unlock(&file->lock);
ipc_answer_1(rid, EOK, newpos);
return;
}
if (whence == SEEK_END) {
rwlock_read_lock(&file->node->contents_rwlock);
fibril_rwlock_read_lock(&file->node->contents_rwlock);
size_t size = file->node->size;
rwlock_read_unlock(&file->node->contents_rwlock);
fibril_rwlock_read_unlock(&file->node->contents_rwlock);
if (size + off < size) {
futex_up(&file->lock);
fibril_mutex_unlock(&file->lock);
ipc_answer_0(rid, EOVERFLOW);
return;
}
newpos = size + off;
futex_up(&file->lock);
fibril_mutex_unlock(&file->lock);
ipc_answer_1(rid, EOK, newpos);
return;
}
futex_up(&file->lock);
fibril_mutex_unlock(&file->lock);
ipc_answer_0(rid, EINVAL);
}
 
797,16 → 963,16
ipc_answer_0(rid, ENOENT);
return;
}
futex_down(&file->lock);
fibril_mutex_lock(&file->lock);
 
rwlock_write_lock(&file->node->contents_rwlock);
fibril_rwlock_write_lock(&file->node->contents_rwlock);
rc = vfs_truncate_internal(file->node->fs_handle,
file->node->dev_handle, file->node->index, size);
if (rc == EOK)
file->node->size = size;
rwlock_write_unlock(&file->node->contents_rwlock);
fibril_rwlock_write_unlock(&file->node->contents_rwlock);
 
futex_up(&file->lock);
fibril_mutex_unlock(&file->lock);
ipc_answer_0(rid, (ipcarg_t)rc);
}
 
836,10 → 1002,10
}
path[len] = '\0';
rwlock_write_lock(&namespace_rwlock);
fibril_rwlock_write_lock(&namespace_rwlock);
int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE;
rc = vfs_lookup_internal(path, lflag, NULL, NULL);
rwlock_write_unlock(&namespace_rwlock);
fibril_rwlock_write_unlock(&namespace_rwlock);
free(path);
ipc_answer_0(rid, rc);
}
870,13 → 1036,13
}
path[len] = '\0';
rwlock_write_lock(&namespace_rwlock);
fibril_rwlock_write_lock(&namespace_rwlock);
lflag &= L_DIRECTORY; /* sanitize lflag */
vfs_lookup_res_t lr;
rc = vfs_lookup_internal(path, lflag | L_UNLINK, &lr, NULL);
free(path);
if (rc != EOK) {
rwlock_write_unlock(&namespace_rwlock);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, rc);
return;
}
887,10 → 1053,10
* VFS_DESTROY'ed after the last reference to it is dropped.
*/
vfs_node_t *node = vfs_node_get(&lr);
futex_down(&nodes_futex);
fibril_mutex_lock(&nodes_mutex);
node->lnkcnt--;
futex_up(&nodes_futex);
rwlock_write_unlock(&namespace_rwlock);
fibril_mutex_unlock(&nodes_mutex);
fibril_rwlock_write_unlock(&namespace_rwlock);
vfs_node_put(node);
ipc_answer_0(rid, EOK);
}
952,8 → 1118,16
}
oldc[olen] = '\0';
newc[nlen] = '\0';
if (!str_lcmp(newc, oldc, str_length(oldc))) {
/* oldc is a prefix of newc */
if ((!str_lcmp(newc, oldc, str_length(oldc))) &&
((newc[str_length(oldc)] == '/') ||
(str_length(oldc) == 1) ||
(str_length(oldc) == str_length(newc)))) {
/*
* oldc is a prefix of newc and either
* - newc continues with a / where oldc ends, or
* - oldc was / itself, or
* - oldc and newc are equal.
*/
ipc_answer_0(rid, EINVAL);
free(old);
free(new);
963,11 → 1137,11
vfs_lookup_res_t old_lr;
vfs_lookup_res_t new_lr;
vfs_lookup_res_t new_par_lr;
rwlock_write_lock(&namespace_rwlock);
fibril_rwlock_write_lock(&namespace_rwlock);
/* Lookup the node belonging to the old file name. */
rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL);
if (rc != EOK) {
rwlock_write_unlock(&namespace_rwlock);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, rc);
free(old);
free(new);
975,16 → 1149,31
}
vfs_node_t *old_node = vfs_node_get(&old_lr);
if (!old_node) {
rwlock_write_unlock(&namespace_rwlock);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, ENOMEM);
free(old);
free(new);
return;
}
/* Determine the path to the parent of the node with the new name. */
char *parentc = str_dup(newc);
if (!parentc) {
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, rc);
free(old);
free(new);
return;
}
char *lastsl = str_rchr(parentc + 1, '/');
if (lastsl)
*lastsl = '\0';
else
parentc[1] = '\0';
/* Lookup parent of the new file name. */
rc = vfs_lookup_internal(newc, L_PARENT, &new_par_lr, NULL);
rc = vfs_lookup_internal(parentc, L_NONE, &new_par_lr, NULL);
free(parentc); /* not needed anymore */
if (rc != EOK) {
rwlock_write_unlock(&namespace_rwlock);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, rc);
free(old);
free(new);
993,7 → 1182,7
/* Check whether linking to the same file system instance. */
if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) ||
(old_node->dev_handle != new_par_lr.triplet.dev_handle)) {
rwlock_write_unlock(&namespace_rwlock);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, EXDEV); /* different file systems */
free(old);
free(new);
1009,18 → 1198,18
case EOK:
new_node = vfs_node_get(&new_lr);
if (!new_node) {
rwlock_write_unlock(&namespace_rwlock);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, ENOMEM);
free(old);
free(new);
return;
}
futex_down(&nodes_futex);
fibril_mutex_lock(&nodes_mutex);
new_node->lnkcnt--;
futex_up(&nodes_futex);
fibril_mutex_unlock(&nodes_mutex);
break;
default:
rwlock_write_unlock(&namespace_rwlock);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, ENOTEMPTY);
free(old);
free(new);
1029,7 → 1218,7
/* Create the new link for the new name. */
rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index);
if (rc != EOK) {
rwlock_write_unlock(&namespace_rwlock);
fibril_rwlock_write_unlock(&namespace_rwlock);
if (new_node)
vfs_node_put(new_node);
ipc_answer_0(rid, rc);
1037,13 → 1226,13
free(new);
return;
}
futex_down(&nodes_futex);
fibril_mutex_lock(&nodes_mutex);
old_node->lnkcnt++;
futex_up(&nodes_futex);
fibril_mutex_unlock(&nodes_mutex);
/* Destroy the link for the old name. */
rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL);
if (rc != EOK) {
rwlock_write_unlock(&namespace_rwlock);
fibril_rwlock_write_unlock(&namespace_rwlock);
vfs_node_put(old_node);
if (new_node)
vfs_node_put(new_node);
1052,10 → 1241,10
free(new);
return;
}
futex_down(&nodes_futex);
fibril_mutex_lock(&nodes_mutex);
old_node->lnkcnt--;
futex_up(&nodes_futex);
rwlock_write_unlock(&namespace_rwlock);
fibril_mutex_unlock(&nodes_mutex);
fibril_rwlock_write_unlock(&namespace_rwlock);
vfs_node_put(old_node);
if (new_node)
vfs_node_put(new_node);
1066,4 → 1255,4
 
/**
* @}
*/
*/
/branches/network/uspace/srv/vfs/vfs_register.c
45,15 → 45,16
#include <string.h>
#include <ctype.h>
#include <bool.h>
#include <futex.h>
#include <libadt/list.h>
#include <fibril_sync.h>
#include <adt/list.h>
#include <as.h>
#include <assert.h>
#include <atomic.h>
#include "vfs.h"
 
atomic_t fs_head_futex = FUTEX_INITIALIZER;
link_t fs_head;
FIBRIL_CONDVAR_INITIALIZE(fs_head_cv);
FIBRIL_MUTEX_INITIALIZE(fs_head_lock);
LIST_INITIALIZE(fs_head);
 
atomic_t fs_handle_next = {
.count = 1
159,7 → 160,7
return;
}
link_initialize(&fs_info->fs_link);
futex_initialize(&fs_info->phone_futex, 1);
fibril_mutex_initialize(&fs_info->phone_lock);
rc = ipc_data_write_finalize(callid, &fs_info->vfs_info, size);
if (rc != EOK) {
180,8 → 181,7
return;
}
futex_down(&fs_head_futex);
fibril_inc_sercount();
fibril_mutex_lock(&fs_head_lock);
 
/*
* Check for duplicit registrations.
191,8 → 191,7
* We already register a fs like this.
*/
dprintf("FS is already registered.\n");
fibril_dec_sercount();
futex_up(&fs_head_futex);
fibril_mutex_unlock(&fs_head_lock);
free(fs_info);
ipc_answer_0(callid, EEXISTS);
ipc_answer_0(rid, EEXISTS);
214,8 → 213,7
if (IPC_GET_METHOD(call) != IPC_M_CONNECT_TO_ME) {
dprintf("Unexpected call, method = %d\n", IPC_GET_METHOD(call));
list_remove(&fs_info->fs_link);
fibril_dec_sercount();
futex_up(&fs_head_futex);
fibril_mutex_unlock(&fs_head_lock);
free(fs_info);
ipc_answer_0(callid, EINVAL);
ipc_answer_0(rid, EINVAL);
233,8 → 231,7
if (!ipc_share_in_receive(&callid, &size)) {
dprintf("Unexpected call, method = %d\n", IPC_GET_METHOD(call));
list_remove(&fs_info->fs_link);
fibril_dec_sercount();
futex_up(&fs_head_futex);
fibril_mutex_unlock(&fs_head_lock);
ipc_hangup(fs_info->phone);
free(fs_info);
ipc_answer_0(callid, EINVAL);
248,8 → 245,7
if (size != PLB_SIZE) {
dprintf("Client suggests wrong size of PFB, size = %d\n", size);
list_remove(&fs_info->fs_link);
fibril_dec_sercount();
futex_up(&fs_head_futex);
fibril_mutex_unlock(&fs_head_lock);
ipc_hangup(fs_info->phone);
free(fs_info);
ipc_answer_0(callid, EINVAL);
273,16 → 269,11
fs_info->fs_handle = (fs_handle_t) atomic_postinc(&fs_handle_next);
ipc_answer_1(rid, EOK, (ipcarg_t) fs_info->fs_handle);
fibril_dec_sercount();
futex_up(&fs_head_futex);
fibril_condvar_broadcast(&fs_head_cv);
fibril_mutex_unlock(&fs_head_lock);
dprintf("\"%.*s\" filesystem successfully registered, handle=%d.\n",
FS_NAME_MAXLEN, fs_info->vfs_info.name, fs_info->fs_handle);
/* Process pending mount requests possibly waiting
* for this filesystem implementation.
*/
vfs_process_pending_mount();
}
 
/** For a given file system handle, implement policy for allocating a phone.
294,76 → 285,49
*/
int vfs_grab_phone(fs_handle_t handle)
{
int phone;
 
/*
* For now, we don't try to be very clever and very fast.
* We simply lookup the phone in the fs_head list. We currently don't
* open any additional phones (even though that itself would be pretty
* straightforward; housekeeping multiple open phones to a FS task would
* be more demanding). Instead, we simply take the respective
* phone_futex and keep it until vfs_release_phone().
* For now, we don't try to be very clever and very fast. We simply
* lookup the phone in the fs_head list and duplicate it. The duplicate
* phone will be returned to the client and the client will use it for
* communication. In the future, we should cache the connections so
* that they do not have to be reestablished over and over again.
*/
futex_down(&fs_head_futex);
fibril_mutex_lock(&fs_head_lock);
link_t *cur;
fs_info_t *fs;
for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
fs = list_get_instance(cur, fs_info_t, fs_link);
if (fs->fs_handle == handle) {
futex_up(&fs_head_futex);
/*
* For now, take the futex unconditionally.
* Oh yeah, serialization rocks.
* It will be up'ed in vfs_release_phone().
*/
futex_down(&fs->phone_futex);
/*
* Avoid deadlock with other fibrils in the same thread
* by disabling fibril preemption.
*/
fibril_inc_sercount();
return fs->phone;
fibril_mutex_unlock(&fs_head_lock);
fibril_mutex_lock(&fs->phone_lock);
phone = ipc_connect_me_to(fs->phone, 0, 0, 0);
fibril_mutex_unlock(&fs->phone_lock);
 
assert(phone > 0);
return phone;
}
}
futex_up(&fs_head_futex);
fibril_mutex_unlock(&fs_head_lock);
return 0;
}
 
/** Tell VFS that the phone is in use for any request.
/** Tell VFS that the phone is not needed anymore.
*
* @param phone Phone to FS task.
*/
void vfs_release_phone(int phone)
{
bool found = false;
 
/*
* Undo the fibril_inc_sercount() done in vfs_grab_phone().
*/
fibril_dec_sercount();
futex_down(&fs_head_futex);
link_t *cur;
for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link);
if (fs->phone == phone) {
found = true;
futex_up(&fs_head_futex);
futex_up(&fs->phone_futex);
return;
}
}
futex_up(&fs_head_futex);
 
/*
* Not good to get here.
*/
assert(found == true);
/* TODO: implement connection caching */
ipc_hangup(phone);
}
 
/** Convert file system name to its handle.
*
* @param name File system name.
* @param lock If true, the function will down and up the
* fs_head_futex.
* @param lock If true, the function will lock and unlock the
* fs_head_lock.
*
* @return File system handle or zero if file system not found.
*/
372,7 → 336,7
int handle = 0;
if (lock)
futex_down(&fs_head_futex);
fibril_mutex_lock(&fs_head_lock);
link_t *cur;
for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link);
382,7 → 346,7
}
}
if (lock)
futex_up(&fs_head_futex);
fibril_mutex_unlock(&fs_head_lock);
return handle;
}
 
/branches/network/uspace/srv/vfs/vfs.h
28,70 → 28,25
 
/** @addtogroup fs
* @{
*/
*/
 
#ifndef VFS_VFS_H_
#define VFS_VFS_H_
 
#include <ipc/ipc.h>
#include <libadt/list.h>
#include <futex.h>
#include <rwlock.h>
#include <adt/list.h>
#include <fibril_sync.h>
#include <sys/types.h>
#include <devmap.h>
#include <bool.h>
#include <ipc/vfs.h>
 
// FIXME: according to CONFIG_DEBUG
// #define dprintf(...) printf(__VA_ARGS__)
// #define dprintf(...) printf(__VA_ARGS__)
 
#define dprintf(...)
 
#define VFS_FIRST IPC_FIRST_USER_METHOD
 
/* Basic types. */
typedef int16_t fs_handle_t;
typedef int16_t dev_handle_t;
typedef uint32_t fs_index_t;
 
typedef enum {
VFS_READ = VFS_FIRST,
VFS_WRITE,
VFS_TRUNCATE,
VFS_MOUNT,
VFS_UNMOUNT,
VFS_LAST_CMN, /* keep this the last member of this enum */
} vfs_request_cmn_t;
 
typedef enum {
VFS_LOOKUP = VFS_LAST_CMN,
VFS_MOUNTED,
VFS_DESTROY,
VFS_LAST_CLNT, /* keep this the last member of this enum */
} vfs_request_clnt_t;
 
typedef enum {
VFS_REGISTER = VFS_LAST_CMN,
VFS_OPEN,
VFS_CLOSE,
VFS_SEEK,
VFS_MKDIR,
VFS_UNLINK,
VFS_RENAME,
VFS_LAST_SRV, /* keep this the last member of this enum */
} vfs_request_srv_t;
 
#define FS_NAME_MAXLEN 20
 
/**
* A structure like this is passed to VFS by each individual FS upon its
* registration. It assosiates a human-readable identifier with each
* registered FS.
*/
typedef struct {
/** Unique identifier of the fs. */
char name[FS_NAME_MAXLEN + 1];
} vfs_info_t;
 
/**
* A structure like this will be allocated for each registered file system.
*/
typedef struct {
98,7 → 53,7
link_t fs_link;
vfs_info_t vfs_info;
fs_handle_t fs_handle;
futex_t phone_futex; /**< Phone serializing futex. */
fibril_mutex_t phone_lock;
ipcarg_t phone;
} fs_info_t;
 
105,8 → 60,8
/**
* VFS_PAIR uniquely represents a file system instance.
*/
#define VFS_PAIR \
fs_handle_t fs_handle; \
#define VFS_PAIR \
fs_handle_t fs_handle; \
dev_handle_t dev_handle;
 
/**
116,8 → 71,8
* @note fs_handle, dev_handle and index are meant to be returned in one
* IPC reply.
*/
#define VFS_TRIPLET \
VFS_PAIR; \
#define VFS_TRIPLET \
VFS_PAIR; \
fs_index_t index;
 
typedef struct {
128,50 → 83,6
VFS_TRIPLET;
} vfs_triplet_t;
 
/*
* Lookup flags.
*/
/**
* No lookup flags used.
*/
#define L_NONE 0
/**
* Lookup will succeed only if the object is a regular file. If L_CREATE is
* specified, an empty file will be created. This flag is mutually exclusive
* with L_DIRECTORY.
*/
#define L_FILE 1
/**
* Lookup wil succeed only if the object is a directory. If L_CREATE is
* specified, an empty directory will be created. This flag is mutually
* exclusive with L_FILE.
*/
#define L_DIRECTORY 2
/**
* When used with L_CREATE, L_EXCLUSIVE will cause the lookup to fail if the
* object already exists. L_EXCLUSIVE is implied when L_DIRECTORY is used.
*/
#define L_EXCLUSIVE 4
/**
* L_CREATE is used for creating both regular files and directories.
*/
#define L_CREATE 8
/**
* L_LINK is used for linking to an already existing nodes.
*/
#define L_LINK 16
/**
* L_UNLINK is used to remove leaves from the file system namespace. This flag
* cannot be passed directly by the client, but will be set by VFS during
* VFS_UNLINK.
*/
#define L_UNLINK 32
/**
* L_PARENT performs a lookup but returns the triplet of the parent node.
* This flag may not be combined with any other lookup flag.
*/
#define L_PARENT 64
 
typedef enum vfs_node_type {
VFS_NODE_UNKNOWN,
VFS_NODE_FILE,
210,7 → 121,7
/**
* Holding this rwlock prevents modifications of the node's contents.
*/
rwlock_t contents_rwlock;
fibril_rwlock_t contents_rwlock;
} vfs_node_t;
 
/**
219,7 → 130,7
*/
typedef struct {
/** Serializes access to this open file. */
futex_t lock;
fibril_mutex_t lock;
 
vfs_node_t *node;
233,16 → 144,14
off_t pos;
} vfs_file_t;
 
extern futex_t nodes_futex;
extern fibril_mutex_t nodes_mutex;
 
extern fibril_condvar_t fs_head_cv;
extern fibril_mutex_t fs_head_lock;
extern link_t fs_head; /**< List of registered file systems. */
 
extern vfs_pair_t rootfs; /**< Root file system. */
 
#define MAX_PATH_LEN (64 * 1024)
 
#define PLB_SIZE (2 * MAX_PATH_LEN)
 
/** Each instance of this type describes one path lookup in progress. */
typedef struct {
link_t plb_link; /**< Active PLB entries list link. */
250,7 → 159,7
size_t len; /**< Number of characters in this PLB entry. */
} plb_entry_t;
 
extern futex_t plb_futex; /**< Futex protecting plb and plb_head. */
extern fibril_mutex_t plb_mutex;/**< Mutex protecting plb and plb_head. */
extern uint8_t *plb; /**< Path Lookup Buffer */
extern link_t plb_head; /**< List of active PLB entries. */
 
257,7 → 166,7
#define MAX_MNTOPTS_LEN 256
 
/** Holding this rwlock prevents changes in file system namespace. */
extern rwlock_t namespace_rwlock;
extern fibril_rwlock_t namespace_rwlock;
 
extern int vfs_grab_phone(fs_handle_t);
extern void vfs_release_phone(int);
264,8 → 173,9
 
extern fs_handle_t fs_name_to_handle(char *, bool);
 
extern int vfs_lookup_internal(char *, int, vfs_lookup_res_t *, vfs_pair_t *,
...);
extern int vfs_lookup_internal(char *, int, vfs_lookup_res_t *,
vfs_pair_t *, ...);
extern int vfs_open_node_internal(vfs_lookup_res_t *);
 
extern bool vfs_nodes_init(void);
extern vfs_node_t *vfs_node_get(vfs_lookup_res_t *);
284,10 → 194,13
extern void vfs_node_addref(vfs_node_t *);
extern void vfs_node_delref(vfs_node_t *);
 
extern void vfs_process_pending_mount(void);
extern void vfs_register(ipc_callid_t, ipc_call_t *);
extern void vfs_mount(ipc_callid_t, ipc_call_t *);
extern void vfs_open(ipc_callid_t, ipc_call_t *);
extern void vfs_open_node(ipc_callid_t, ipc_call_t *);
extern void vfs_device(ipc_callid_t, ipc_call_t *);
extern void vfs_sync(ipc_callid_t, ipc_call_t *);
extern void vfs_node(ipc_callid_t, ipc_call_t *);
extern void vfs_close(ipc_callid_t, ipc_call_t *);
extern void vfs_read(ipc_callid_t, ipc_call_t *);
extern void vfs_write(ipc_callid_t, ipc_call_t *);
/branches/network/uspace/srv/vfs/vfs_node.c
38,15 → 38,14
#include "vfs.h"
#include <stdlib.h>
#include <string.h>
#include <futex.h>
#include <rwlock.h>
#include <libadt/hash_table.h>
#include <fibril_sync.h>
#include <adt/hash_table.h>
#include <assert.h>
#include <async.h>
#include <errno.h>
 
/** Futex protecting the VFS node hash table. */
futex_t nodes_futex = FUTEX_INITIALIZER;
/** Mutex protecting the VFS node hash table. */
FIBRIL_MUTEX_INITIALIZE(nodes_mutex);
 
#define NODES_BUCKETS_LOG 8
#define NODES_BUCKETS (1 << NODES_BUCKETS_LOG)
89,9 → 88,9
*/
void vfs_node_addref(vfs_node_t *node)
{
futex_down(&nodes_futex);
fibril_mutex_lock(&nodes_mutex);
_vfs_node_addref(node);
futex_up(&nodes_futex);
fibril_mutex_unlock(&nodes_mutex);
}
 
/** Decrement reference count of a VFS node.
105,7 → 104,7
bool free_vfs_node = false;
bool free_fs_node = false;
 
futex_down(&nodes_futex);
fibril_mutex_lock(&nodes_mutex);
if (node->refcnt-- == 1) {
/*
* We are dropping the last reference to this node.
121,7 → 120,7
if (!node->lnkcnt)
free_fs_node = true;
}
futex_up(&nodes_futex);
fibril_mutex_unlock(&nodes_mutex);
 
if (free_fs_node) {
/*
161,12 → 160,12
link_t *tmp;
vfs_node_t *node;
 
futex_down(&nodes_futex);
fibril_mutex_lock(&nodes_mutex);
tmp = hash_table_find(&nodes, key);
if (!tmp) {
node = (vfs_node_t *) malloc(sizeof(vfs_node_t));
if (!node) {
futex_up(&nodes_futex);
fibril_mutex_unlock(&nodes_mutex);
return NULL;
}
memset(node, 0, sizeof(vfs_node_t));
177,10 → 176,10
node->lnkcnt = result->lnkcnt;
node->type = result->type;
link_initialize(&node->nh_link);
rwlock_initialize(&node->contents_rwlock);
fibril_rwlock_initialize(&node->contents_rwlock);
hash_table_insert(&nodes, key, &node->nh_link);
} else {
node = hash_table_get_instance(tmp, vfs_node_t, nh_link);
node = hash_table_get_instance(tmp, vfs_node_t, nh_link);
if (node->type == VFS_NODE_UNKNOWN &&
result->type != VFS_NODE_UNKNOWN) {
/* Upgrade the node type. */
193,7 → 192,7
assert(node->type == result->type || result->type == VFS_NODE_UNKNOWN);
 
_vfs_node_addref(node);
futex_up(&nodes_futex);
fibril_mutex_unlock(&nodes_mutex);
 
return node;
}
233,4 → 232,4
 
/**
* @}
*/
*/
/branches/network/uspace/srv/vfs/vfs_lookup.c
28,10 → 28,10
 
/** @addtogroup fs
* @{
*/
*/
 
/**
* @file vfs_lookup.c
* @file vfs_lookup.c
* @brief
*/
 
42,27 → 42,28
#include <string.h>
#include <stdarg.h>
#include <bool.h>
#include <futex.h>
#include <libadt/list.h>
#include <fibril_sync.h>
#include <adt/list.h>
#include <vfs/canonify.h>
 
#define min(a, b) ((a) < (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
 
futex_t plb_futex = FUTEX_INITIALIZER;
link_t plb_head; /**< PLB entry ring buffer. */
FIBRIL_MUTEX_INITIALIZE(plb_mutex);
LIST_INITIALIZE(plb_head); /**< PLB entry ring buffer. */
uint8_t *plb = NULL;
 
/** Perform a path lookup.
*
* @param path Path to be resolved; it must be a NULL-terminated
* string.
* @param lflag Flags to be used during lookup.
* @param result Empty structure where the lookup result will be stored.
* Can be NULL.
* @param altroot If non-empty, will be used instead of rootfs as the root
* of the whole VFS tree.
* @param path Path to be resolved; it must be a NULL-terminated
* string.
* @param lflag Flags to be used during lookup.
* @param result Empty structure where the lookup result will be stored.
* Can be NULL.
* @param altroot If non-empty, will be used instead of rootfs as the root
* of the whole VFS tree.
*
* @return EOK on success or an error code from errno.h.
* @return EOK on success or an error code from errno.h.
*
*/
int vfs_lookup_internal(char *path, int lflag, vfs_lookup_res_t *result,
vfs_pair_t *altroot, ...)
91,7 → 92,7
va_end(ap);
}
futex_down(&plb_futex);
fibril_mutex_lock(&plb_mutex);
 
plb_entry_t entry;
link_initialize(&entry.plb_link);
118,7 → 119,7
/*
* The buffer cannot absorb the path.
*/
futex_up(&plb_futex);
fibril_mutex_unlock(&plb_mutex);
return ELIMIT;
}
} else {
126,7 → 127,7
/*
* The buffer cannot absorb the path.
*/
futex_up(&plb_futex);
fibril_mutex_unlock(&plb_mutex);
return ELIMIT;
}
}
145,7 → 146,7
*/
list_append(&entry.plb_link, &plb_head);
futex_up(&plb_futex);
fibril_mutex_unlock(&plb_mutex);
 
/*
* Copy the path into PLB.
162,12 → 163,12
(ipcarg_t) (first + len - 1) % PLB_SIZE,
(ipcarg_t) root->dev_handle, (ipcarg_t) lflag, (ipcarg_t) index,
&answer);
vfs_release_phone(phone);
 
ipcarg_t rc;
async_wait_for(req, &rc);
 
futex_down(&plb_futex);
vfs_release_phone(phone);
fibril_mutex_lock(&plb_mutex);
list_remove(&entry.plb_link);
/*
* Erasing the path from PLB will come handy for debugging purposes.
174,9 → 175,9
*/
memset(&plb[first], 0, cnt1);
memset(plb, 0, cnt2);
futex_up(&plb_futex);
fibril_mutex_unlock(&plb_mutex);
 
if ((rc == EOK) && result) {
if ((rc == EOK) && (result)) {
result->triplet.fs_handle = (fs_handle_t) IPC_GET_ARG1(answer);
result->triplet.dev_handle = (dev_handle_t) IPC_GET_ARG2(answer);
result->triplet.index = (fs_index_t) IPC_GET_ARG3(answer);
193,6 → 194,39
return rc;
}
 
/** Perform a node open operation.
*
* @return EOK on success or an error code from errno.h.
*
*/
int vfs_open_node_internal(vfs_lookup_res_t *result)
{
int phone = vfs_grab_phone(result->triplet.fs_handle);
ipc_call_t answer;
aid_t req = async_send_2(phone, VFS_OPEN_NODE,
(ipcarg_t) result->triplet.dev_handle,
(ipcarg_t) result->triplet.index, &answer);
ipcarg_t rc;
async_wait_for(req, &rc);
vfs_release_phone(phone);
if (rc == EOK) {
result->size = (size_t) IPC_GET_ARG1(answer);
result->lnkcnt = (unsigned) IPC_GET_ARG2(answer);
if (IPC_GET_ARG3(answer) & L_FILE)
result->type = VFS_NODE_FILE;
else if (IPC_GET_ARG3(answer) & L_DIRECTORY)
result->type = VFS_NODE_DIRECTORY;
else
result->type = VFS_NODE_UNKNOWN;
}
return rc;
}
 
/**
* @}
*/
/branches/network/uspace/srv/vfs/Makefile
69,7 → 69,7
disasm: $(OUTPUT).disasm
 
$(OUTPUT).disasm: $(OUTPUT)
$(OBJDUMP) -d $< >$@
$(OBJDUMP) -d $< > $@
 
%.o: %.S
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
/branches/network/uspace/srv/vfs/vfs_file.c
40,6 → 40,8
#include <string.h>
#include <assert.h>
#include <bool.h>
#include <fibril.h>
#include <fibril_sync.h>
#include "vfs.h"
 
/**
55,9 → 57,9
* 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.
* don't need to protect it by a mutex.
*/
__thread vfs_file_t **files = NULL;
fibril_local vfs_file_t **files = NULL;
 
/** Initialize the table of open files. */
bool vfs_files_init(void)
78,19 → 80,23
*/
int vfs_fd_alloc(void)
{
int i;
 
if (!vfs_files_init())
return ENOMEM;
unsigned 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));
futex_initialize(&files[i]->lock, 1);
fibril_mutex_initialize(&files[i]->lock);
vfs_file_addref(files[i]);
return i;
return (int) i;
}
}
return EMFILE;
}
 
103,10 → 109,15
*/
int vfs_fd_free(int fd)
{
if ((fd >= MAX_OPEN_FILES) || (files[fd] == NULL))
if (!vfs_files_init())
return ENOMEM;
if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (files[fd] == NULL))
return EBADF;
vfs_file_delref(files[fd]);
files[fd] = NULL;
return EOK;
}
 
150,11 → 161,15
*/
vfs_file_t *vfs_file_get(int fd)
{
if (fd < MAX_OPEN_FILES)
if (!vfs_files_init())
return NULL;
if ((fd >= 0) && (fd < MAX_OPEN_FILES))
return files[fd];
return NULL;
}
 
/**
* @}
*/
*/