aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r--fs/fuse/dev.c39
1 files changed, 30 insertions, 9 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 6c740f860665..104a62dadb94 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -92,40 +92,52 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc)
92{ 92{
93 struct fuse_req *req; 93 struct fuse_req *req;
94 sigset_t oldset; 94 sigset_t oldset;
95 int intr;
95 int err; 96 int err;
96 97
98 atomic_inc(&fc->num_waiting);
97 block_sigs(&oldset); 99 block_sigs(&oldset);
98 err = wait_event_interruptible(fc->blocked_waitq, !fc->blocked); 100 intr = wait_event_interruptible(fc->blocked_waitq, !fc->blocked);
99 restore_sigs(&oldset); 101 restore_sigs(&oldset);
100 if (err) 102 err = -EINTR;
101 return ERR_PTR(-EINTR); 103 if (intr)
104 goto out;
102 105
103 req = fuse_request_alloc(); 106 req = fuse_request_alloc();
107 err = -ENOMEM;
104 if (!req) 108 if (!req)
105 return ERR_PTR(-ENOMEM); 109 goto out;
106 110
107 atomic_inc(&fc->num_waiting);
108 fuse_request_init(req);
109 req->in.h.uid = current->fsuid; 111 req->in.h.uid = current->fsuid;
110 req->in.h.gid = current->fsgid; 112 req->in.h.gid = current->fsgid;
111 req->in.h.pid = current->pid; 113 req->in.h.pid = current->pid;
114 req->waiting = 1;
112 return req; 115 return req;
116
117 out:
118 atomic_dec(&fc->num_waiting);
119 return ERR_PTR(err);
113} 120}
114 121
115void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) 122void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
116{ 123{
117 if (atomic_dec_and_test(&req->count)) { 124 if (atomic_dec_and_test(&req->count)) {
118 atomic_dec(&fc->num_waiting); 125 if (req->waiting)
126 atomic_dec(&fc->num_waiting);
119 fuse_request_free(req); 127 fuse_request_free(req);
120 } 128 }
121} 129}
122 130
131/*
132 * Called with sbput_sem held for read (request_end) or write
133 * (fuse_put_super). By the time fuse_put_super() is finished, all
134 * inodes belonging to background requests must be released, so the
135 * iputs have to be done within the locked region.
136 */
123void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req) 137void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req)
124{ 138{
125 iput(req->inode); 139 iput(req->inode);
126 iput(req->inode2); 140 iput(req->inode2);
127 if (req->file)
128 fput(req->file);
129 spin_lock(&fc->lock); 141 spin_lock(&fc->lock);
130 list_del(&req->bg_entry); 142 list_del(&req->bg_entry);
131 if (fc->num_background == FUSE_MAX_BACKGROUND) { 143 if (fc->num_background == FUSE_MAX_BACKGROUND) {
@@ -170,6 +182,11 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
170 if (fc->mounted) 182 if (fc->mounted)
171 fuse_release_background(fc, req); 183 fuse_release_background(fc, req);
172 up_read(&fc->sbput_sem); 184 up_read(&fc->sbput_sem);
185
186 /* fput must go outside sbput_sem, otherwise it can deadlock */
187 if (req->file)
188 fput(req->file);
189
173 if (end) 190 if (end)
174 end(fc, req); 191 end(fc, req);
175 else 192 else
@@ -277,6 +294,10 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
277 len_args(req->in.numargs, (struct fuse_arg *) req->in.args); 294 len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
278 list_add_tail(&req->list, &fc->pending); 295 list_add_tail(&req->list, &fc->pending);
279 req->state = FUSE_REQ_PENDING; 296 req->state = FUSE_REQ_PENDING;
297 if (!req->waiting) {
298 req->waiting = 1;
299 atomic_inc(&fc->num_waiting);
300 }
280 wake_up(&fc->waitq); 301 wake_up(&fc->waitq);
281 kill_fasync(&fc->fasync, SIGIO, POLL_IN); 302 kill_fasync(&fc->fasync, SIGIO, POLL_IN);
282} 303}