mirror of
https://github.com/libfuse/libfuse.git
synced 2024-11-30 15:44:18 +08:00
improvements
This commit is contained in:
parent
79b52f6330
commit
d8ae7147bf
201
dev.c
201
dev.c
@ -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, ¶m, 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(¶m, 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
14
dir.c
@ -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
41
fuse.h
@ -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:
|
||||
*/
|
||||
|
27
fuse_i.h
27
fuse_i.h
@ -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
|
||||
|
28
fusemount.c
28
fusemount.c
@ -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, ¶m, 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, ¶m, 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;
|
||||
}
|
||||
|
1
inode.c
1
inode.c
@ -6,7 +6,6 @@
|
||||
See the file COPYING.
|
||||
*/
|
||||
|
||||
#include "fuse.h"
|
||||
#include "fuse_i.h"
|
||||
|
||||
#include <linux/module.h>
|
||||
|
22
request.c
Normal file
22
request.c
Normal 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:
|
||||
*/
|
Loading…
Reference in New Issue
Block a user