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>

+31 -36
+12 -16
fs/fuse/dev.c
··· 128 128 } 129 129 } 130 130 131 - void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req) 131 + void 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 139 if (fc->num_background == FUSE_MAX_BACKGROUND) { 135 140 fc->blocked = 0; 136 141 wake_up_all(&fc->blocked_waitq); 137 142 } 138 143 fc->num_background--; 144 + spin_unlock(&fc->lock); 139 145 } 140 146 141 147 /* ··· 171 165 wake_up(&req->waitq); 172 166 fuse_put_request(fc, req); 173 167 } else { 174 - struct inode *inode = req->inode; 175 - struct inode *inode2 = req->inode2; 176 - struct file *file = req->file; 177 168 void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; 178 169 req->end = NULL; 179 - req->inode = NULL; 180 - req->inode2 = NULL; 181 - req->file = NULL; 182 - if (!list_empty(&req->bg_entry)) 183 - fuse_remove_background(fc, req); 184 170 spin_unlock(&fc->lock); 185 - 171 + down_read(&fc->sbput_sem); 172 + if (fc->mounted) 173 + fuse_release_background(fc, req); 174 + up_read(&fc->sbput_sem); 186 175 if (end) 187 176 end(fc, req); 188 177 else 189 178 fuse_put_request(fc, req); 190 - 191 - if (file) 192 - fput(file); 193 - iput(inode); 194 - iput(inode2); 195 179 } 196 180 } 197 181
+9 -3
fs/fuse/fuse_i.h
··· 258 258 /** waitq for blocked connection */ 259 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 264 /** The next unique request id */ 262 265 u64 reqctr; 266 + 267 + /** Mount is active */ 268 + unsigned mounted; 263 269 264 270 /** Connection established, cleared on umount, connection 265 271 abort and device release */ ··· 477 471 void request_send_background(struct fuse_conn *fc, struct fuse_req *req); 478 472 479 473 /** 480 - * Remove request from the the background list 474 + * Release inodes and file associated with background request 481 475 */ 482 - void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req); 476 + void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req); 483 477 484 - /** Abort all requests */ 478 + /* Abort all requests */ 485 479 void fuse_abort_conn(struct fuse_conn *fc); 486 480 487 481 /**
+10 -17
fs/fuse/inode.c
··· 204 204 { 205 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 213 spin_lock(&fc->lock); 214 + fc->mounted = 0; 208 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 216 spin_unlock(&fc->lock); 217 + up_write(&fc->sbput_sem); 227 218 /* Flush all readers on this fs */ 228 219 kill_fasync(&fc->fasync, SIGIO, POLL_IN); 229 220 wake_up_all(&fc->waitq); ··· 386 395 INIT_LIST_HEAD(&fc->processing); 387 396 INIT_LIST_HEAD(&fc->io); 388 397 INIT_LIST_HEAD(&fc->background); 398 + init_rwsem(&fc->sbput_sem); 389 399 kobj_set_kset_s(fc, connections_subsys); 390 400 kobject_init(&fc->kobj); 391 401 atomic_set(&fc->num_waiting, 0); ··· 541 549 goto err_free_req; 542 550 543 551 sb->s_root = root_dentry; 552 + fc->mounted = 1; 544 553 fc->connected = 1; 545 554 kobject_get(&fc->kobj); 546 555 file->private_data = fc;