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