dir.o: dir.c
$(CC) $(KCFLAGS) $(KCPPFLAGS) -c dir.c
-main.o: main.c
- $(CC) $(KCFLAGS) $(KCPPFLAGS) -c main.c
+util.o: util.c
+ $(CC) $(KCFLAGS) $(KCPPFLAGS) -c util.c
-fuse_objs = dev.o inode.o dir.o main.o
+fuse_objs = dev.o inode.o dir.o util.o
fuse.o: $(fuse_objs)
ld -r -o fuse.o $(fuse_objs)
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/poll.h>
-#include <linux/file.h>
#include <linux/proc_fs.h>
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)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct fuse_req *req;
+
+ 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;
+
+ spin_unlock(&fuse_lock);
+ schedule();
+ spin_lock(&fuse_lock);
+ }
+ 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);
+}
+
static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes,
loff_t *off)
{
- printk(KERN_DEBUG "fuse_dev_read\n");
- return 0;
+ ssize_t res;
+ struct fuse_conn *fc = file->private_data;
+ struct fuse_req *req;
+
+ printk(KERN_DEBUG "fuse_dev_read[%i]\n", fc->id);
+
+ res = -ERESTARTSYS;
+ req = request_wait(fc);
+ if(req == NULL)
+ goto err;
+
+ res = -EIO;
+ if(nbytes < req->size) {
+ printk("fuse_dev_read: buffer too small (%i)\n", req->size);
+ goto err_free_req;
+ }
+
+ res = -EFAULT;
+ if(copy_to_user(buf, req->data, req->size))
+ goto err_free_req;
+
+ request_processing(fc, req);
+ return req->size;
+
+ err_free_req:
+ request_free(req);
+ err:
+ return res;
}
static ssize_t fuse_dev_write(struct file *file, const char *buf,
size_t nbytes, loff_t *off)
{
- printk(KERN_DEBUG "fuse_dev_write <%.*s>\n", (int) nbytes, buf);
+ struct fuse_conn *fc = file->private_data;
+
+ printk(KERN_DEBUG "fuse_dev_write[%i] <%.*s>\n", fc->id, (int) nbytes,
+ buf);
return nbytes;
}
static unsigned int fuse_dev_poll(struct file *file, poll_table *wait)
{
- printk(KERN_DEBUG "fuse_dev_poll\n");
+ struct fuse_conn *fc = file->private_data;
+
+ printk(KERN_DEBUG "fuse_dev_poll[%i]\n", fc->id);
return 0;
}
+static struct fuse_conn *new_conn(void)
+{
+ static int connctr = 1;
+ struct fuse_conn *fc;
+
+ fc = kmalloc(sizeof(*fc), GFP_KERNEL);
+ if(fc != NULL) {
+ fc->sb = NULL;
+ fc->file = NULL;
+ init_waitqueue_head(&fc->waitq);
+ INIT_LIST_HEAD(&fc->pending);
+ INIT_LIST_HEAD(&fc->processing);
+ fc->outstanding = 0;
+
+ spin_lock(&fuse_lock);
+ fc->id = connctr ++;
+ spin_unlock(&fuse_lock);
+ }
+ return fc;
+}
+
static int fuse_dev_open(struct inode *inode, struct file *file)
{
- int res;
struct fuse_conn *fc;
printk(KERN_DEBUG "fuse_dev_open\n");
- res = -ENOMEM;
- fc = kmalloc(sizeof(*fc), GFP_KERNEL);
+ fc = new_conn();
if(!fc)
- goto out;
-
- fc->sb = NULL;
+ return -ENOMEM;
+
fc->file = file;
-
- lock_kernel();
file->private_data = fc;
- unlock_kernel();
- res = 0;
-
- out:
- return res;
+
+ printk(KERN_DEBUG "new connection: %i\n", fc->id);
+
+ return 0;
}
static int fuse_dev_release(struct inode *inode, struct file *file)
{
struct fuse_conn *fc = file->private_data;
- printk(KERN_DEBUG "fuse_dev_release\n");
+ printk(KERN_DEBUG "fuse_dev_release[%i]\n", fc->id);
- lock_kernel();
+ spin_lock(&fuse_lock);
fc->file = NULL;
fuse_release_conn(fc);
- unlock_kernel();
+ spin_unlock(&fuse_lock);
return 0;
}
*/
-#include "fuse.h"
+#include "fuse_i.h"
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
-#include <linux/sched.h>
-#include <linux/file.h>
static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
{
*/
#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
#define FUSE_VERSION "0.1"
/** The opened client device */
struct file *file;
+
+ /** The client wait queue */
+ wait_queue_head_t waitq;
+
+ /** The list of pending requests */
+ struct list_head pending;
+
+ /** The list of requests being processed */
+ struct list_head processing;
+
+ /** The number of outstanding requests */
+ int outstanding;
+
+ /** Connnection number (for debuging) */
+ int id;
+};
+
+/**
+ * A filesystem request
+ */
+struct fuse_req {
+ /** The request list */
+ struct list_head list;
+
+ /** The size of the data */
+ size_t size;
+
+ /** A pointer to the data */
+ void *data;
};
/**
*/
extern struct proc_dir_entry *proc_fuse_dev;
+/**
+ * The lock to protect fuses structures
+ */
+extern spinlock_t fuse_lock;
+
/**
* Fill in the directory operations
*/
void fuse_dir_init(struct inode *inode);
-
/**
* Check if the connection can be released, and if yes, then free the
* connection structure
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/sched.h>
#include <linux/file.h>
{
struct fuse_conn *fc = sb->u.generic_sbp;
- printk(KERN_DEBUG "fuse_put_super\n");
+ printk(KERN_DEBUG "fuse_put_super[%i]\n", fc->id);
+ spin_lock(&fuse_lock);
fc->sb = NULL;
fuse_release_conn(fc);
+ spin_unlock(&fuse_lock);
+
}
static struct super_operations fuse_super_operations = {
}
+static struct inode *get_root_inode(struct super_block *sb)
+{
+ struct inode *root ;
+
+ root = iget(sb, 1);
+ if(root) {
+ root->i_mode = S_IFDIR;
+ root->i_uid = 0;
+ root->i_gid = 0;
+ root->i_nlink = 2;
+ root->i_size = 0;
+ root->i_blksize = 1024;
+ root->i_blocks = 0;
+ root->i_atime = CURRENT_TIME;
+ root->i_mtime = CURRENT_TIME;
+ root->i_ctime = CURRENT_TIME;
+ fuse_dir_init(root);
+ }
+
+ return root;
+}
+
static struct super_block *fuse_read_super(struct super_block *sb,
void *data, int silent)
{
struct fuse_conn *fc;
struct inode *root;
- fc = get_conn(data);
- if(fc == NULL)
- goto err;
-
- if(fc->sb != NULL) {
- printk("fuse_read_super: file already mounted\n");
- goto err;
- }
-
- sb->u.generic_sbp = fc;
sb->s_blocksize = 1024;
sb->s_blocksize_bits = 10;
sb->s_magic = FUSE_SUPER_MAGIC;
sb->s_op = &fuse_super_operations;
- root = iget(sb, 1);
- if(!root) {
+ root = get_root_inode(sb);
+ if(root == NULL) {
printk("fuse_read_super: failed to get root inode\n");
- goto err;
+ return NULL;
}
printk(KERN_DEBUG "root inode: %ld/%d\n", root->i_ino, root->i_dev);
- root->i_mode = S_IFDIR;
- root->i_uid = 0;
- root->i_gid = 0;
- root->i_nlink = 2;
- root->i_size = 0;
- root->i_blksize = 1024;
- root->i_blocks = 0;
- root->i_atime = CURRENT_TIME;
- root->i_mtime = CURRENT_TIME;
- root->i_ctime = CURRENT_TIME;
- fuse_dir_init(root);
+ spin_lock(&fuse_lock);
+ fc = get_conn(data);
+ if(fc == NULL)
+ goto err;
- sb->s_root = d_alloc_root(root);
- if(!sb->s_root) {
- printk("fuse_read_super: failed to allocate root dentry\n");
- goto err_iput;
+ if(fc->sb != NULL) {
+ printk("fuse_read_super: connection %i already mounted\n",
+ fc->id);
+ goto err;
}
+ sb->u.generic_sbp = fc;
+ sb->s_root = d_alloc_root(root);
fc->sb = sb;
-
+ spin_unlock(&fuse_lock);
+
return sb;
- err_iput:
- iput(root);
err:
+ spin_unlock(&fuse_lock);
+ iput(root);
return NULL;
}
+++ /dev/null
-/*
- 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/smp_lock.h>
-#include <linux/slab.h>
-
-#define FUSE_VERSION "0.1"
-
-
-void fuse_release_conn(struct fuse_conn *fc)
-{
- if(fc->sb == NULL && fc->file == NULL) {
- printk(KERN_DEBUG "fuse: release connection\n");
- kfree(fc);
- }
-}
-
-int init_module(void)
-{
- int res;
-
- printk(KERN_DEBUG "fuse init (version %s)\n", FUSE_VERSION);
-
- res = fuse_fs_init();
- if(res)
- goto err;
-
- res = fuse_dev_init();
- if(res)
- goto err_fs_cleanup;
-
- return 0;
-
- err_fs_cleanup:
- fuse_fs_cleanup();
- err:
- return res;
-}
-
-void cleanup_module(void)
-{
- printk(KERN_DEBUG "fuse cleanup\n");
-
- fuse_fs_cleanup();
- fuse_dev_cleanup();
-}
-
-/*
- * Local Variables:
- * indent-tabs-mode: t
- * c-basic-offset: 8
- */
--- /dev/null
+/*
+ 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/smp_lock.h>
+#include <linux/slab.h>
+
+#define FUSE_VERSION "0.1"
+
+spinlock_t fuse_lock = SPIN_LOCK_UNLOCKED;
+
+/* Must be called with the fuse lock held */
+void fuse_release_conn(struct fuse_conn *fc)
+{
+ if(fc->sb == NULL && fc->file == NULL) {
+ printk(KERN_DEBUG "fuse: release connection: %i\n", fc->id);
+ kfree(fc);
+ }
+}
+
+int init_module(void)
+{
+ int res;
+
+ printk(KERN_DEBUG "fuse init (version %s)\n", FUSE_VERSION);
+
+ res = fuse_fs_init();
+ if(res)
+ goto err;
+
+ res = fuse_dev_init();
+ if(res)
+ goto err_fs_cleanup;
+
+ return 0;
+
+ err_fs_cleanup:
+ fuse_fs_cleanup();
+ err:
+ return res;
+}
+
+void cleanup_module(void)
+{
+ printk(KERN_DEBUG "fuse cleanup\n");
+
+ fuse_fs_cleanup();
+ fuse_dev_cleanup();
+}
+
+/*
+ * Local Variables:
+ * indent-tabs-mode: t
+ * c-basic-offset: 8
+ */