diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2006-04-12 10:41:50 +0000 |
---|---|---|
committer | Miklos Szeredi <miklos@szeredi.hu> | 2006-04-12 10:41:50 +0000 |
commit | 7a2814c8b45e667822ed5c2ce0b8b2c9ce5d2692 (patch) | |
tree | 03cd5dfdc3278dc7da08d971a2d0fa0eaf6efd62 /kernel/dev.c | |
parent | baa49d21aa15f07e88fb609d40a46b860974d501 (diff) | |
download | libfuse-7a2814c8b45e667822ed5c2ce0b8b2c9ce5d2692.tar.gz |
fix
Diffstat (limited to 'kernel/dev.c')
-rw-r--r-- | kernel/dev.c | 135 |
1 files changed, 56 insertions, 79 deletions
diff --git a/kernel/dev.c b/kernel/dev.c index c968941..932e9c3 100644 --- a/kernel/dev.c +++ b/kernel/dev.c @@ -112,10 +112,8 @@ static void restore_sigs(sigset_t *oldset) */ void fuse_reset_request(struct fuse_req *req) { - int preallocated = req->preallocated; BUG_ON(atomic_read(&req->count) != 1); fuse_request_init(req); - req->preallocated = preallocated; } static void __fuse_get_request(struct fuse_req *req) @@ -130,80 +128,54 @@ static void __fuse_put_request(struct fuse_req *req) atomic_dec(&req->count); } -static struct fuse_req *do_get_request(struct fuse_conn *fc) +struct fuse_req *fuse_get_req(struct fuse_conn *fc) { struct fuse_req *req; - - 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(&fc->lock); - fuse_request_init(req); - req->preallocated = 1; - req->in.h.uid = current->fsuid; - req->in.h.gid = current->fsgid; - req->in.h.pid = current->pid; - return req; -} - -/* This can return NULL, but only in case it's interrupted by a SIGKILL */ -struct fuse_req *fuse_get_request(struct fuse_conn *fc) -{ - int intr; sigset_t oldset; + int intr; + int err; atomic_inc(&fc->num_waiting); block_sigs(&oldset); - intr = down_interruptible(&fc->outstanding_sem); + intr = wait_event_interruptible(fc->blocked_waitq, !fc->blocked); restore_sigs(&oldset); - if (intr) { - atomic_dec(&fc->num_waiting); - return NULL; - } - return do_get_request(fc); -} + err = -EINTR; + if (intr) + goto out; -/* Must be called with fc->lock held */ -static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req) -{ - if (req->preallocated) { - atomic_dec(&fc->num_waiting); - list_add(&req->list, &fc->unused_list); - } else - fuse_request_free(req); + req = fuse_request_alloc(); + err = -ENOMEM; + if (!req) + goto out; - /* If we are in debt decrease that first */ - if (fc->outstanding_debt) - fc->outstanding_debt--; - else - up(&fc->outstanding_sem); + req->in.h.uid = current->fsuid; + req->in.h.gid = current->fsgid; + req->in.h.pid = current->pid; + req->waiting = 1; + return req; + + out: + atomic_dec(&fc->num_waiting); + return ERR_PTR(err); } void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) { if (atomic_dec_and_test(&req->count)) { - spin_lock(&fc->lock); - fuse_putback_request(fc, req); - spin_unlock(&fc->lock); + if (req->waiting) + atomic_dec(&fc->num_waiting); + fuse_request_free(req); } } -static void fuse_put_request_locked(struct fuse_conn *fc, struct fuse_req *req) +void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req) { - if (atomic_dec_and_test(&req->count)) - fuse_putback_request(fc, 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(&fc->lock); - list_del(&req->bg_entry); - spin_unlock(&fc->lock); + list_del_init(&req->bg_entry); + if (fc->num_background == FUSE_MAX_BACKGROUND) { + fc->blocked = 0; + wake_up_all(&fc->blocked_waitq); + } + fc->num_background--; } /* @@ -229,21 +201,31 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) list_del(&req->list); req->state = FUSE_REQ_FINISHED; if (!req->background) { - wake_up(&req->waitq); - fuse_put_request_locked(fc, req); spin_unlock(&fc->lock); + wake_up(&req->waitq); + fuse_put_request(fc, req); } else { + struct inode *inode = req->inode; + struct inode *inode2 = req->inode2; + struct file *file = req->file; void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; req->end = NULL; + req->inode = NULL; + req->inode2 = NULL; + req->file = NULL; + if (!list_empty(&req->bg_entry)) + fuse_remove_background(fc, req); spin_unlock(&fc->lock); - down_read(&fc->sbput_sem); - if (fc->mounted) - fuse_release_background(fc, req); - up_read(&fc->sbput_sem); + if (end) end(fc, req); else fuse_put_request(fc, req); + + if (file) + fput(file); + iput(inode); + iput(inode2); } } @@ -280,6 +262,9 @@ static void background_request(struct fuse_conn *fc, struct fuse_req *req) { req->background = 1; list_add(&req->bg_entry, &fc->background); + fc->num_background++; + if (fc->num_background == FUSE_MAX_BACKGROUND) + fc->blocked = 1; if (req->inode) req->inode = igrab(req->inode); if (req->inode2) @@ -342,18 +327,12 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req) req->in.h.unique = fc->reqctr; req->in.h.len = sizeof(struct fuse_in_header) + len_args(req->in.numargs, (struct fuse_arg *) req->in.args); - if (!req->preallocated) { - /* If request is not preallocated (either FORGET or - RELEASE), then still decrease outstanding_sem, so - user can't open infinite number of files while not - processing the RELEASE requests. However for - efficiency do it without blocking, so if down() - would block, just increase the debt instead */ - if (down_trylock(&fc->outstanding_sem)) - fc->outstanding_debt++; - } list_add_tail(&req->list, &fc->pending); req->state = FUSE_REQ_PENDING; + if (!req->waiting) { + req->waiting = 1; + atomic_inc(&fc->num_waiting); + } wake_up(&fc->waitq); kill_fasync(&fc->fasync, SIGIO, POLL_IN); } @@ -383,6 +362,7 @@ void request_send(struct fuse_conn *fc, struct fuse_req *req) static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) { spin_lock(&fc->lock); + background_request(fc, req); if (fc->connected) { queue_request(fc, req); spin_unlock(&fc->lock); @@ -401,9 +381,6 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) void request_send_background(struct fuse_conn *fc, struct fuse_req *req) { req->isreply = 1; - spin_lock(&fc->lock); - background_request(fc, req); - spin_unlock(&fc->lock); request_send_nowait(fc, req); } @@ -669,8 +646,8 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov, restart: spin_lock(&fc->lock); err = -EAGAIN; - if((file->f_flags & O_NONBLOCK) && fc->connected && - list_empty(&fc->pending)) + if ((file->f_flags & O_NONBLOCK) && fc->connected && + list_empty(&fc->pending)) goto err_unlock; request_wait(fc); |