/*
FUSE: Filesystem in Userspace
- Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
+ Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
{
struct fuse_req *req;
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
BUG_ON(list_empty(&fc->unused_list));
req = list_entry(fc->unused_list.next, struct fuse_req, list);
list_del_init(&req->list);
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
fuse_request_init(req);
req->preallocated = 1;
req->in.h.uid = current->fsuid;
return do_get_request(fc);
}
-/* Must be called with fuse_lock held */
+/* Must be called with fc->lock held */
static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req)
{
if (req->preallocated) {
void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
{
if (atomic_dec_and_test(&req->count)) {
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
fuse_putback_request(fc, req);
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
}
}
fuse_putback_request(fc, req);
}
-void fuse_release_background(struct fuse_req *req)
+void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req)
{
iput(req->inode);
iput(req->inode2);
if (req->file)
fput(req->file);
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
list_del(&req->bg_entry);
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
}
/*
* interrupted and put in the background, it will return with an error
* and hence never be reset and reused.
*
- * Called with fuse_lock, unlocks it
+ * Called with fc->lock, unlocks it
*/
static void request_end(struct fuse_conn *fc, struct fuse_req *req)
{
if (!req->background) {
wake_up(&req->waitq);
fuse_put_request_locked(fc, req);
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
} else {
void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
req->end = NULL;
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
down_read(&fc->sbput_sem);
if (fc->mounted)
- fuse_release_background(req);
+ fuse_release_background(fc, req);
up_read(&fc->sbput_sem);
if (end)
end(fc, req);
get_file(req->file);
}
-/* Called with fuse_lock held. Releases, and then reacquires it. */
+/* Called with fc->lock held. Releases, and then reacquires it. */
static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
{
sigset_t oldset;
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
block_sigs(&oldset);
wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED);
restore_sigs(&oldset);
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
if (req->state == FUSE_REQ_FINISHED && !req->interrupted)
return;
locked state, there mustn't be any filesystem
operation (e.g. page fault), since that could lead
to deadlock */
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
wait_event(req->waitq, !req->locked);
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
}
if (req->state == FUSE_REQ_PENDING) {
list_del(&req->list);
void request_send(struct fuse_conn *fc, struct fuse_req *req)
{
req->isreply = 1;
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
if (!fc->connected)
req->out.h.error = -ENOTCONN;
else if (fc->conn_error)
request_wait_answer(fc, req);
}
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
}
static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
{
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
if (fc->connected) {
queue_request(fc, req);
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
} else {
req->out.h.error = -ENOTCONN;
request_end(fc, req);
void request_send_background(struct fuse_conn *fc, struct fuse_req *req)
{
req->isreply = 1;
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
background_request(fc, req);
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
request_send_nowait(fc, req);
}
* anything that could cause a page-fault. If the request was already
* interrupted bail out.
*/
-static int lock_request(struct fuse_req *req)
+static int lock_request(struct fuse_conn *fc, struct fuse_req *req)
{
int err = 0;
if (req) {
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
if (req->interrupted)
err = -ENOENT;
else
req->locked = 1;
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
}
return err;
}
* requester thread is currently waiting for it to be unlocked, so
* wake it up.
*/
-static void unlock_request(struct fuse_req *req)
+static void unlock_request(struct fuse_conn *fc, struct fuse_req *req)
{
if (req) {
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
req->locked = 0;
if (req->interrupted)
wake_up(&req->waitq);
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
}
}
struct fuse_copy_state {
+ struct fuse_conn *fc;
int write;
struct fuse_req *req;
const struct iovec *iov;
unsigned len;
};
-static void fuse_copy_init(struct fuse_copy_state *cs, int write,
- struct fuse_req *req, const struct iovec *iov,
- unsigned long nr_segs)
+static void fuse_copy_init(struct fuse_copy_state *cs, struct fuse_conn *fc,
+ int write, struct fuse_req *req,
+ const struct iovec *iov, unsigned long nr_segs)
{
memset(cs, 0, sizeof(*cs));
+ cs->fc = fc;
cs->write = write;
cs->req = req;
cs->iov = iov;
unsigned long offset;
int err;
- unlock_request(cs->req);
+ unlock_request(cs->fc, cs->req);
fuse_copy_finish(cs);
if (!cs->seglen) {
BUG_ON(!cs->nr_segs);
cs->seglen -= cs->len;
cs->addr += cs->len;
- return lock_request(cs->req);
+ return lock_request(cs->fc, cs->req);
}
/* Do as much copy to/from userspace buffer as we can */
if (signal_pending(current))
break;
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
schedule();
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&fc->waitq, &wait);
return -EPERM;
restart:
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
err = -EAGAIN;
if ((file->f_flags & O_NONBLOCK) && fc->connected &&
list_empty(&fc->pending))
request_end(fc, req);
goto restart;
}
- spin_unlock(&fuse_lock);
- fuse_copy_init(&cs, 1, req, iov, nr_segs);
+ spin_unlock(&fc->lock);
+ fuse_copy_init(&cs, fc, 1, req, iov, nr_segs);
err = fuse_copy_one(&cs, &in->h, sizeof(in->h));
if (!err)
err = fuse_copy_args(&cs, in->numargs, in->argpages,
(struct fuse_arg *) in->args, 0);
fuse_copy_finish(&cs);
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
req->locked = 0;
if (!err && req->interrupted)
err = -ENOENT;
else {
req->state = FUSE_REQ_SENT;
list_move_tail(&req->list, &fc->processing);
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
}
return reqsize;
err_unlock:
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
return err;
}
if (!fc)
return -ENODEV;
- fuse_copy_init(&cs, 0, NULL, iov, nr_segs);
+ fuse_copy_init(&cs, fc, 0, NULL, iov, nr_segs);
if (nbytes < sizeof(struct fuse_out_header))
return -EINVAL;
oh.len != nbytes)
goto err_finish;
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
err = -ENOENT;
if (!fc->connected)
goto err_unlock;
goto err_unlock;
if (req->interrupted) {
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
fuse_copy_finish(&cs);
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
request_end(fc, req);
return -ENOENT;
}
req->out.h = oh;
req->locked = 1;
cs.req = req;
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
err = copy_out_args(&cs, &req->out, nbytes);
fuse_copy_finish(&cs);
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
req->locked = 0;
if (!err) {
if (req->interrupted)
return err ? err : nbytes;
err_unlock:
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
err_finish:
fuse_copy_finish(&cs);
return err;
poll_wait(file, &fc->waitq, wait);
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
if (!fc->connected)
mask = POLLERR;
else if (!list_empty(&fc->pending))
mask |= POLLIN | POLLRDNORM;
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
return mask;
}
/*
* Abort all requests on the given list (pending or processing)
*
- * This function releases and reacquires fuse_lock
+ * This function releases and reacquires fc->lock
*/
static void end_requests(struct fuse_conn *fc, struct list_head *head)
{
req = list_entry(head->next, struct fuse_req, list);
req->out.h.error = -ECONNABORTED;
request_end(fc, req);
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
}
}
req->end = NULL;
/* The end function will consume this reference */
__fuse_get_request(req);
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
wait_event(req->waitq, !req->locked);
end(fc, req);
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
}
}
}
*/
void fuse_abort_conn(struct fuse_conn *fc)
{
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
if (fc->connected) {
fc->connected = 0;
end_io_requests(fc);
wake_up_all(&fc->waitq);
kill_fasync(&fc->fasync, SIGIO, POLL_IN);
}
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
}
static int fuse_dev_release(struct inode *inode, struct file *file)
{
struct fuse_conn *fc = fuse_get_conn(file);
if (fc) {
- spin_lock(&fuse_lock);
+ spin_lock(&fc->lock);
fc->connected = 0;
end_requests(fc, &fc->pending);
end_requests(fc, &fc->processing);
- spin_unlock(&fuse_lock);
+ spin_unlock(&fc->lock);
fasync_helper(-1, file, 0, &fc->fasync);
kobject_put(&fc->kobj);
}