diff options
author | 2004-12-13 15:22:28 +0000 | |
---|---|---|
committer | 2004-12-13 15:22:28 +0000 | |
commit | 0fcfa039c1dfb7cf9d9da132972334e33f320dd1 (patch) | |
tree | a825d1176d07fe68074cbd835c4934ba67cb72ea /kernel/dev.c | |
parent | e56818b231a231a48e2616ec083999a14516a4ae (diff) |
fix
Diffstat (limited to 'kernel/dev.c')
-rw-r--r-- | kernel/dev.c | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/kernel/dev.c b/kernel/dev.c index b2a1b90..3f2d85a 100644 --- a/kernel/dev.c +++ b/kernel/dev.c @@ -216,7 +216,11 @@ static void request_wait_answer(struct fuse_req *req, int interruptible, req->isreply = 0; return; } - req->out.h.error = -ERESTARTNOINTR; + if (!interruptible || req->sent) + req->out.h.error = -EINTR; + else + req->out.h.error = -ERESTARTNOINTR; + req->interrupted = 1; if (req->locked) { /* This is uninterruptible sleep, because data is @@ -304,6 +308,16 @@ static inline void unlock_request(struct fuse_req *req) } } + +/* Why all this complex one-page-at-a-time copying needed instead of + just copy_to/from_user()? The reason is that blocking on a page + fault must be avoided while the request is locked. This is because + if servicing that pagefault happens to be done by this filesystem, + an unbreakable deadlock can occur. So the code is careful to allow + request interruption during get_user_pages(), and only lock the + request while doing kmapped copying, which cannot block. + */ + struct fuse_copy_state { int write; struct fuse_req *req; @@ -521,7 +535,7 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov, err = -ENODEV; if (!fc->sb) goto err_unlock; - err = -EINTR; + err = -ERESTARTSYS; if (list_empty(&fc->pending)) goto err_unlock; |