Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 4667 → Rev 4668

/branches/dd/uspace/srv/vfs/vfs_ops.c
43,7 → 43,6
#include <stdlib.h>
#include <string.h>
#include <bool.h>
#include <futex.h>
#include <fibril_sync.h>
#include <adt/list.h>
#include <unistd.h>
55,20 → 54,6
/* 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;
 
FIBRIL_MUTEX_INITIALIZE(pending_lock);
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.
123,7 → 108,7
/*
* Now we hold a reference to mp_node.
* It will be dropped upon the corresponding VFS_UNMOUNT.
* It will be dropped upon the corresponding VFS_IN_UNMOUNT.
* This prevents the mount point from being deleted.
*/
} else {
136,20 → 121,20
/* Tell the mountee that it is being mounted. */
phone = vfs_grab_phone(fs_handle);
msg = async_send_1(phone, VFS_MOUNTED,
msg = async_send_1(phone, VFS_OUT_MOUNTED,
(ipcarg_t) dev_handle, &answer);
/* send the mount options */
rc = ipc_data_write_start(phone, (void *)opts,
str_size(opts));
if (rc != EOK) {
async_wait_for(msg, NULL);
vfs_release_phone(phone);
async_wait_for(msg, NULL);
fibril_rwlock_write_unlock(&namespace_rwlock);
ipc_answer_0(rid, rc);
return;
}
async_wait_for(msg, &rc);
vfs_release_phone(phone);
async_wait_for(msg, &rc);
if (rc != EOK) {
fibril_rwlock_write_unlock(&namespace_rwlock);
196,10 → 181,9
int mountee_phone = vfs_grab_phone(fs_handle);
assert(mountee_phone >= 0);
vfs_release_phone(mountee_phone);
 
phone = vfs_grab_phone(mp_res.triplet.fs_handle);
msg = async_send_4(phone, VFS_MOUNT,
msg = async_send_4(phone, VFS_OUT_MOUNT,
(ipcarg_t) mp_res.triplet.dev_handle,
(ipcarg_t) mp_res.triplet.index,
(ipcarg_t) fs_handle,
208,8 → 192,9
/* 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);
async_wait_for(msg, NULL);
/* Mount failed, drop reference to mp_node. */
if (mp_node)
vfs_node_put(mp_node);
217,12 → 202,14
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) {
async_wait_for(msg, NULL);
vfs_release_phone(phone);
async_wait_for(msg, NULL);
/* Mount failed, drop reference to mp_node. */
if (mp_node)
vfs_node_put(mp_node);
230,8 → 217,8
ipc_answer_0(rid, rc);
return;
}
async_wait_for(msg, &rc);
vfs_release_phone(phone);
async_wait_for(msg, &rc);
if (rc == EOK) {
rindex = (fs_index_t) IPC_GET_ARG1(answer);
258,39 → 245,6
fibril_rwlock_write_unlock(&namespace_rwlock);
}
 
/** Process pending mount requests */
void vfs_process_pending_mount(void)
{
link_t *cur;
loop:
fibril_mutex_lock(&pending_lock);
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);
fibril_mutex_unlock(&pending_lock);
fibril_yield();
goto loop;
}
fibril_mutex_unlock(&pending_lock);
}
 
void vfs_mount(ipc_callid_t rid, ipc_call_t *request)
{
/*
444,35 → 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);
fibril_mutex_lock(&pending_lock);
list_append(&pr->link, &pending_req);
fibril_mutex_unlock(&pending_lock);
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);
480,6 → 416,7
free(opts);
return;
}
fibril_mutex_unlock(&fs_head_lock);
/* Acknowledge that we know fs_name. */
ipc_answer_0(callid, EOK);
500,8 → 437,8
/*
* The POSIX interface is open(path, oflag, mode).
* We can receive oflags and mode along with the VFS_OPEN call; the path
* will need to arrive in another call.
* We can receive oflags and mode along with the VFS_IN_OPEN call;
* the path will need to arrive in another call.
*
* We also receive one private, non-POSIX set of flags called lflag
* used to pass information to vfs_lookup_internal().
618,7 → 555,7
* 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.
* respective VFS_IN_CLOSE.
*/
vfs_node_addref(node);
vfs_node_put(node);
695,7 → 632,7
* 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.
* respective VFS_IN_CLOSE.
*/
vfs_node_addref(node);
vfs_node_put(node);
704,7 → 641,7
ipc_answer_1(rid, EOK, fd);
}
 
void vfs_node(ipc_callid_t rid, ipc_call_t *request)
void vfs_sync(ipc_callid_t rid, ipc_call_t *request)
{
int fd = IPC_GET_ARG1(*request);
715,21 → 652,6
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.
737,53 → 659,17
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. */
/* Make a VFS_OUT_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);
vfs_release_phone(fs_phone);
msg = async_send_2(fs_phone, VFS_OUT_SYNC, file->node->dev_handle,
file->node->index, &answer);
 
/* Wait for reply from the FS server. */
ipcarg_t rc;
async_wait_for(msg, &rc);
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);
 
vfs_release_phone(fs_phone);
 
/* Wait for reply from the FS server. */
ipcarg_t rc;
async_wait_for(msg, &rc);
fibril_mutex_unlock(&file->lock);
ipc_answer_0(rid, rc);
805,21 → 691,19
* 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. */
/* Make a VFS_OUT_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);
msg = async_send_2(fs_phone, VFS_OUT_CLOSE, file->node->dev_handle,
file->node->index, &answer);
 
vfs_release_phone(fs_phone);
/* 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);
899,7 → 783,7
ipc_call_t answer;
if (!read && file->append)
file->pos = file->node->size;
msg = async_send_3(fs_phone, IPC_GET_METHOD(*request),
msg = async_send_3(fs_phone, read ? VFS_OUT_READ : VFS_OUT_WRITE,
file->node->dev_handle, file->node->index, file->pos, &answer);
/*
910,12 → 794,12
*/
ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
 
vfs_release_phone(fs_phone);
/* Wait for reply from the FS server. */
ipcarg_t rc;
async_wait_for(msg, &rc);
vfs_release_phone(fs_phone);
size_t bytes = IPC_GET_ARG1(answer);
 
if (file->node->type == VFS_NODE_DIRECTORY)
1013,7 → 897,7
int fs_phone;
fs_phone = vfs_grab_phone(fs_handle);
rc = async_req_3_0(fs_phone, VFS_TRUNCATE, (ipcarg_t)dev_handle,
rc = async_req_3_0(fs_phone, VFS_OUT_TRUNCATE, (ipcarg_t)dev_handle,
(ipcarg_t)index, (ipcarg_t)size);
vfs_release_phone(fs_phone);
return (int)rc;
1043,6 → 927,106
ipc_answer_0(rid, (ipcarg_t)rc);
}
 
void vfs_fstat(ipc_callid_t rid, ipc_call_t *request)
{
int fd = IPC_GET_ARG1(*request);
size_t size = IPC_GET_ARG2(*request);
ipcarg_t rc;
 
vfs_file_t *file = vfs_file_get(fd);
if (!file) {
ipc_answer_0(rid, ENOENT);
return;
}
 
ipc_callid_t callid;
if (!ipc_data_read_receive(&callid, NULL)) {
ipc_answer_0(callid, EINVAL);
ipc_answer_0(rid, EINVAL);
return;
}
 
fibril_mutex_lock(&file->lock);
 
int fs_phone = vfs_grab_phone(file->node->fs_handle);
aid_t msg;
msg = async_send_3(fs_phone, VFS_OUT_STAT, file->node->dev_handle,
file->node->index, true, NULL);
ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
async_wait_for(msg, &rc);
vfs_release_phone(fs_phone);
 
fibril_mutex_unlock(&file->lock);
ipc_answer_0(rid, rc);
}
 
void vfs_stat(ipc_callid_t rid, ipc_call_t *request)
{
size_t len;
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);
ipc_answer_0(rid, ENOMEM);
return;
}
int rc;
if ((rc = ipc_data_write_finalize(callid, path, len))) {
ipc_answer_0(rid, rc);
free(path);
return;
}
path[len] = '\0';
 
if (!ipc_data_read_receive(&callid, NULL)) {
free(path);
ipc_answer_0(callid, EINVAL);
ipc_answer_0(rid, EINVAL);
return;
}
 
vfs_lookup_res_t lr;
fibril_rwlock_read_lock(&namespace_rwlock);
rc = vfs_lookup_internal(path, L_NONE, &lr, NULL);
free(path);
if (rc != EOK) {
fibril_rwlock_read_unlock(&namespace_rwlock);
ipc_answer_0(callid, rc);
ipc_answer_0(rid, rc);
return;
}
vfs_node_t *node = vfs_node_get(&lr);
if (!node) {
fibril_rwlock_read_unlock(&namespace_rwlock);
ipc_answer_0(callid, ENOMEM);
ipc_answer_0(rid, ENOMEM);
return;
}
 
fibril_rwlock_read_unlock(&namespace_rwlock);
 
int fs_phone = vfs_grab_phone(node->fs_handle);
aid_t msg;
msg = async_send_3(fs_phone, VFS_OUT_STAT, node->dev_handle,
node->index, false, NULL);
ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
ipcarg_t rv;
async_wait_for(msg, &rv);
vfs_release_phone(fs_phone);
 
ipc_answer_0(rid, rv);
 
vfs_node_put(node);
}
 
void vfs_mkdir(ipc_callid_t rid, ipc_call_t *request)
{
int mode = IPC_GET_ARG1(*request);
1117,12 → 1101,12
/*
* The name has already been unlinked by vfs_lookup_internal().
* We have to get and put the VFS node to ensure that it is
* VFS_DESTROY'ed after the last reference to it is dropped.
* VFS_OUT_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);
fibril_mutex_unlock(&nodes_mutex);
fibril_rwlock_write_unlock(&namespace_rwlock);
vfs_node_put(node);
ipc_answer_0(rid, EOK);
1271,9 → 1255,9
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:
fibril_rwlock_write_unlock(&namespace_rwlock);
1293,9 → 1277,9
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) {
1308,9 → 1292,9
free(new);
return;
}
futex_down(&nodes_futex);
fibril_mutex_lock(&nodes_mutex);
old_node->lnkcnt--;
futex_up(&nodes_futex);
fibril_mutex_unlock(&nodes_mutex);
fibril_rwlock_write_unlock(&namespace_rwlock);
vfs_node_put(old_node);
if (new_node)