<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
From: Miklos Szeredi &lt;miklos@szeredi.hu&gt;

This patch fixes an Oops which was caused by premature release of the
fuse_conn object.  It does this by introducing reference counting for this
object, instead of using the -&gt;file and -&gt;sb members.  Since -&gt;file and -&gt;sb
are never actually dereferenced, these are replaced by -&gt;connected and
-&gt;mounted bool members.

Signed-off-by: Miklos Szeredi &lt;miklos@szeredi.hu&gt;
Signed-off-by: Andrew Morton &lt;akpm@osdl.org&gt;
---

 fs/fuse/dev.c    |   14 +++++++-------
 fs/fuse/fuse_i.h |   13 ++++++++-----
 fs/fuse/inode.c  |   24 +++++++++---------------
 3 files changed, 24 insertions(+), 27 deletions(-)

diff -puN fs/fuse/dev.c~fuse-mount-options-reference-counting-fix fs/fuse/dev.c
--- 25/fs/fuse/dev.c~fuse-mount-options-reference-counting-fix	2005-04-26 04:05:04.037031328 -0700
+++ 25-akpm/fs/fuse/dev.c	2005-04-26 04:06:10.263963304 -0700
@@ -24,7 +24,7 @@ static inline struct fuse_conn *fuse_get
 	struct fuse_conn *fc;
 	spin_lock(&amp;fuse_lock);
 	fc = file-&gt;private_data;
-	if (fc &amp;&amp; !fc-&gt;sb)
+	if (fc &amp;&amp; !fc-&gt;mounted)
 		fc = NULL;
 	spin_unlock(&amp;fuse_lock);
 	return fc;
