X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=fs%2Ffuse%2Fdev.c;h=db534bcde45f6ff52a7cbfb44fcb8b49ea9bbb9d;hb=488fd99588bf23da951b524a806e44feaa1aa366;hp=66571eafbb1eb88afd8acc0e3625bdc0342207df;hpb=5a3e3b2230980cf2ce6e5e56b816dde19b993939;p=linux-2.6 diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 66571eafbb..db534bcde4 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -19,7 +19,7 @@ MODULE_ALIAS_MISCDEV(FUSE_MINOR); -static kmem_cache_t *fuse_req_cachep; +static struct kmem_cache *fuse_req_cachep; static struct fuse_conn *fuse_get_conn(struct file *file) { @@ -41,7 +41,7 @@ static void fuse_request_init(struct fuse_req *req) struct fuse_req *fuse_request_alloc(void) { - struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, SLAB_KERNEL); + struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, GFP_KERNEL); if (req) fuse_request_init(req); return req; @@ -129,7 +129,7 @@ static struct fuse_req *get_reserved_req(struct fuse_conn *fc, struct fuse_file *ff = file->private_data; do { - wait_event(fc->blocked_waitq, ff->reserved_req); + wait_event(fc->reserved_req_waitq, ff->reserved_req); spin_lock(&fc->lock); if (ff->reserved_req) { req = ff->reserved_req; @@ -155,7 +155,7 @@ static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req) fuse_request_init(req); BUG_ON(ff->reserved_req); ff->reserved_req = req; - wake_up(&fc->blocked_waitq); + wake_up_all(&fc->reserved_req_waitq); spin_unlock(&fc->lock); fput(file); } @@ -224,13 +224,13 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) fc->blocked = 0; wake_up_all(&fc->blocked_waitq); } + if (fc->num_background == FUSE_CONGESTION_THRESHOLD) { + clear_bdi_congested(&fc->bdi, READ); + clear_bdi_congested(&fc->bdi, WRITE); + } fc->num_background--; } spin_unlock(&fc->lock); - dput(req->dentry); - mntput(req->vfsmount); - if (req->file) - fput(req->file); wake_up(&req->waitq); if (end) end(fc, req); @@ -273,28 +273,41 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) queue_interrupt(fc, req); } - if (req->force) { - spin_unlock(&fc->lock); - wait_event(req->waitq, req->state == FUSE_REQ_FINISHED); - spin_lock(&fc->lock); - } else { + if (!req->force) { sigset_t oldset; /* Only fatal signals may interrupt this */ block_sigs(&oldset); wait_answer_interruptible(fc, req); restore_sigs(&oldset); + + if (req->aborted) + goto aborted; + if (req->state == FUSE_REQ_FINISHED) + return; + + /* Request is not yet in userspace, bail out */ + if (req->state == FUSE_REQ_PENDING) { + list_del(&req->list); + __fuse_put_request(req); + req->out.h.error = -EINTR; + return; + } } - if (req->aborted) - goto aborted; - if (req->state == FUSE_REQ_FINISHED) - return; + /* + * Either request is already in userspace, or it was forced. + * Wait it out. + */ + spin_unlock(&fc->lock); + wait_event(req->waitq, req->state == FUSE_REQ_FINISHED); + spin_lock(&fc->lock); - req->out.h.error = -EINTR; - req->aborted = 1; + if (!req->aborted) + return; aborted: + BUG_ON(req->state != FUSE_REQ_FINISHED); if (req->locked) { /* This is uninterruptible sleep, because data is being copied to/from the buffers of req. During @@ -305,14 +318,6 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) wait_event(req->waitq, !req->locked); spin_lock(&fc->lock); } - if (req->state == FUSE_REQ_PENDING) { - list_del(&req->list); - __fuse_put_request(req); - } else if (req->state == FUSE_REQ_SENT) { - spin_unlock(&fc->lock); - wait_event(req->waitq, req->state == FUSE_REQ_FINISHED); - spin_lock(&fc->lock); - } } static unsigned len_args(unsigned numargs, struct fuse_arg *args) @@ -378,6 +383,10 @@ static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) fc->num_background++; if (fc->num_background == FUSE_MAX_BACKGROUND) fc->blocked = 1; + if (fc->num_background == FUSE_CONGESTION_THRESHOLD) { + set_bdi_congested(&fc->bdi, READ); + set_bdi_congested(&fc->bdi, WRITE); + } queue_request(fc, req); spin_unlock(&fc->lock); @@ -738,11 +747,12 @@ static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov, fuse_copy_finish(&cs); spin_lock(&fc->lock); req->locked = 0; - if (!err && req->aborted) - err = -ENOENT; + if (req->aborted) { + request_end(fc, req); + return -ENODEV; + } if (err) { - if (!req->aborted) - req->out.h.error = -EIO; + req->out.h.error = -EIO; request_end(fc, req); return err; } @@ -1044,7 +1054,7 @@ int __init fuse_dev_init(void) int err = -ENOMEM; fuse_req_cachep = kmem_cache_create("fuse_request", sizeof(struct fuse_req), - 0, 0, NULL, NULL); + 0, 0, NULL); if (!fuse_req_cachep) goto out;