Commit 5fec8bdb authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: clean up annotations of fc->lock
  fuse: fix sparse warning in ioctl
  fuse: update interface version
  fuse: add fuse_conn->release()
  fuse: separate out fuse_conn_init() from new_conn()
  fuse: add fuse_ prefix to several functions
  fuse: implement poll support
  fuse: implement unsolicited notification
  fuse: add file kernel handle
  fuse: implement ioctl support
  fuse: don't let fuse_req->end() put the base reference
  fuse: move FUSE_MINOR to miscdevice.h
  fuse: style fixes
parents 59e3af21 5d9ec854
/* /*
FUSE: Filesystem in Userspace FUSE: Filesystem in Userspace
Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL. This program can be distributed under the terms of the GNU GPL.
See the file COPYING. See the file COPYING.
...@@ -48,11 +48,13 @@ static ssize_t fuse_conn_waiting_read(struct file *file, char __user *buf, ...@@ -48,11 +48,13 @@ static ssize_t fuse_conn_waiting_read(struct file *file, char __user *buf,
size_t size; size_t size;
if (!*ppos) { if (!*ppos) {
long value;
struct fuse_conn *fc = fuse_ctl_file_conn_get(file); struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
if (!fc) if (!fc)
return 0; return 0;
file->private_data=(void *)(long)atomic_read(&fc->num_waiting); value = atomic_read(&fc->num_waiting);
file->private_data = (void *)value;
fuse_conn_put(fc); fuse_conn_put(fc);
} }
size = sprintf(tmp, "%ld\n", (long)file->private_data); size = sprintf(tmp, "%ld\n", (long)file->private_data);
......
/* /*
FUSE: Filesystem in Userspace FUSE: Filesystem in Userspace
Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL. This program can be distributed under the terms of the GNU GPL.
See the file COPYING. See the file COPYING.
...@@ -269,7 +269,7 @@ static void flush_bg_queue(struct fuse_conn *fc) ...@@ -269,7 +269,7 @@ static void flush_bg_queue(struct fuse_conn *fc)
* Called with fc->lock, unlocks it * Called with fc->lock, unlocks it
*/ */
static void request_end(struct fuse_conn *fc, struct fuse_req *req) static void request_end(struct fuse_conn *fc, struct fuse_req *req)
__releases(fc->lock) __releases(&fc->lock)
{ {
void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
req->end = NULL; req->end = NULL;
...@@ -293,13 +293,13 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) ...@@ -293,13 +293,13 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
wake_up(&req->waitq); wake_up(&req->waitq);
if (end) if (end)
end(fc, req); end(fc, req);
else
fuse_put_request(fc, req); fuse_put_request(fc, req);
} }
static void wait_answer_interruptible(struct fuse_conn *fc, static void wait_answer_interruptible(struct fuse_conn *fc,
struct fuse_req *req) struct fuse_req *req)
__releases(fc->lock) __acquires(fc->lock) __releases(&fc->lock)
__acquires(&fc->lock)
{ {
if (signal_pending(current)) if (signal_pending(current))
return; return;
...@@ -317,7 +317,8 @@ static void queue_interrupt(struct fuse_conn *fc, struct fuse_req *req) ...@@ -317,7 +317,8 @@ static void queue_interrupt(struct fuse_conn *fc, struct fuse_req *req)
} }
static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
__releases(fc->lock) __acquires(fc->lock) __releases(&fc->lock)
__acquires(&fc->lock)
{ {
if (!fc->no_interrupt) { if (!fc->no_interrupt) {
/* Any signal may interrupt this */ /* Any signal may interrupt this */
...@@ -380,7 +381,7 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) ...@@ -380,7 +381,7 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
} }
} }
void request_send(struct fuse_conn *fc, struct fuse_req *req) void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
{ {
req->isreply = 1; req->isreply = 1;
spin_lock(&fc->lock); spin_lock(&fc->lock);
...@@ -399,7 +400,7 @@ void request_send(struct fuse_conn *fc, struct fuse_req *req) ...@@ -399,7 +400,7 @@ void request_send(struct fuse_conn *fc, struct fuse_req *req)
spin_unlock(&fc->lock); spin_unlock(&fc->lock);
} }
static void request_send_nowait_locked(struct fuse_conn *fc, static void fuse_request_send_nowait_locked(struct fuse_conn *fc,
struct fuse_req *req) struct fuse_req *req)
{ {
req->background = 1; req->background = 1;
...@@ -414,11 +415,11 @@ static void request_send_nowait_locked(struct fuse_conn *fc, ...@@ -414,11 +415,11 @@ static void request_send_nowait_locked(struct fuse_conn *fc,
flush_bg_queue(fc); flush_bg_queue(fc);
} }
static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) static void fuse_request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
{ {
spin_lock(&fc->lock); spin_lock(&fc->lock);
if (fc->connected) { if (fc->connected) {
request_send_nowait_locked(fc, req); fuse_request_send_nowait_locked(fc, req);
spin_unlock(&fc->lock); spin_unlock(&fc->lock);
} else { } else {
req->out.h.error = -ENOTCONN; req->out.h.error = -ENOTCONN;
...@@ -426,16 +427,16 @@ static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) ...@@ -426,16 +427,16 @@ static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
} }
} }
void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) void fuse_request_send_noreply(struct fuse_conn *fc, struct fuse_req *req)
{ {
req->isreply = 0; req->isreply = 0;
request_send_nowait(fc, req); fuse_request_send_nowait(fc, req);
} }
void request_send_background(struct fuse_conn *fc, struct fuse_req *req) void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req)
{ {
req->isreply = 1; req->isreply = 1;
request_send_nowait(fc, req); fuse_request_send_nowait(fc, req);
} }
/* /*
...@@ -443,10 +444,11 @@ void request_send_background(struct fuse_conn *fc, struct fuse_req *req) ...@@ -443,10 +444,11 @@ void request_send_background(struct fuse_conn *fc, struct fuse_req *req)
* *
* fc->connected must have been checked previously * fc->connected must have been checked previously
*/ */
void request_send_background_locked(struct fuse_conn *fc, struct fuse_req *req) void fuse_request_send_background_locked(struct fuse_conn *fc,
struct fuse_req *req)
{ {
req->isreply = 1; req->isreply = 1;
request_send_nowait_locked(fc, req); fuse_request_send_nowait_locked(fc, req);
} }
/* /*
...@@ -539,8 +541,8 @@ static int fuse_copy_fill(struct fuse_copy_state *cs) ...@@ -539,8 +541,8 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
BUG_ON(!cs->nr_segs); BUG_ON(!cs->nr_segs);
cs->seglen = cs->iov[0].iov_len; cs->seglen = cs->iov[0].iov_len;
cs->addr = (unsigned long) cs->iov[0].iov_base; cs->addr = (unsigned long) cs->iov[0].iov_base;
cs->iov ++; cs->iov++;
cs->nr_segs --; cs->nr_segs--;
} }
down_read(&current->mm->mmap_sem); down_read(&current->mm->mmap_sem);
err = get_user_pages(current, current->mm, cs->addr, 1, cs->write, 0, err = get_user_pages(current, current->mm, cs->addr, 1, cs->write, 0,
...@@ -589,9 +591,11 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page *page, ...@@ -589,9 +591,11 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page *page,
kunmap_atomic(mapaddr, KM_USER1); kunmap_atomic(mapaddr, KM_USER1);
} }
while (count) { while (count) {
int err; if (!cs->len) {
if (!cs->len && (err = fuse_copy_fill(cs))) int err = fuse_copy_fill(cs);
if (err)
return err; return err;
}
if (page) { if (page) {
void *mapaddr = kmap_atomic(page, KM_USER1); void *mapaddr = kmap_atomic(page, KM_USER1);
void *buf = mapaddr + offset; void *buf = mapaddr + offset;
...@@ -631,9 +635,11 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes, ...@@ -631,9 +635,11 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
static int fuse_copy_one(struct fuse_copy_state *cs, void *val, unsigned size) static int fuse_copy_one(struct fuse_copy_state *cs, void *val, unsigned size)
{ {
while (size) { while (size) {
int err; if (!cs->len) {
if (!cs->len && (err = fuse_copy_fill(cs))) int err = fuse_copy_fill(cs);
if (err)
return err; return err;
}
fuse_copy_do(cs, &val, &size); fuse_copy_do(cs, &val, &size);
} }
return 0; return 0;
...@@ -664,6 +670,8 @@ static int request_pending(struct fuse_conn *fc) ...@@ -664,6 +670,8 @@ static int request_pending(struct fuse_conn *fc)
/* Wait until a request is available on the pending list */ /* Wait until a request is available on the pending list */
static void request_wait(struct fuse_conn *fc) static void request_wait(struct fuse_conn *fc)
__releases(&fc->lock)
__acquires(&fc->lock)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
...@@ -691,7 +699,7 @@ static void request_wait(struct fuse_conn *fc) ...@@ -691,7 +699,7 @@ static void request_wait(struct fuse_conn *fc)
*/ */
static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_req *req, static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_req *req,
const struct iovec *iov, unsigned long nr_segs) const struct iovec *iov, unsigned long nr_segs)
__releases(fc->lock) __releases(&fc->lock)
{ {
struct fuse_copy_state cs; struct fuse_copy_state cs;
struct fuse_in_header ih; struct fuse_in_header ih;
...@@ -813,6 +821,34 @@ static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov, ...@@ -813,6 +821,34 @@ static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
return err; return err;
} }
static int fuse_notify_poll(struct fuse_conn *fc, unsigned int size,
struct fuse_copy_state *cs)
{
struct fuse_notify_poll_wakeup_out outarg;
int err;
if (size != sizeof(outarg))
return -EINVAL;
err = fuse_copy_one(cs, &outarg, sizeof(outarg));
if (err)
return err;
return fuse_notify_poll_wakeup(fc, &outarg);
}
static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
unsigned int size, struct fuse_copy_state *cs)
{
switch (code) {
case FUSE_NOTIFY_POLL:
return fuse_notify_poll(fc, size, cs);
default:
return -EINVAL;
}
}
/* Look up request on processing list by unique ID */ /* Look up request on processing list by unique ID */
static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique) static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique)
{ {
...@@ -876,9 +912,23 @@ static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov, ...@@ -876,9 +912,23 @@ static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov,
err = fuse_copy_one(&cs, &oh, sizeof(oh)); err = fuse_copy_one(&cs, &oh, sizeof(oh));
if (err) if (err)
goto err_finish; goto err_finish;
err = -EINVAL; err = -EINVAL;
if (!oh.unique || oh.error <= -1000 || oh.error > 0 || if (oh.len != nbytes)
oh.len != nbytes) goto err_finish;
/*
* Zero oh.unique indicates unsolicited notification message
* and error contains notification code.
*/
if (!oh.unique) {
err = fuse_notify(fc, oh.error, nbytes - sizeof(oh), &cs);
fuse_copy_finish(&cs);
return err ? err : nbytes;
}
err = -EINVAL;
if (oh.error <= -1000 || oh.error > 0)
goto err_finish; goto err_finish;
spin_lock(&fc->lock); spin_lock(&fc->lock);
...@@ -966,6 +1016,8 @@ static unsigned fuse_dev_poll(struct file *file, poll_table *wait) ...@@ -966,6 +1016,8 @@ static unsigned fuse_dev_poll(struct file *file, poll_table *wait)
* This function releases and reacquires fc->lock * This function releases and reacquires fc->lock
*/ */
static void end_requests(struct fuse_conn *fc, struct list_head *head) static void end_requests(struct fuse_conn *fc, struct list_head *head)
__releases(&fc->lock)
__acquires(&fc->lock)
{ {
while (!list_empty(head)) { while (!list_empty(head)) {
struct fuse_req *req; struct fuse_req *req;
...@@ -988,7 +1040,8 @@ static void end_requests(struct fuse_conn *fc, struct list_head *head) ...@@ -988,7 +1040,8 @@ static void end_requests(struct fuse_conn *fc, struct list_head *head)
* locked). * locked).
*/ */
static void end_io_requests(struct fuse_conn *fc) static void end_io_requests(struct fuse_conn *fc)
__releases(fc->lock) __acquires(fc->lock) __releases(&fc->lock)
__acquires(&fc->lock)
{ {
while (!list_empty(&fc->io)) { while (!list_empty(&fc->io)) {
struct fuse_req *req = struct fuse_req *req =
...@@ -1002,11 +1055,11 @@ static void end_io_requests(struct fuse_conn *fc) ...@@ -1002,11 +1055,11 @@ static void end_io_requests(struct fuse_conn *fc)
wake_up(&req->waitq); wake_up(&req->waitq);
if (end) { if (end) {
req->end = NULL; req->end = NULL;
/* The end function will consume this reference */
__fuse_get_request(req); __fuse_get_request(req);
spin_unlock(&fc->lock); spin_unlock(&fc->lock);
wait_event(req->waitq, !req->locked); wait_event(req->waitq, !req->locked);
end(fc, req); end(fc, req);
fuse_put_request(fc, req);
spin_lock(&fc->lock); spin_lock(&fc->lock);
} }
} }
......
/* /*
FUSE: Filesystem in Userspace FUSE: Filesystem in Userspace
Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL. This program can be distributed under the terms of the GNU GPL.
See the file COPYING. See the file COPYING.
...@@ -189,7 +189,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) ...@@ -189,7 +189,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
parent = dget_parent(entry); parent = dget_parent(entry);
fuse_lookup_init(fc, req, get_node_id(parent->d_inode), fuse_lookup_init(fc, req, get_node_id(parent->d_inode),
&entry->d_name, &outarg); &entry->d_name, &outarg);
request_send(fc, req); fuse_request_send(fc, req);
dput(parent); dput(parent);
err = req->out.h.error; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
...@@ -204,7 +204,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) ...@@ -204,7 +204,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
return 0; return 0;
} }
spin_lock(&fc->lock); spin_lock(&fc->lock);
fi->nlookup ++; fi->nlookup++;
spin_unlock(&fc->lock); spin_unlock(&fc->lock);
} }
fuse_put_request(fc, forget_req); fuse_put_request(fc, forget_req);
...@@ -283,7 +283,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, ...@@ -283,7 +283,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
attr_version = fuse_get_attr_version(fc); attr_version = fuse_get_attr_version(fc);
fuse_lookup_init(fc, req, nodeid, name, outarg); fuse_lookup_init(fc, req, nodeid, name, outarg);
request_send(fc, req); fuse_request_send(fc, req);
err = req->out.h.error; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
/* Zero nodeid is same as -ENOENT, but with valid timeout */ /* Zero nodeid is same as -ENOENT, but with valid timeout */
...@@ -369,7 +369,7 @@ static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff, ...@@ -369,7 +369,7 @@ static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff,
{ {
fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE); fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE);
ff->reserved_req->force = 1; ff->reserved_req->force = 1;
request_send(fc, ff->reserved_req); fuse_request_send(fc, ff->reserved_req);
fuse_put_request(fc, ff->reserved_req); fuse_put_request(fc, ff->reserved_req);
kfree(ff); kfree(ff);
} }
...@@ -408,7 +408,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, ...@@ -408,7 +408,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
goto out_put_forget_req; goto out_put_forget_req;
err = -ENOMEM; err = -ENOMEM;
ff = fuse_file_alloc(); ff = fuse_file_alloc(fc);
if (!ff) if (!ff)
goto out_put_request; goto out_put_request;
...@@ -432,7 +432,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, ...@@ -432,7 +432,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
req->out.args[0].value = &outentry; req->out.args[0].value = &outentry;
req->out.args[1].size = sizeof(outopen); req->out.args[1].size = sizeof(outopen);
req->out.args[1].value = &outopen; req->out.args[1].value = &outopen;
request_send(fc, req); fuse_request_send(fc, req);
err = req->out.h.error; err = req->out.h.error;
if (err) { if (err) {
if (err == -ENOSYS) if (err == -ENOSYS)
...@@ -502,7 +502,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, ...@@ -502,7 +502,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
else else
req->out.args[0].size = sizeof(outarg); req->out.args[0].size = sizeof(outarg);
req->out.args[0].value = &outarg; req->out.args[0].value = &outarg;
request_send(fc, req); fuse_request_send(fc, req);
err = req->out.h.error; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
if (err) if (err)
...@@ -631,15 +631,17 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) ...@@ -631,15 +631,17 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
req->in.numargs = 1; req->in.numargs = 1;
req->in.args[0].size = entry->d_name.len + 1; req->in.args[0].size = entry->d_name.len + 1;
req->in.args[0].value = entry->d_name.name; req->in.args[0].value = entry->d_name.name;
request_send(fc, req); fuse_request_send(fc, req);
err = req->out.h.error; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
if (!err) { if (!err) {
struct inode *inode = entry->d_inode; struct inode *inode = entry->d_inode;
/* Set nlink to zero so the inode can be cleared, if /*
the inode does have more links this will be * Set nlink to zero so the inode can be cleared, if the inode
discovered at the next lookup/getattr */ * does have more links this will be discovered at the next
* lookup/getattr.
*/
clear_nlink(inode); clear_nlink(inode);
fuse_invalidate_attr(inode); fuse_invalidate_attr(inode);
fuse_invalidate_attr(dir); fuse_invalidate_attr(dir);
...@@ -662,7 +664,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry) ...@@ -662,7 +664,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
req->in.numargs = 1; req->in.numargs = 1;
req->in.args[0].size = entry->d_name.len + 1; req->in.args[0].size = entry->d_name.len + 1;
req->in.args[0].value = entry->d_name.name; req->in.args[0].value = entry->d_name.name;
request_send(fc, req); fuse_request_send(fc, req);
err = req->out.h.error; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
if (!err) { if (!err) {
...@@ -695,7 +697,7 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent, ...@@ -695,7 +697,7 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
req->in.args[1].value = oldent->d_name.name; req->in.args[1].value = oldent->d_name.name;
req->in.args[2].size = newent->d_name.len + 1; req->in.args[2].size = newent->d_name.len + 1;
req->in.args[2].value = newent->d_name.name; req->in.args[2].value = newent->d_name.name;
request_send(fc, req); fuse_request_send(fc, req);
err = req->out.h.error; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
if (!err) { if (!err) {
...@@ -811,7 +813,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, ...@@ -811,7 +813,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
else else
req->out.args[0].size = sizeof(outarg); req->out.args[0].size = sizeof(outarg);
req->out.args[0].value = &outarg; req->out.args[0].value = &outarg;
request_send(fc, req); fuse_request_send(fc, req);
err = req->out.h.error; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
if (!err) { if (!err) {
...@@ -911,7 +913,7 @@ static int fuse_access(struct inode *inode, int mask) ...@@ -911,7 +913,7 @@ static int fuse_access(struct inode *inode, int mask)
req->in.numargs = 1; req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg); req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg; req->in.args[0].value = &inarg;
request_send(fc, req); fuse_request_send(fc, req);
err = req->out.h.error; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
if (err == -ENOSYS) { if (err == -ENOSYS) {
...@@ -1033,7 +1035,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) ...@@ -1033,7 +1035,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
req->num_pages = 1; req->num_pages = 1;
req->pages[0] = page; req->pages[0] = page;
fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR); fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR);
request_send(fc, req); fuse_request_send(fc, req);
nbytes = req->out.args[0].size; nbytes = req->out.args[0].size;
err = req->out.h.error; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
...@@ -1067,7 +1069,7 @@ static char *read_link(struct dentry *dentry) ...@@ -1067,7 +1069,7 @@ static char *read_link(struct dentry *dentry)
req->out.numargs = 1; req->out.numargs = 1;
req->out.args[0].size = PAGE_SIZE - 1; req->out.args[0].size = PAGE_SIZE - 1;
req->out.args[0].value = link; req->out.args[0].value = link;
request_send(fc, req); fuse_request_send(fc, req);
if (req->out.h.error) { if (req->out.h.error) {
free_page((unsigned long) link); free_page((unsigned long) link);
link = ERR_PTR(req->out.h.error); link = ERR_PTR(req->out.h.error);
...@@ -1273,7 +1275,7 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr, ...@@ -1273,7 +1275,7 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
else else
req->out.args[0].size = sizeof(outarg); req->out.args[0].size = sizeof(outarg);
req->out.args[0].value = &outarg; req->out.args[0].value = &outarg;
request_send(fc, req); fuse_request_send(fc, req);
err = req->out.h.error; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
if (err) { if (err) {
...@@ -1367,7 +1369,7 @@ static int fuse_setxattr(struct dentry *entry, const char *name, ...@@ -1367,7 +1369,7 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
req->in.args[1].value = name; req->in.args[1].value = name;
req->in.args[2].size = size; req->in.args[2].size = size;
req->in.args[2].value = value; req->in.args[2].value = value;
request_send(fc, req); fuse_request_send(fc, req);
err = req->out.h.error; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
if (err == -ENOSYS) { if (err == -ENOSYS) {
...@@ -1413,7 +1415,7 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name, ...@@ -1413,7 +1415,7 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
req->out.args[0].size = sizeof(outarg); req->out.args[0].size = sizeof(outarg);
req->out.args[0].value = &outarg; req->out.args[0].value = &outarg;
} }
request_send(fc, req); fuse_request_send(fc, req);
ret = req->out.h.error; ret = req->out.h.error;
if (!ret) if (!ret)
ret = size ? req->out.args[0].size : outarg.size; ret = size ? req->out.args[0].size : outarg.size;
...@@ -1463,7 +1465,7 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) ...@@ -1463,7 +1465,7 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
req->out.args[0].size = sizeof(outarg); req->out.args[0].size = sizeof(outarg);
req->out.args[0].value = &outarg; req->out.args[0].value = &outarg;
} }
request_send(fc, req); fuse_request_send(fc, req);
ret = req->out.h.error; ret = req->out.h.error;
if (!ret) if (!ret)
ret = size ? req->out.args[0].size : outarg.size; ret = size ? req->out.args[0].size : outarg.size;
...@@ -1496,7 +1498,7 @@ static int fuse_removexattr(struct dentry *entry, const char *name) ...@@ -1496,7 +1498,7 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
req->in.numargs = 1; req->in.numargs = 1;
req->in.args[0].size = strlen(name) + 1; req->in.args[0].size = strlen(name) + 1;
req->in.args[0].value = name; req->in.args[0].value = name;
request_send(fc, req); fuse_request_send(fc, req);
err = req->out.h.error; err = req->out.h.error;
fuse_put_request(fc, req); fuse_put_request(fc, req);
if (err == -ENOSYS) { if (err == -ENOSYS) {
......
This diff is collapsed.
/* /*
FUSE: Filesystem in Userspace FUSE: Filesystem in Userspace
Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL. This program can be distributed under the terms of the GNU GPL.
See the file COPYING. See the file COPYING.
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/rbtree.h>
#include <linux/poll.h>
/** Max number of pages that can be used in a single read request */ /** Max number of pages that can be used in a single read request */
#define FUSE_MAX_PAGES_PER_REQ 32 #define FUSE_MAX_PAGES_PER_REQ 32
...@@ -100,6 +102,9 @@ struct fuse_file { ...@@ -100,6 +102,9 @@ struct fuse_file {
/** Request reserved for flush and release */ /** Request reserved for flush and release */
struct fuse_req *reserved_req; struct fuse_req *reserved_req;
/** Kernel file handle guaranteed to be unique */
u64 kh;
/** File handle used by userspace */ /** File handle used by userspace */
u64 fh; u64 fh;
...@@ -108,6 +113,12 @@ struct fuse_file { ...@@ -108,6 +113,12 @@ struct fuse_file {
/** Entry on inode's write_files list */ /** Entry on inode's write_files list */
struct list_head write_entry; struct list_head write_entry;
/** RB node to be linked on fuse_conn->polled_files */
struct rb_node polled_node;
/** Wait queue head for poll */
wait_queue_head_t poll_wait;
}; };
/** One input argument of a request */ /** One input argument of a request */
...@@ -322,6 +333,12 @@ struct fuse_conn { ...@@ -322,6 +333,12 @@ struct fuse_conn {
/** The list of requests under I/O */ /** The list of requests under I/O */
struct list_head io; struct list_head io;
/** The next unique kernel file handle */
u64 khctr;
/** rbtree of fuse_files waiting for poll events indexed by ph */
struct rb_root polled_files;
/** Number of requests currently in the background */ /** Number of requests currently in the background */
unsigned num_background; unsigned num_background;
...@@ -355,19 +372,19 @@ struct fuse_conn { ...@@ -355,19 +372,19 @@ struct fuse_conn {
/** Connection failed (version mismatch). Cannot race with /** Connection failed (version mismatch). Cannot race with
setting other bitfields since it is only set once in INIT setting other bitfields since it is only set once in INIT
reply, before any other request, and never cleared */ reply, before any other request, and never cleared */
unsigned conn_error : 1; unsigned conn_error:1;
/** Connection successful. Only set in INIT */ /** Connection successful. Only set in INIT */
unsigned conn_init : 1; unsigned conn_init:1;
/** Do readpages asynchronously? Only set in INIT */ /** Do readpages asynchronously? Only set in INIT */
unsigned async_read : 1; unsigned async_read:1;
/** Do not send separate SETATTR request before open(O_TRUNC) */ /** Do not send separate SETATTR request before open(O_TRUNC) */
unsigned atomic_o_trunc : 1; unsigned atomic_o_trunc:1;
/** Filesystem supports NFS exporting. Only set in INIT */ /** Filesystem supports NFS exporting. Only set in INIT */
unsigned export_support : 1; unsigned export_support:1;
/* /*
* The following bitfields are only for optimization purposes * The following bitfields are only for optimization purposes
...@@ -375,43 +392,46 @@ struct fuse_conn { ...@@ -375,43 +392,46 @@ struct fuse_conn {
*/ */
/** Is fsync not implemented by fs? */ /** Is fsync not implemented by fs? */
unsigned no_fsync : 1; unsigned no_fsync:1;
/** Is fsyncdir not implemented by fs? */ /** Is fsyncdir not implemented by fs? */
unsigned no_fsyncdir : 1; unsigned no_fsyncdir:1;
/** Is flush not implemented by fs? */ /** Is flush not implemented by fs? */
unsigned no_flush : 1; unsigned no_flush:1;
/** Is setxattr not implemented by fs? */ /** Is setxattr not implemented by fs? */
unsigned no_setxattr : 1; unsigned no_setxattr:1;
/** Is getxattr not implemented by fs? */ /** Is getxattr not implemented by fs? */
unsigned no_getxattr : 1; unsigned no_getxattr:1;
/** Is listxattr not implemented by fs? */ /** Is listxattr not implemented by fs? */
unsigned no_listxattr : 1; unsigned no_listxattr:1;
/** Is removexattr not implemented by fs? */ /** Is removexattr not implemented by fs? */
unsigned no_removexattr : 1; unsigned no_removexattr:1;
/** Are file locking primitives not implemented by fs? */ /** Are file locking primitives not implemented by fs? */
unsigned no_lock : 1; unsigned no_lock:1;
/** Is access not implemented by fs? */ /** Is access not implemented by fs? */
unsigned no_access : 1; unsigned no_access:1;
/** Is create not implemented by fs? */ /** Is create not implemented by fs? */
unsigned no_create : 1; unsigned no_create:1;
/** Is interrupt not implemented by fs? */ /** Is interrupt not implemented by fs? */
unsigned no_interrupt : 1; unsigned no_interrupt:1;
/** Is bmap not implemented by fs? */ /** Is bmap not implemented by fs? */
unsigned no_bmap : 1; unsigned no_bmap:1;
/** Is poll not implemented by fs? */
unsigned no_poll:1;
/** Do multi-page cached writes */ /** Do multi-page cached writes */
unsigned big_writes : 1; unsigned big_writes:1;
/** The number of requests waiting for completion */ /** The number of requests waiting for completion */
atomic_t num_waiting; atomic_t num_waiting;
...@@ -445,6 +465,9 @@ struct fuse_conn { ...@@ -445,6 +465,9 @@ struct fuse_conn {
/** Version counter for attribute changes */ /** Version counter for attribute changes */
u64 attr_version; u64 attr_version;
/** Called on final put */
void (*release)(struct fuse_conn *);
}; };
static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
...@@ -499,7 +522,7 @@ void fuse_read_fill(struct fuse_req *req, struct file *file, ...@@ -499,7 +522,7 @@ void fuse_read_fill(struct fuse_req *req, struct file *file,
*/ */
int fuse_open_common(struct inode *inode, struct file *file, int isdir); int fuse_open_common(struct inode *inode, struct file *file, int isdir);
struct fuse_file *fuse_file_alloc(void); struct fuse_file *fuse_file_alloc(struct fuse_conn *fc);
void fuse_file_free(struct fuse_file *ff); void fuse_file_free(struct fuse_file *ff);
void fuse_finish_open(struct inode *inode, struct file *file, void fuse_finish_open(struct inode *inode, struct file *file,
struct fuse_file *ff, struct fuse_open_out *outarg); struct fuse_file *ff, struct fuse_open_out *outarg);
...@@ -518,6 +541,12 @@ int fuse_release_common(struct inode *inode, struct file *file, int isdir); ...@@ -518,6 +541,12 @@ int fuse_release_common(struct inode *inode, struct file *file, int isdir);
int fuse_fsync_common(struct file *file, struct dentry *de, int datasync, int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
int isdir); int isdir);
/**
* Notify poll wakeup
*/
int fuse_notify_poll_wakeup(struct fuse_conn *fc,
struct fuse_notify_poll_wakeup_out *outarg);
/** /**
* Initialize file operations on a regular file * Initialize file operations on a regular file
*/ */
...@@ -593,19 +622,20 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req); ...@@ -593,19 +622,20 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req);
/** /**
* Send a request (synchronous) * Send a request (synchronous)
*/ */
void request_send(struct fuse_conn *fc, struct fuse_req *req); void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req);
/** /**
* Send a request with no reply * Send a request with no reply
*/ */
void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req); void fuse_request_send_noreply(struct fuse_conn *fc, struct fuse_req *req);
/** /**
* Send a request in the background * Send a request in the background
*/ */
void request_send_background(struct fuse_conn *fc, struct fuse_req *req); void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req);
void request_send_background_locked(struct fuse_conn *fc, struct fuse_req *req); void fuse_request_send_background_locked(struct fuse_conn *fc,
struct fuse_req *req);
/* Abort all requests */ /* Abort all requests */
void fuse_abort_conn(struct fuse_conn *fc); void fuse_abort_conn(struct fuse_conn *fc);
...@@ -622,6 +652,11 @@ void fuse_invalidate_entry_cache(struct dentry *entry); ...@@ -622,6 +652,11 @@ void fuse_invalidate_entry_cache(struct dentry *entry);
*/ */
struct fuse_conn *fuse_conn_get(struct fuse_conn *fc); struct fuse_conn *fuse_conn_get(struct fuse_conn *fc);
/**
* Initialize fuse_conn
*/
int fuse_conn_init(struct fuse_conn *fc, struct super_block *sb);
/** /**
* Release reference to fuse_conn * Release reference to fuse_conn
*/ */
......
/* /*
FUSE: Filesystem in Userspace FUSE: Filesystem in Userspace
Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL. This program can be distributed under the terms of the GNU GPL.
See the file COPYING. See the file COPYING.
...@@ -37,10 +37,10 @@ struct fuse_mount_data { ...@@ -37,10 +37,10 @@ struct fuse_mount_data {
unsigned rootmode; unsigned rootmode;
unsigned user_id; unsigned user_id;
unsigned group_id; unsigned group_id;
unsigned fd_present : 1; unsigned fd_present:1;
unsigned rootmode_present : 1; unsigned rootmode_present:1;
unsigned user_id_present : 1; unsigned user_id_present:1;
unsigned group_id_present : 1; unsigned group_id_present:1;
unsigned flags; unsigned flags;
unsigned max_read; unsigned max_read;
unsigned blksize; unsigned blksize;
...@@ -94,7 +94,7 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, ...@@ -94,7 +94,7 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
req->in.numargs = 1; req->in.numargs = 1;
req->in.args[0].size = sizeof(struct fuse_forget_in); req->in.args[0].size = sizeof(struct fuse_forget_in);
req->in.args[0].value = inarg; req->in.args[0].value = inarg;
request_send_noreply(fc, req); fuse_request_send_noreply(fc, req);
} }
static void fuse_clear_inode(struct inode *inode) static void fuse_clear_inode(struct inode *inode)
...@@ -250,7 +250,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, ...@@ -250,7 +250,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
fi = get_fuse_inode(inode); fi = get_fuse_inode(inode);
spin_lock(&fc->lock); spin_lock(&fc->lock);
fi->nlookup ++; fi->nlookup++;
spin_unlock(&fc->lock); spin_unlock(&fc->lock);
fuse_change_attributes(inode, attr, attr_valid, attr_version); fuse_change_attributes(inode, attr, attr_valid, attr_version);
...@@ -269,7 +269,7 @@ static void fuse_send_destroy(struct fuse_conn *fc) ...@@ -269,7 +269,7 @@ static void fuse_send_destroy(struct fuse_conn *fc)
fc->destroy_req = NULL; fc->destroy_req = NULL;
req->in.h.opcode = FUSE_DESTROY; req->in.h.opcode = FUSE_DESTROY;
req->force = 1; req->force = 1;
request_send(fc, req); fuse_request_send(fc, req);
fuse_put_request(fc, req); fuse_put_request(fc, req);
} }
} }
...@@ -334,7 +334,7 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -334,7 +334,7 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
req->out.args[0].size = req->out.args[0].size =
fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg); fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg);
req->out.args[0].value = &outarg; req->out.args[0].value = &outarg;
request_send(fc, req); fuse_request_send(fc, req);
err = req->out.h.error; err = req->out.h.error;
if (!err) if (!err)
convert_fuse_statfs(buf, &outarg.st); convert_fuse_statfs(buf, &outarg.st);
...@@ -462,13 +462,11 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) ...@@ -462,13 +462,11 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
return 0; return 0;
} }
static struct fuse_conn *new_conn(struct super_block *sb) int fuse_conn_init(struct fuse_conn *fc, struct super_block *sb)
{ {
struct fuse_conn *fc;
int err; int err;
fc = kzalloc(sizeof(*fc), GFP_KERNEL); memset(fc, 0, sizeof(*fc));
if (fc) {
spin_lock_init(&fc->lock); spin_lock_init(&fc->lock);
mutex_init(&fc->inst_mutex); mutex_init(&fc->inst_mutex);
atomic_set(&fc->count, 1); atomic_set(&fc->count, 1);
...@@ -480,15 +478,18 @@ static struct fuse_conn *new_conn(struct super_block *sb) ...@@ -480,15 +478,18 @@ static struct fuse_conn *new_conn(struct super_block *sb)
INIT_LIST_HEAD(&fc->io); INIT_LIST_HEAD(&fc->io);
INIT_LIST_HEAD(&fc->interrupts); INIT_LIST_HEAD(&fc->interrupts);
INIT_LIST_HEAD(&fc->bg_queue); INIT_LIST_HEAD(&fc->bg_queue);
INIT_LIST_HEAD(&fc->entry);
atomic_set(&fc->num_waiting, 0); atomic_set(&fc->num_waiting, 0);
fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
fc->bdi.unplug_io_fn = default_unplug_io_fn; fc->bdi.unplug_io_fn = default_unplug_io_fn;
/* fuse does it's own writeback accounting */ /* fuse does it's own writeback accounting */
fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB; fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB;
fc->khctr = 0;
fc->polled_files = RB_ROOT;
fc->dev = sb->s_dev; fc->dev = sb->s_dev;
err = bdi_init(&fc->bdi); err = bdi_init(&fc->bdi);
if (err) if (err)
goto error_kfree; goto error_mutex_destroy;
if (sb->s_bdev) { if (sb->s_bdev) {
err = bdi_register(&fc->bdi, NULL, "%u:%u-fuseblk", err = bdi_register(&fc->bdi, NULL, "%u:%u-fuseblk",
MAJOR(fc->dev), MINOR(fc->dev)); MAJOR(fc->dev), MINOR(fc->dev));
...@@ -514,16 +515,16 @@ static struct fuse_conn *new_conn(struct super_block *sb) ...@@ -514,16 +515,16 @@ static struct fuse_conn *new_conn(struct super_block *sb)
fc->blocked = 1; fc->blocked = 1;
fc->attr_version = 1; fc->attr_version = 1;
get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
}
return fc;
error_bdi_destroy: return 0;
error_bdi_destroy:
bdi_destroy(&fc->bdi); bdi_destroy(&fc->bdi);
error_kfree: error_mutex_destroy:
mutex_destroy(&fc->inst_mutex); mutex_destroy(&fc->inst_mutex);
kfree(fc); return err;
return NULL;
} }
EXPORT_SYMBOL_GPL(fuse_conn_init);
void fuse_conn_put(struct fuse_conn *fc) void fuse_conn_put(struct fuse_conn *fc)
{ {
...@@ -532,7 +533,7 @@ void fuse_conn_put(struct fuse_conn *fc) ...@@ -532,7 +533,7 @@ void fuse_conn_put(struct fuse_conn *fc)
fuse_request_free(fc->destroy_req); fuse_request_free(fc->destroy_req);
mutex_destroy(&fc->inst_mutex); mutex_destroy(&fc->inst_mutex);
bdi_destroy(&fc->bdi); bdi_destroy(&fc->bdi);
kfree(fc); fc->release(fc);
} }
} }
...@@ -542,7 +543,7 @@ struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) ...@@ -542,7 +543,7 @@ struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
return fc; return fc;
} }
static struct inode *get_root_inode(struct super_block *sb, unsigned mode) static struct inode *fuse_get_root_inode(struct super_block *sb, unsigned mode)
{ {
struct fuse_attr attr; struct fuse_attr attr;
memset(&attr, 0, sizeof(attr)); memset(&attr, 0, sizeof(attr));
...@@ -553,8 +554,7 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode) ...@@ -553,8 +554,7 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
return fuse_iget(sb, 1, 0, &attr, 0, 0); return fuse_iget(sb, 1, 0, &attr, 0, 0);
} }
struct fuse_inode_handle struct fuse_inode_handle {
{
u64 nodeid; u64 nodeid;
u32 generation; u32 generation;
}; };
...@@ -761,7 +761,6 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) ...@@ -761,7 +761,6 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
fc->max_write = max_t(unsigned, 4096, fc->max_write); fc->max_write = max_t(unsigned, 4096, fc->max_write);
fc->conn_init = 1; fc->conn_init = 1;
} }
fuse_put_request(fc, req);
fc->blocked = 0; fc->blocked = 0;
wake_up_all(&fc->blocked_waitq); wake_up_all(&fc->blocked_waitq);
} }
...@@ -787,7 +786,12 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) ...@@ -787,7 +786,12 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
req->out.args[0].size = sizeof(struct fuse_init_out); req->out.args[0].size = sizeof(struct fuse_init_out);
req->out.args[0].value = &req->misc.init_out; req->out.args[0].value = &req->misc.init_out;
req->end = process_init_reply; req->end = process_init_reply;
request_send_background(fc, req); fuse_request_send_background(fc, req);
}
static void fuse_free_conn(struct fuse_conn *fc)
{
kfree(fc);
} }
static int fuse_fill_super(struct super_block *sb, void *data, int silent) static int fuse_fill_super(struct super_block *sb, void *data, int silent)
...@@ -828,10 +832,17 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) ...@@ -828,10 +832,17 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
if (file->f_op != &fuse_dev_operations) if (file->f_op != &fuse_dev_operations)
return -EINVAL; return -EINVAL;
fc = new_conn(sb); fc = kmalloc(sizeof(*fc), GFP_KERNEL);
if (!fc) if (!fc)
return -ENOMEM; return -ENOMEM;
err = fuse_conn_init(fc, sb);
if (err) {
kfree(fc);
return err;
}
fc->release = fuse_free_conn;
fc->flags = d.flags; fc->flags = d.flags;
fc->user_id = d.user_id; fc->user_id = d.user_id;
fc->group_id = d.group_id; fc->group_id = d.group_id;
...@@ -841,7 +852,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) ...@@ -841,7 +852,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
sb->s_fs_info = fc; sb->s_fs_info = fc;
err = -ENOMEM; err = -ENOMEM;
root = get_root_inode(sb, d.rootmode); root = fuse_get_root_inode(sb, d.rootmode);
if (!root) if (!root)
goto err; goto err;
...@@ -952,7 +963,7 @@ static inline void unregister_fuseblk(void) ...@@ -952,7 +963,7 @@ static inline void unregister_fuseblk(void)
static void fuse_inode_init_once(void *foo) static void fuse_inode_init_once(void *foo)
{ {
struct inode * inode = foo; struct inode *inode = foo;
inode_init_once(inode); inode_init_once(inode);
} }
...@@ -1031,7 +1042,7 @@ static int __init fuse_init(void) ...@@ -1031,7 +1042,7 @@ static int __init fuse_init(void)
{ {
int res; int res;
printk("fuse init (API version %i.%i)\n", printk(KERN_INFO "fuse init (API version %i.%i)\n",
FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
INIT_LIST_HEAD(&fuse_conn_list); INIT_LIST_HEAD(&fuse_conn_list);
......
/* /*
FUSE: Filesystem in Userspace FUSE: Filesystem in Userspace
Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL. This program can be distributed under the terms of the GNU GPL.
See the file COPYING. See the file COPYING.
...@@ -20,29 +20,27 @@ ...@@ -20,29 +20,27 @@
* *
* 7.10 * 7.10
* - add nonseekable open flag * - add nonseekable open flag
*
* 7.11
* - add IOCTL message
* - add unsolicited notification support
* - add POLL message and NOTIFY_POLL notification
*/ */
#ifndef _LINUX_FUSE_H #ifndef _LINUX_FUSE_H
#define _LINUX_FUSE_H #define _LINUX_FUSE_H
#include <asm/types.h> #include <linux/types.h>
#include <linux/major.h>
/** Version number of this interface */ /** Version number of this interface */
#define FUSE_KERNEL_VERSION 7 #define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */ /** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 10 #define FUSE_KERNEL_MINOR_VERSION 11
/** The node ID of the root inode */ /** The node ID of the root inode */
#define FUSE_ROOT_ID 1 #define FUSE_ROOT_ID 1
/** The major number of the fuse character device */
#define FUSE_MAJOR MISC_MAJOR
/** The minor number of the fuse character device */
#define FUSE_MINOR 229
/* Make sure all structures are padded to 64bit boundary, so 32bit /* Make sure all structures are padded to 64bit boundary, so 32bit
userspace works under 64bit kernels */ userspace works under 64bit kernels */
...@@ -151,6 +149,28 @@ struct fuse_file_lock { ...@@ -151,6 +149,28 @@ struct fuse_file_lock {
*/ */
#define FUSE_READ_LOCKOWNER (1 << 1) #define FUSE_READ_LOCKOWNER (1 << 1)
/**
* Ioctl flags
*
* FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
* FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
* FUSE_IOCTL_RETRY: retry with new iovecs
*
* FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
*/
#define FUSE_IOCTL_COMPAT (1 << 0)
#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
#define FUSE_IOCTL_RETRY (1 << 2)
#define FUSE_IOCTL_MAX_IOV 256
/**
* Poll flags
*
* FUSE_POLL_SCHEDULE_NOTIFY: request poll notify
*/
#define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0)
enum fuse_opcode { enum fuse_opcode {
FUSE_LOOKUP = 1, FUSE_LOOKUP = 1,
FUSE_FORGET = 2, /* no reply */ FUSE_FORGET = 2, /* no reply */
...@@ -188,6 +208,13 @@ enum fuse_opcode { ...@@ -188,6 +208,13 @@ enum fuse_opcode {
FUSE_INTERRUPT = 36, FUSE_INTERRUPT = 36,
FUSE_BMAP = 37, FUSE_BMAP = 37,
FUSE_DESTROY = 38, FUSE_DESTROY = 38,
FUSE_IOCTL = 39,
FUSE_POLL = 40,
};
enum fuse_notify_code {
FUSE_NOTIFY_POLL = 1,
FUSE_NOTIFY_CODE_MAX,
}; };
/* The read buffer is required to be at least 8k, but may be much larger */ /* The read buffer is required to be at least 8k, but may be much larger */
...@@ -388,6 +415,38 @@ struct fuse_bmap_out { ...@@ -388,6 +415,38 @@ struct fuse_bmap_out {
__u64 block; __u64 block;
}; };
struct fuse_ioctl_in {
__u64 fh;
__u32 flags;
__u32 cmd;
__u64 arg;
__u32 in_size;
__u32 out_size;
};
struct fuse_ioctl_out {
__s32 result;
__u32 flags;
__u32 in_iovs;
__u32 out_iovs;
};
struct fuse_poll_in {
__u64 fh;
__u64 kh;
__u32 flags;
__u32 padding;
};
struct fuse_poll_out {
__u32 revents;
__u32 padding;
};
struct fuse_notify_poll_wakeup_out {
__u64 kh;
};
struct fuse_in_header { struct fuse_in_header {
__u32 len; __u32 len;
__u32 opcode; __u32 opcode;
......
...@@ -23,13 +23,13 @@ ...@@ -23,13 +23,13 @@
#define STORE_QUEUE_MINOR 155 #define STORE_QUEUE_MINOR 155
#define I2O_MINOR 166 #define I2O_MINOR 166
#define MICROCODE_MINOR 184 #define MICROCODE_MINOR 184
#define TUN_MINOR 200
#define MWAVE_MINOR 219 /* ACP/Mwave Modem */ #define MWAVE_MINOR 219 /* ACP/Mwave Modem */
#define MPT_MINOR 220 #define MPT_MINOR 220
#define MISC_DYNAMIC_MINOR 255
#define TUN_MINOR 200
#define HPET_MINOR 228 #define HPET_MINOR 228
#define FUSE_MINOR 229
#define KVM_MINOR 232 #define KVM_MINOR 232
#define MISC_DYNAMIC_MINOR 255
struct device; struct device;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment