Skip to content

Commit

Permalink
Revert "[fuse] fix deadlock between fuse_put_super() and request_end()"
Browse files Browse the repository at this point in the history
This reverts 73ce835 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>
  • Loading branch information
Miklos Szeredi committed Apr 26, 2006
1 parent 4d5c34e commit 5a5fb1e
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 36 deletions.
28 changes: 12 additions & 16 deletions fs/fuse/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,20 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
}
}

void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req)
void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req)
{
list_del_init(&req->bg_entry);
iput(req->inode);
iput(req->inode2);
if (req->file)
fput(req->file);
spin_lock(&fc->lock);
list_del(&req->bg_entry);
if (fc->num_background == FUSE_MAX_BACKGROUND) {
fc->blocked = 0;
wake_up_all(&fc->blocked_waitq);
}
fc->num_background--;
spin_unlock(&fc->lock);
}

/*
Expand Down Expand Up @@ -165,27 +171,17 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
wake_up(&req->waitq);
fuse_put_request(fc, req);
} else {
struct inode *inode = req->inode;
struct inode *inode2 = req->inode2;
struct file *file = req->file;
void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
req->end = NULL;
req->inode = NULL;
req->inode2 = NULL;
req->file = NULL;
if (!list_empty(&req->bg_entry))
fuse_remove_background(fc, req);
spin_unlock(&fc->lock);

down_read(&fc->sbput_sem);
if (fc->mounted)
fuse_release_background(fc, req);
up_read(&fc->sbput_sem);
if (end)
end(fc, req);
else
fuse_put_request(fc, req);

if (file)
fput(file);
iput(inode);
iput(inode2);
}
}

Expand Down
12 changes: 9 additions & 3 deletions fs/fuse/fuse_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,15 @@ struct fuse_conn {
/** waitq for blocked connection */
wait_queue_head_t blocked_waitq;

/** RW semaphore for exclusion with fuse_put_super() */
struct rw_semaphore sbput_sem;

/** The next unique request id */
u64 reqctr;

/** Mount is active */
unsigned mounted;

/** Connection established, cleared on umount, connection
abort and device release */
unsigned connected;
Expand Down Expand Up @@ -471,11 +477,11 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req);
void request_send_background(struct fuse_conn *fc, struct fuse_req *req);

/**
* Remove request from the the background list
* Release inodes and file associated with background request
*/
void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req);
void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req);

/** Abort all requests */
/* Abort all requests */
void fuse_abort_conn(struct fuse_conn *fc);

/**
Expand Down
27 changes: 10 additions & 17 deletions fs/fuse/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,26 +204,17 @@ static void fuse_put_super(struct super_block *sb)
{
struct fuse_conn *fc = get_fuse_conn_super(sb);

down_write(&fc->sbput_sem);
while (!list_empty(&fc->background))
fuse_release_background(fc,
list_entry(fc->background.next,
struct fuse_req, bg_entry));

spin_lock(&fc->lock);
fc->mounted = 0;
fc->connected = 0;
while (!list_empty(&fc->background)) {
struct fuse_req *req = list_entry(fc->background.next,
struct fuse_req, bg_entry);
struct inode *inode = req->inode;
struct inode *inode2 = req->inode2;

/* File would hold a reference to vfsmount */
BUG_ON(req->file);
req->inode = NULL;
req->inode2 = NULL;
fuse_remove_background(fc, req);

spin_unlock(&fc->lock);
iput(inode);
iput(inode2);
spin_lock(&fc->lock);
}
spin_unlock(&fc->lock);
up_write(&fc->sbput_sem);
/* Flush all readers on this fs */
kill_fasync(&fc->fasync, SIGIO, POLL_IN);
wake_up_all(&fc->waitq);
Expand Down Expand Up @@ -395,6 +386,7 @@ static struct fuse_conn *new_conn(void)
INIT_LIST_HEAD(&fc->processing);
INIT_LIST_HEAD(&fc->io);
INIT_LIST_HEAD(&fc->background);
init_rwsem(&fc->sbput_sem);
kobj_set_kset_s(fc, connections_subsys);
kobject_init(&fc->kobj);
atomic_set(&fc->num_waiting, 0);
Expand Down Expand Up @@ -549,6 +541,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
goto err_free_req;

sb->s_root = root_dentry;
fc->mounted = 1;
fc->connected = 1;
kobject_get(&fc->kobj);
file->private_data = fc;
Expand Down

0 comments on commit 5a5fb1e

Please sign in to comment.