aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2006-04-26 04:48:55 -0400
committerMiklos Szeredi <miklos@szeredi.hu>2006-04-26 04:48:55 -0400
commit5a5fb1ea74d8b82ca1461b885a1334fb21e037be (patch)
treef6e823d4a8e09ce0780d891f8f38f033ccbd7da2
parent4d5c34ec7b007cfb0771a36996b009f194acbb2f (diff)
Revert "[fuse] fix deadlock between fuse_put_super() and request_end()"
This reverts 73ce8355c243a434524a34c05cc417dd0467996e commit. It was wrong, because it didn't take into account the requirement, that iput() for background requests must be performed synchronously with ->put_super(), otherwise active inodes may remain after unmount. The right solution is to keep the sbput_sem and perform iput() within the locked region, but move fput() outside sbput_sem. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
-rw-r--r--fs/fuse/dev.c28
-rw-r--r--fs/fuse/fuse_i.h12
-rw-r--r--fs/fuse/inode.c27
3 files changed, 31 insertions, 36 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index cc750c68fe70..4967bd40b953 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -128,14 +128,20 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
128 } 128 }
129} 129}
130 130
131void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req) 131void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req)
132{ 132{
133 list_del_init(&req->bg_entry); 133 iput(req->inode);
134 iput(req->inode2);
135 if (req->file)
136 fput(req->file);
137 spin_lock(&fc->lock);
138 list_del(&req->bg_entry);
134 if (fc->num_background == FUSE_MAX_BACKGROUND) { 139 if (fc->num_background == FUSE_MAX_BACKGROUND) {
135 fc->blocked = 0; 140 fc->blocked = 0;
136 wake_up_all(&fc->blocked_waitq); 141 wake_up_all(&fc->blocked_waitq);
137 } 142 }
138 fc->num_background--; 143 fc->num_background--;
144 spin_unlock(&fc->lock);
139} 145}
140 146
141/* 147/*
@@ -165,27 +171,17 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
165 wake_up(&req->waitq); 171 wake_up(&req->waitq);
166 fuse_put_request(fc, req); 172 fuse_put_request(fc, req);
167 } else { 173 } else {
168 struct inode *inode = req->inode;
169 struct inode *inode2 = req->inode2;
170 struct file *file = req->file;
171 void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; 174 void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
172 req->end = NULL; 175 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);
178 spin_unlock(&fc->lock); 176 spin_unlock(&fc->lock);
179 177 down_read(&fc->sbput_sem);
178 if (fc->mounted)
179 fuse_release_background(fc, req);
180 up_read(&fc->sbput_sem);
180 if (end) 181 if (end)
181 end(fc, req); 182 end(fc, req);
182 else 183 else
183 fuse_put_request(fc, req); 184 fuse_put_request(fc, req);
184
185 if (file)
186 fput(file);
187 iput(inode);
188 iput(inode2);
189 } 185 }
190} 186}
191 187
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 59661c481d9d..0474202cb5dc 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -258,9 +258,15 @@ struct fuse_conn {
258 /** waitq for blocked connection */ 258 /** waitq for blocked connection */
259 wait_queue_head_t blocked_waitq; 259 wait_queue_head_t blocked_waitq;
260 260
261 /** RW semaphore for exclusion with fuse_put_super() */
262 struct rw_semaphore sbput_sem;
263
261 /** The next unique request id */ 264 /** The next unique request id */
262 u64 reqctr; 265 u64 reqctr;
263 266
267 /** Mount is active */
268 unsigned mounted;
269
264 /** Connection established, cleared on umount, connection 270 /** Connection established, cleared on umount, connection
265 abort and device release */ 271 abort and device release */
266 unsigned connected; 272 unsigned connected;
@@ -471,11 +477,11 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req);
471void request_send_background(struct fuse_conn *fc, struct fuse_req *req); 477void request_send_background(struct fuse_conn *fc, struct fuse_req *req);
472 478
473/** 479/**
474 * Remove request from the the background list 480 * Release inodes and file associated with background request
475 */ 481 */
476void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req); 482void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req);
477 483
478/** Abort all requests */ 484/* Abort all requests */
479void fuse_abort_conn(struct fuse_conn *fc); 485void fuse_abort_conn(struct fuse_conn *fc);
480 486
481/** 487/**
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 43a6fc0db8a7..fd34037b0588 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -204,26 +204,17 @@ 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
207 spin_lock(&fc->lock); 213 spin_lock(&fc->lock);
214 fc->mounted = 0;
208 fc->connected = 0; 215 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 }
226 spin_unlock(&fc->lock); 216 spin_unlock(&fc->lock);
217 up_write(&fc->sbput_sem);
227 /* Flush all readers on this fs */ 218 /* Flush all readers on this fs */
228 kill_fasync(&fc->fasync, SIGIO, POLL_IN); 219 kill_fasync(&fc->fasync, SIGIO, POLL_IN);
229 wake_up_all(&fc->waitq); 220 wake_up_all(&fc->waitq);
@@ -395,6 +386,7 @@ static struct fuse_conn *new_conn(void)
395 INIT_LIST_HEAD(&fc->processing); 386 INIT_LIST_HEAD(&fc->processing);
396 INIT_LIST_HEAD(&fc->io); 387 INIT_LIST_HEAD(&fc->io);
397 INIT_LIST_HEAD(&fc->background); 388 INIT_LIST_HEAD(&fc->background);
389 init_rwsem(&fc->sbput_sem);
398 kobj_set_kset_s(fc, connections_subsys); 390 kobj_set_kset_s(fc, connections_subsys);
399 kobject_init(&fc->kobj); 391 kobject_init(&fc->kobj);
400 atomic_set(&fc->num_waiting, 0); 392 atomic_set(&fc->num_waiting, 0);
@@ -549,6 +541,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
549 goto err_free_req; 541 goto err_free_req;
550 542
551 sb->s_root = root_dentry; 543 sb->s_root = root_dentry;
544 fc->mounted = 1;
552 fc->connected = 1; 545 fc->connected = 1;
553 kobject_get(&fc->kobj); 546 kobject_get(&fc->kobj);
554 file->private_data = fc; 547 file->private_data = fc;