From 0fcfa039c1dfb7cf9d9da132972334e33f320dd1 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 13 Dec 2004 15:22:28 +0000 Subject: fix --- kernel/dev.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'kernel/dev.c') 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; -- cgit v1.2.3