aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-04-14 12:11:34 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-04-14 12:11:34 -0400
commit9a7e9f1c60bada782014b2f422f6c68c4d5388f3 (patch)
tree7e874364f448e050edd6058c50e1e70346b99696
parent9ca686626c012935b3b8219815e9027facc6fe6e (diff)
parent56cf34ff0795692327234963dcdcc2cdeec2bb3d (diff)
Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/mszeredi/fuse
* 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/mszeredi/fuse: [fuse] Direct I/O should not use fuse_reset_request [fuse] Don't init request twice [fuse] Fix accounting the number of waiting requests [fuse] fix deadlock between fuse_put_super() and request_end()
-rw-r--r--fs/fuse/dev.c54
-rw-r--r--fs/fuse/file.c10
-rw-r--r--fs/fuse/fuse_i.h15
-rw-r--r--fs/fuse/inode.c27
4 files changed, 65 insertions, 41 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 6c740f860665..cc750c68fe70 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -92,48 +92,50 @@ 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
123void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req) 131void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req)
124{ 132{
125 iput(req->inode); 133 list_del_init(&req->bg_entry);
126 iput(req->inode2);
127 if (req->file)
128 fput(req->file);
129 spin_lock(&fc->lock);
130 list_del(&req->bg_entry);
131 if (fc->num_background == FUSE_MAX_BACKGROUND) { 134 if (fc->num_background == FUSE_MAX_BACKGROUND) {
132 fc->blocked = 0; 135 fc->blocked = 0;
133 wake_up_all(&fc->blocked_waitq); 136 wake_up_all(&fc->blocked_waitq);
134 } 137 }
135 fc->num_background--; 138 fc->num_background--;
136 spin_unlock(&fc->lock);
137} 139}
138 140
139/* 141/*
@@ -163,17 +165,27 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
163 wake_up(&req->waitq); 165 wake_up(&req->waitq);
164 fuse_put_request(fc, req); 166 fuse_put_request(fc, req);
165 } else { 167 } else {
168 struct inode *inode = req->inode;
169 struct inode *inode2 = req->inode2;
170 struct file *file = req->file;
166 void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; 171 void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
167 req->end = NULL; 172 req->end = NULL;
173 req->inode = NULL;
174 req->inode2 = NULL;
175 req->file = NULL;
176 if (!list_empty(&req->bg_entry))
177 fuse_remove_background(fc, req);
168 spin_unlock(&fc->lock); 178 spin_unlock(&fc->lock);
169 down_read(&fc->sbput_sem); 179
170 if (fc->mounted)
171 fuse_release_background(fc, req);
172 up_read(&fc->sbput_sem);
173 if (end) 180 if (end)
174 end(fc, req); 181 end(fc, req);
175 else 182 else
176 fuse_put_request(fc, req); 183 fuse_put_request(fc, req);
184
185 if (file)
186 fput(file);
187 iput(inode);
188 iput(inode2);
177 } 189 }
178} 190}
179 191
@@ -277,6 +289,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); 289 len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
278 list_add_tail(&req->list, &fc->pending); 290 list_add_tail(&req->list, &fc->pending);
279 req->state = FUSE_REQ_PENDING; 291 req->state = FUSE_REQ_PENDING;
292 if (!req->waiting) {
293 req->waiting = 1;
294 atomic_inc(&fc->num_waiting);
295 }
280 wake_up(&fc->waitq); 296 wake_up(&fc->waitq);
281 kill_fasync(&fc->fasync, SIGIO, POLL_IN); 297 kill_fasync(&fc->fasync, SIGIO, POLL_IN);
282} 298}
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index e4f041a11bb5..fc342cf7c2cc 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1,6 +1,6 @@
1/* 1/*
2 FUSE: Filesystem in Userspace 2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> 3 Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
4 4
5 This program can be distributed under the terms of the GNU GPL. 5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING. 6 See the file COPYING.
@@ -565,8 +565,12 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
565 buf += nres; 565 buf += nres;
566 if (nres != nbytes) 566 if (nres != nbytes)
567 break; 567 break;
568 if (count) 568 if (count) {
569 fuse_reset_request(req); 569 fuse_put_request(fc, req);
570 req = fuse_get_req(fc);
571 if (IS_ERR(req))
572 break;
573 }
570 } 574 }
571 fuse_put_request(fc, req); 575 fuse_put_request(fc, req);
572 if (res > 0) { 576 if (res > 0) {
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 19c7185a7546..59661c481d9d 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -159,6 +159,9 @@ struct fuse_req {
159 /** Data is being copied to/from the request */ 159 /** Data is being copied to/from the request */
160 unsigned locked:1; 160 unsigned locked:1;
161 161
162 /** Request is counted as "waiting" */
163 unsigned waiting:1;
164
162 /** State of the request */ 165 /** State of the request */
163 enum fuse_req_state state; 166 enum fuse_req_state state;
164 167
@@ -255,15 +258,9 @@ struct fuse_conn {
255 /** waitq for blocked connection */ 258 /** waitq for blocked connection */
256 wait_queue_head_t blocked_waitq; 259 wait_queue_head_t blocked_waitq;
257 260
258 /** RW semaphore for exclusion with fuse_put_super() */
259 struct rw_semaphore sbput_sem;
260
261 /** The next unique request id */ 261 /** The next unique request id */
262 u64 reqctr; 262 u64 reqctr;
263 263
264 /** Mount is active */
265 unsigned mounted;
266
267 /** Connection established, cleared on umount, connection 264 /** Connection established, cleared on umount, connection
268 abort and device release */ 265 abort and device release */
269 unsigned connected; 266 unsigned connected;
@@ -474,11 +471,11 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req);
474void request_send_background(struct fuse_conn *fc, struct fuse_req *req); 471void request_send_background(struct fuse_conn *fc, struct fuse_req *req);
475 472
476/** 473/**
477 * Release inodes and file associated with background request 474 * Remove request from the the background list
478 */ 475 */
479void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req); 476void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req);
480 477
481/* Abort all requests */ 478/** Abort all requests */
482void fuse_abort_conn(struct fuse_conn *fc); 479void fuse_abort_conn(struct fuse_conn *fc);
483 480
484/** 481/**
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index fd34037b0588..43a6fc0db8a7 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -204,17 +204,26 @@ static void fuse_put_super(struct super_block *sb)
204{ 204{
205 struct fuse_conn *fc = get_fuse_conn_super(sb); 205 struct fuse_conn *fc = get_fuse_conn_super(sb);
206 206
207 down_write(&fc->sbput_sem);
208 while (!list_empty(&fc->background))
209 fuse_release_background(fc,
210 list_entry(fc->background.next,
211 struct fuse_req, bg_entry));
212
213 spin_lock(&fc->lock); 207 spin_lock(&fc->lock);
214 fc->mounted = 0;
215 fc->connected = 0; 208 fc->connected = 0;
209 while (!list_empty(&fc->background)) {
210 struct fuse_req *req = list_entry(fc->background.next,
211 struct fuse_req, bg_entry);
212 struct inode *inode = req->inode;
213 struct inode *inode2 = req->inode2;
214
215 /* File would hold a reference to vfsmount */
216 BUG_ON(req->file);
217 req->inode = NULL;
218 req->inode2 = NULL;
219 fuse_remove_background(fc, req);
220
221 spin_unlock(&fc->lock);
222 iput(inode);
223 iput(inode2);
224 spin_lock(&fc->lock);
225 }
216 spin_unlock(&fc->lock); 226 spin_unlock(&fc->lock);
217 up_write(&fc->sbput_sem);
218 /* Flush all readers on this fs */ 227 /* Flush all readers on this fs */
219 kill_fasync(&fc->fasync, SIGIO, POLL_IN); 228 kill_fasync(&fc->fasync, SIGIO, POLL_IN);
220 wake_up_all(&fc->waitq); 229 wake_up_all(&fc->waitq);
@@ -386,7 +395,6 @@ static struct fuse_conn *new_conn(void)
386 INIT_LIST_HEAD(&fc->processing); 395 INIT_LIST_HEAD(&fc->processing);
387 INIT_LIST_HEAD(&fc->io); 396 INIT_LIST_HEAD(&fc->io);
388 INIT_LIST_HEAD(&fc->background); 397 INIT_LIST_HEAD(&fc->background);
389 init_rwsem(&fc->sbput_sem);
390 kobj_set_kset_s(fc, connections_subsys); 398 kobj_set_kset_s(fc, connections_subsys);
391 kobject_init(&fc->kobj); 399 kobject_init(&fc->kobj);
392 atomic_set(&fc->num_waiting, 0); 400 atomic_set(&fc->num_waiting, 0);
@@ -541,7 +549,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
541 goto err_free_req; 549 goto err_free_req;
542 550
543 sb->s_root = root_dentry; 551 sb->s_root = root_dentry;
544 fc->mounted = 1;
545 fc->connected = 1; 552 fc->connected = 1;
546 kobject_get(&fc->kobj); 553 kobject_get(&fc->kobj);
547 file->private_data = fc; 554 file->private_data = fc;