@@ -176,7 +176,7 @@ static void request_end(struct fuse_conn
 	spin_unlock(&amp;fuse_lock);
 	if (req-&gt;background) {
 		down_read(&amp;fc-&gt;sbput_sem);
-		if (fc-&gt;sb)
+		if (fc-&gt;mounted)
 			fuse_release_background(req);
 		up_read(&amp;fc-&gt;sbput_sem);
 	}
@@ -306,7 +306,7 @@ static void request_send_wait(struct fus
 {
 	req-&gt;isreply = 1;
 	spin_lock(&amp;fuse_lock);
-	if (!fc-&gt;file)
+	if (!fc-&gt;connected)
 		req-&gt;out.h.error = -ENOTCONN;
 	else if (fc-&gt;conn_error)
 		req-&gt;out.h.error = -ECONNREFUSED;
@@ -339,7 +339,7 @@ void request_send_nonint(struct fuse_con
 static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
 {
 	spin_lock(&amp;fuse_lock);
-	if (fc-&gt;file) {
+	if (fc-&gt;connected) {
 		queue_request(fc, req);
 		spin_unlock(&amp;fuse_lock);
 	} else {
@@ -592,7 +592,7 @@ static void request_wait(struct fuse_con
 	DECLARE_WAITQUEUE(wait, current);
 
 	add_wait_queue_exclusive(&amp;fc-&gt;waitq, &amp;wait);
-	while (fc-&gt;sb &amp;&amp; list_empty(&amp;fc-&gt;pending)) {
+	while (fc-&gt;mounted &amp;&amp; list_empty(&amp;fc-&gt;pending)) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (signal_pending(current))
 			break;
@@ -631,7 +631,7 @@ static ssize_t fuse_dev_readv(struct fil
 		goto err_unlock;
 	request_wait(fc);
 	err = -ENODEV;
-	if (!fc-&gt;sb)
+	if (!fc-&gt;mounted)
 		goto err_unlock;
 	err = -ERESTARTSYS;
 	if (list_empty(&amp;fc-&gt;pending))
@@ -848,7 +848,7 @@ static int fuse_dev_release(struct inode
 	spin_lock(&amp;fuse_lock);
 	fc = file-&gt;private_data;
 	if (fc) {
-		fc-&gt;file = NULL;
+		fc-&gt;connected = 0;
 		end_requests(fc, &amp;fc-&gt;pending);
 		end_requests(fc, &amp;fc-&gt;processing);
 		fuse_release_conn(fc);
diff -puN fs/fuse/fuse_i.h~fuse-mount-options-reference-counting-fix fs/fuse/fuse_i.h
--- 25/fs/fuse/fuse_i.h~fuse-mount-options-reference-counting-fix	2005-04-26 04:05:04.038031176 -0700
+++ 25-akpm/fs/fuse/fuse_i.h	2005-04-26 04:06:09.725045232 -0700
@@ -193,11 +193,8 @@ struct fuse_req {
  * unmounted.
  */
 struct fuse_conn {
-	/** The superblock of the mounted filesystem */
-	struct super_block *sb;
-
-	/** The opened client device */
-	struct file *file;
+	/** Reference count */
+	int count;
 
 	/** The user id for this mount */
 	uid_t user_id;
@@ -234,6 +231,12 @@ struct fuse_conn {
 	/** The next unique request id */
 	int reqctr;
 
+	/** Mount is active */
+	unsigned mounted : 1;
+
+	/** Connection established */
+	unsigned connected : 1;
+
 	/** Connection failed (version mismatch) */
 	unsigned conn_error : 1;
 
diff -puN fs/fuse/inode.c~fuse-mount-options-reference-counting-fix fs/fuse/inode.c
--- 25/fs/fuse/inode.c~fuse-mount-options-reference-counting-fix	2005-04-26 04:05:04.040030872 -0700
+++ 25-akpm/fs/fuse/inode.c	2005-04-26 04:06:09.431089920 -0700
@@ -83,8 +83,8 @@ void fuse_send_forget(struct fuse_conn *
 
 static void fuse_clear_inode(struct inode *inode)
 {
-	struct fuse_conn *fc = get_fuse_conn(inode);
-	if (fc &amp;&amp; (inode-&gt;i_sb-&gt;s_flags &amp; MS_ACTIVE)) {
+	if (inode-&gt;i_sb-&gt;s_flags &amp; MS_ACTIVE) {
+		struct fuse_conn *fc = get_fuse_conn(inode);
 		struct fuse_inode *fi = get_fuse_inode(inode);
 		fuse_send_forget(fc, fi-&gt;forget_req, fi-&gt;nodeid, inode-&gt;i_version);
 		fi-&gt;forget_req = NULL;
@@ -193,14 +193,13 @@ static void fuse_put_super(struct super_
 						   struct fuse_req, bg_entry));
 
 	spin_lock(&amp;fuse_lock);
-	fc-&gt;sb = NULL;
+	fc-&gt;mounted = 0;
 	fc-&gt;user_id = 0;
 	fc-&gt;flags = 0;
 	/* Flush all readers on this fs */
 	wake_up_all(&amp;fc-&gt;waitq);
 	up_write(&amp;fc-&gt;sbput_sem);
 	fuse_release_conn(fc);
-	*get_fuse_conn_super_p(sb) = NULL;
 	spin_unlock(&amp;fuse_lock);
 }
 
@@ -352,7 +351,8 @@ static void free_conn(struct fuse_conn *
 /* Must be called with the fuse lock held */
 void fuse_release_conn(struct fuse_conn *fc)
 {
-	if (!fc-&gt;sb &amp;&amp; !fc-&gt;file)
+	fc-&gt;count--;
+	if (!fc-&gt;count)
 		free_conn(fc);
 }
 
@@ -364,10 +364,6 @@ static struct fuse_conn *new_conn(void)
 	if (fc != NULL) {
 		int i;
 		memset(fc, 0, sizeof(*fc));
-		fc-&gt;sb = NULL;
-		fc-&gt;file = NULL;
-		fc-&gt;flags = 0;
-		fc-&gt;user_id = 0;
 		init_waitqueue_head(&amp;fc-&gt;waitq);
 		INIT_LIST_HEAD(&amp;fc-&gt;pending);
 		INIT_LIST_HEAD(&amp;fc-&gt;processing);
@@ -405,8 +401,10 @@ static struct fuse_conn *get_conn(struct
 		fc = ERR_PTR(-EINVAL);
 	} else {
 		file-&gt;private_data = fc;
-		fc-&gt;sb = sb;
-		fc-&gt;file = file;
+		*get_fuse_conn_super_p(sb) = fc;
+		fc-&gt;mounted = 1;
+		fc-&gt;connected = 1;
+		fc-&gt;count = 2;
 	}
 	spin_unlock(&amp;fuse_lock);
 	return fc;
@@ -461,8 +459,6 @@ static int fuse_fill_super(struct super_
 	fc-&gt;flags = d.flags;
 	fc-&gt;user_id = d.user_id;
 
-	*get_fuse_conn_super_p(sb) = fc;
-
 	err = -ENOMEM;
 	root = get_root_inode(sb, d.rootmode);
 	if (root == NULL)
@@ -478,10 +474,8 @@ static int fuse_fill_super(struct super_
 
  err:
 	spin_lock(&amp;fuse_lock);
-	fc-&gt;sb = NULL;
 	fuse_release_conn(fc);
 	spin_unlock(&amp;fuse_lock);
-	*get_fuse_conn_super_p(sb) = NULL;
 	return err;
 }
 
_
</pre></body></html>