improvements

This commit is contained in:
Miklos Szeredi 2001-10-25 14:16:17 +00:00
parent 79b52f6330
commit d8ae7147bf
7 changed files with 271 additions and 63 deletions

201
dev.c
View File

@ -16,18 +16,79 @@
static struct proc_dir_entry *proc_fs_fuse;
struct proc_dir_entry *proc_fuse_dev;
static struct fuse_req *request_wait(struct fuse_conn *fc)
static int request_wait_answer(struct fuse_req *req)
{
int ret = 0;
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(&req->waitq, &wait);
while(!req->done) {
set_current_state(TASK_INTERRUPTIBLE);
if(signal_pending(current)) {
ret = -EINTR;
break;
}
spin_unlock(&fuse_lock);
schedule();
spin_lock(&fuse_lock);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&req->waitq, &wait);
return ret;
}
void request_send(struct fuse_conn *fc, struct fuse_inparam *in,
struct fuse_outparam *out, int valuret)
{
int ret;
struct fuse_req *req;
req = kmalloc(sizeof(*req), GFP_KERNEL);
if(req == NULL) {
out->result = -ENOMEM;
return;
}
req->param.u.i = *in;
req->size = sizeof(req->param);
req->done = 0;
init_waitqueue_head(&req->waitq);
spin_lock(&fuse_lock);
add_wait_queue(&fc->waitq, &wait);
set_current_state(TASK_INTERRUPTIBLE);
while(list_empty(&fc->pending)) {
if(signal_pending(current))
break;
req->param.unique = fc->reqctr ++;
list_add_tail(&req->list, &fc->pending);
fc->outstanding ++;
/* FIXME: Wait until the number of outstanding requests drops
below a certain level */
wake_up(&fc->waitq);
ret = request_wait_answer(req);
fc->outstanding --;
*out = req->param.u.o;
list_del(&req->list);
kfree(req);
spin_unlock(&fuse_lock);
if(ret)
out->result = ret;
else if (out->result < -512 || (out->result > 0 && !valuret)) {
printk("Bad result from client: %i\n", out->result);
out->result = -EIO;
}
}
static int request_wait(struct fuse_conn *fc)
{
int ret = 0;
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(&fc->waitq, &wait);
while(list_empty(&fc->pending)) {
set_current_state(TASK_INTERRUPTIBLE);
if(signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
spin_unlock(&fuse_lock);
schedule();
spin_lock(&fuse_lock);
@ -35,69 +96,96 @@ static struct fuse_req *request_wait(struct fuse_conn *fc)
set_current_state(TASK_RUNNING);
remove_wait_queue(&fc->waitq, &wait);
if(list_empty(&fc->pending))
return NULL;
req = list_entry(fc->pending.next, struct fuse_req, list);
list_del(&req->list);
spin_unlock(&fuse_lock);
return req;
}
static void request_processing(struct fuse_conn *fc, struct fuse_req *req)
{
spin_lock(&fuse_lock);
list_add_tail(&req->list, &fc->processing);
fc->outstanding ++;
spin_unlock(&fuse_lock);
}
static void request_free(struct fuse_req *req)
{
kfree(req);
return ret;
}
static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes,
loff_t *off)
{
ssize_t res;
ssize_t ret;
struct fuse_conn *fc = file->private_data;
struct fuse_req *req;
struct fuse_param param;
size_t size;
spin_lock(&fuse_lock);
ret = request_wait(fc);
if(ret)
goto err;
printk(KERN_DEBUG "fuse_dev_read[%i]\n", fc->id);
res = -ERESTARTSYS;
req = request_wait(fc);
if(req == NULL)
goto err;
req = list_entry(fc->pending.next, struct fuse_req, list);
param = req->param;
size = req->size;
res = -EIO;
if(nbytes < req->size) {
printk("fuse_dev_read: buffer too small (%i)\n", req->size);
goto err_free_req;
ret = -EIO;
if(nbytes < size) {
printk("fuse_dev_read: buffer too small (%i)\n", size);
goto err;
}
res = -EFAULT;
if(copy_to_user(buf, req->data, req->size))
goto err_free_req;
list_del(&req->list);
list_add_tail(&req->list, &fc->processing);
spin_unlock(&fuse_lock);
request_processing(fc, req);
return req->size;
if(copy_to_user(buf, &param, size))
return -EFAULT;
return size;
err_free_req:
request_free(req);
err:
return res;
spin_unlock(&fuse_lock);
return ret;
}
static struct fuse_req *request_find(struct fuse_conn *fc, unsigned int unique)
{
struct list_head *entry;
struct fuse_req *req = NULL;
list_for_each(entry, &fc->processing) {
struct fuse_req *tmp;
tmp = list_entry(entry, struct fuse_req, list);
if(tmp->param.unique == unique) {
req = tmp;
list_del_init(&req->list);
break;
}
}
return req;
}
static ssize_t fuse_dev_write(struct file *file, const char *buf,
size_t nbytes, loff_t *off)
size_t nbytes, loff_t *off)
{
struct fuse_conn *fc = file->private_data;
struct fuse_param param;
struct fuse_req *req;
printk(KERN_DEBUG "fuse_dev_write[%i]\n", fc->id);
if(nbytes < sizeof(param.unique) || nbytes > sizeof(param)) {
printk("fuse_dev_write: write is short or long\n");
return -EIO;
}
if(copy_from_user(&param, buf, nbytes))
return -EFAULT;
spin_lock(&fuse_lock);
req = request_find(fc, param.unique);
if(req == NULL)
printk("fuse_dev_write[%i]: unknown request: %i", fc->id,
param.unique);
else {
req->param = param;
req->done = 1;
wake_up(&req->waitq);
}
spin_unlock(&fuse_lock);
printk(KERN_DEBUG "fuse_dev_write[%i] <%.*s>\n", fc->id, (int) nbytes,
buf);
return nbytes;
}
@ -105,9 +193,16 @@ static ssize_t fuse_dev_write(struct file *file, const char *buf,
static unsigned int fuse_dev_poll(struct file *file, poll_table *wait)
{
struct fuse_conn *fc = file->private_data;
unsigned int mask = POLLOUT | POLLWRNORM;
printk(KERN_DEBUG "fuse_dev_poll[%i]\n", fc->id);
return 0;
poll_wait(file, &fc->waitq, wait);
spin_lock(&fuse_lock);
if (!list_empty(&fc->pending))
mask |= POLLIN | POLLRDNORM;
spin_unlock(&fuse_lock);
return mask;
}
static struct fuse_conn *new_conn(void)
@ -123,6 +218,7 @@ static struct fuse_conn *new_conn(void)
INIT_LIST_HEAD(&fc->pending);
INIT_LIST_HEAD(&fc->processing);
fc->outstanding = 0;
fc->reqctr = 0;
spin_lock(&fuse_lock);
fc->id = connctr ++;
@ -173,12 +269,12 @@ static struct file_operations fuse_dev_operations = {
int fuse_dev_init()
{
int res;
int ret;
proc_fs_fuse = NULL;
proc_fuse_dev = NULL;
res = -EIO;
ret = -EIO;
proc_fs_fuse = proc_mkdir("fuse", proc_root_fs);
if(!proc_fs_fuse) {
printk("fuse: failed to create directory in /proc/fs\n");
@ -199,8 +295,7 @@ int fuse_dev_init()
err:
fuse_dev_cleanup();
return res;
return ret;
}
void fuse_dev_cleanup()

14
dir.c
View File

@ -43,9 +43,21 @@ static int fuse_readdir(struct file *file, void *dirent, filldir_t filldir)
static int fuse_open(struct inode *inode, struct file *file)
{
struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
struct fuse_inparam in;
struct fuse_outparam out;
printk(KERN_DEBUG "fuse_open: %li\n", inode->i_ino);
return 0;
in.opcode = FUSE_OPEN;
in.u.open.ino = inode->i_ino;
in.u.open.flags = file->f_flags & ~O_EXCL;
request_send(fc, &in, &out, 0);
printk(KERN_DEBUG " fuse_open: <%i> %i\n", out.result, out.u.open.fd);
return out.result;
}
static int fuse_release(struct inode *inode, struct file *file)

41
fuse.h
View File

@ -1,4 +1,3 @@
/* -*- indent-tabs-mode: t; c-basic-offset: 8; -*- */
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu)
@ -15,3 +14,43 @@ struct fuse_mount_data {
int fd;
};
enum fuse_opcode {
FUSE_OPEN,
FUSE_RELEASE,
};
struct fuse_inparam {
enum fuse_opcode opcode;
union {
struct {
unsigned int ino;
int flags;
} open;
} u;
};
struct fuse_outparam {
int result;
union {
struct {
int fd;
} open;
} u;
};
struct fuse_param {
int unique;
int result;
union {
struct fuse_inparam i;
struct fuse_outparam o;
} u;
};
/*
* Local Variables:
* indent-tabs-mode: t
* c-basic-offset: 8
* End:
*/

View File

@ -6,6 +6,8 @@
See the file COPYING.
*/
#include "fuse.h"
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/spinlock.h>
@ -40,20 +42,29 @@ struct fuse_conn {
/** Connnection number (for debuging) */
int id;
/** The request id */
int reqctr;
};
/**
* A filesystem request
* A request to the client
*/
struct fuse_req {
/** The request list */
struct list_head list;
/** The size of the data */
/** The size of the parameters */
size_t size;
/** A pointer to the data */
void *data;
/** The request parameters */
struct fuse_param param;
/** The request wait queue */
wait_queue_head_t waitq;
/** True if the request is finished */
int done;
};
/**
@ -97,6 +108,14 @@ int fuse_fs_init(void);
*/
void fuse_fs_cleanup(void);
/**
* Send a request
*
* @valuret: if true then the request can return a positive value
*/
void request_send(struct fuse_conn *fc, struct fuse_inparam *in,
struct fuse_outparam *out, int valuret);
/*
* Local Variables:
* indent-tabs-mode: t

View File

@ -17,8 +17,30 @@
#include <sys/mount.h>
#include <mntent.h>
static void loop(int devfd)
{
int res;
struct fuse_param param;
while(1) {
res = read(devfd, &param, sizeof(param));
if(res == -1) {
perror("read");
exit(1);
}
printf("unique: %i, opcode: %i\n", param.unique, param.u.i.opcode);
param.u.o.result = 0;
res = write(devfd, &param, sizeof(param));
if(res == -1) {
perror("write");
exit(1);
}
}
}
int mount_fuse(const char *dev, const char *dir, int devfd)
static int mount_fuse(const char *dev, const char *dir, int devfd)
{
int res;
const char *type;
@ -81,7 +103,7 @@ int main(int argc, char *argv[])
mount_fuse(dev, dir, devfd);
sleep(1000);
loop(devfd);
return 0;
}

View File

@ -6,7 +6,6 @@
See the file COPYING.
*/
#include "fuse.h"
#include "fuse_i.h"
#include <linux/module.h>

22
request.c Normal file
View File

@ -0,0 +1,22 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu)
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#include "fuse_i.h"
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
/*
* Local Variables:
* indent-tabs-mode: t
* c-basic-offset: 8
* End:
*/