All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] fuse: return -ECONNABORTED on /dev/fuse read after abort
@ 2017-10-31 18:55 Szymon Lukasz
  2017-11-03 15:04 ` [PATCH v2] " Szymon Lukasz
  0 siblings, 1 reply; 10+ messages in thread
From: Szymon Lukasz @ 2017-10-31 18:55 UTC (permalink / raw)
  To: miklos; +Cc: linux-fsdevel, Szymon Lukasz

Currently the userspace has no way of knowing whether the fuse
connection ended because of umount or abort via sysfs. It makes it hard
for filesystems to free the mountpoint after abort without worrying
about removing some new mount.
The patch fixes it by returning different errors when userspace reads
from /dev/fuse (-ENODEV for umount and -ECONNABORTED for abort).

Signed-off-by: Szymon Lukasz <noh4hss@gmail.com>
---
 fs/fuse/control.c |  2 +-
 fs/fuse/dev.c     | 13 ++++++++-----
 fs/fuse/fuse_i.h  |  8 +++++++-
 fs/fuse/inode.c   |  4 ++--
 4 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/fs/fuse/control.c b/fs/fuse/control.c
index b9ea99c5b5b3..eeda05a7c882 100644
--- a/fs/fuse/control.c
+++ b/fs/fuse/control.c
@@ -35,7 +35,7 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf,
 {
 	struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
 	if (fc) {
-		fuse_abort_conn(fc);
+		fuse_abort_conn(fc, 1);
 		fuse_conn_put(fc);
 	}
 	return count;
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 13c65dd2d37d..b51da52b92b9 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1234,9 +1234,10 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
 	if (err)
 		goto err_unlock;
 
-	err = -ENODEV;
-	if (!fiq->connected)
+	if (!fiq->connected) {
+		err = fiq->aborted ? -ECONNABORTED : -ENODEV;
 		goto err_unlock;
+	}
 
 	if (!list_empty(&fiq->interrupts)) {
 		req = list_entry(fiq->interrupts.next, struct fuse_req,
@@ -1287,7 +1288,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
 	spin_lock(&fpq->lock);
 	clear_bit(FR_LOCKED, &req->flags);
 	if (!fpq->connected) {
-		err = -ENODEV;
+		err = fpq->aborted ? -ECONNABORTED : -ENODEV;
 		goto out_end;
 	}
 	if (err) {
@@ -2076,7 +2077,7 @@ static void end_polls(struct fuse_conn *fc)
  * is OK, the request will in that case be removed from the list before we touch
  * it.
  */
-void fuse_abort_conn(struct fuse_conn *fc)
+void fuse_abort_conn(struct fuse_conn *fc, int is_abort)
 {
 	struct fuse_iqueue *fiq = &fc->iq;
 
@@ -2095,6 +2096,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
 
 			spin_lock(&fpq->lock);
 			fpq->connected = 0;
+			fpq->aborted = is_abort;
 			list_for_each_entry_safe(req, next, &fpq->io, list) {
 				req->out.h.error = -ECONNABORTED;
 				spin_lock(&req->waitq.lock);
@@ -2113,6 +2115,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
 
 		spin_lock(&fiq->waitq.lock);
 		fiq->connected = 0;
+		fiq->aborted = is_abort;
 		list_splice_init(&fiq->pending, &to_end2);
 		list_for_each_entry(req, &to_end2, list)
 			clear_bit(FR_PENDING, &req->flags);
@@ -2151,7 +2154,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)
 		/* Are we the last open device? */
 		if (atomic_dec_and_test(&fc->dev_count)) {
 			WARN_ON(fc->iq.fasync != NULL);
-			fuse_abort_conn(fc);
+			fuse_abort_conn(fc, 0);
 		}
 		fuse_dev_free(fud);
 	}
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index d5773ca67ad2..650e72be4174 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -387,6 +387,9 @@ struct fuse_iqueue {
 	/** Connection established */
 	unsigned connected;
 
+	/** Connection aborted via sysfs */
+	int aborted;
+
 	/** Readers of the connection are waiting on this */
 	wait_queue_head_t waitq;
 
@@ -414,6 +417,9 @@ struct fuse_pqueue {
 	/** Connection established */
 	unsigned connected;
 
+	/** Connection aborted via sysfs */
+	int aborted;
+
 	/** Lock protecting accessess to  members of this structure */
 	spinlock_t lock;
 
@@ -851,7 +857,7 @@ void fuse_request_send_background_locked(struct fuse_conn *fc,
 					 struct fuse_req *req);
 
 /* Abort all requests */
-void fuse_abort_conn(struct fuse_conn *fc);
+void fuse_abort_conn(struct fuse_conn *fc, int is_abort);
 
 /**
  * Invalidate inode attributes
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 94a745acaef8..8cc9de4ec16d 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -371,7 +371,7 @@ void fuse_unlock_inode(struct inode *inode)
 
 static void fuse_umount_begin(struct super_block *sb)
 {
-	fuse_abort_conn(get_fuse_conn_super(sb));
+	fuse_abort_conn(get_fuse_conn_super(sb), 0);
 }
 
 static void fuse_send_destroy(struct fuse_conn *fc)
@@ -393,7 +393,7 @@ static void fuse_put_super(struct super_block *sb)
 
 	fuse_send_destroy(fc);
 
-	fuse_abort_conn(fc);
+	fuse_abort_conn(fc, 0);
 	mutex_lock(&fuse_mutex);
 	list_del(&fc->entry);
 	fuse_ctl_remove_conn(fc);
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2] fuse: return -ECONNABORTED on /dev/fuse read after abort
  2017-10-31 18:55 [PATCH] fuse: return -ECONNABORTED on /dev/fuse read after abort Szymon Lukasz
@ 2017-11-03 15:04 ` Szymon Lukasz
  2017-11-06  9:51   ` Miklos Szeredi
  0 siblings, 1 reply; 10+ messages in thread
From: Szymon Lukasz @ 2017-11-03 15:04 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: linux-fsdevel, fuse-devel, Szymon Lukasz

Return -ECONNABORTED when userspace tries to read from /dev/fuse after
the fuse connection was aborted via sysfs.
The patch increases FUSE_KERNEL_MINOR_VERSION. However -ECONNABORTED is
always returned, regardless of the minor version sent by userspace in
FUSE_INIT.

Info why this patch might be useful:
https://github.com/libfuse/libfuse/issues/122

Signed-off-by: Szymon Lukasz <noh4hss@gmail.com>
---
 fs/fuse/control.c         |  2 +-
 fs/fuse/dev.c             | 13 ++++++++-----
 fs/fuse/fuse_i.h          |  8 +++++++-
 fs/fuse/inode.c           |  4 ++--
 include/uapi/linux/fuse.h |  5 ++++-
 5 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/fs/fuse/control.c b/fs/fuse/control.c
index b9ea99c5b5b3..eeda05a7c882 100644
--- a/fs/fuse/control.c
+++ b/fs/fuse/control.c
@@ -35,7 +35,7 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf,
 {
 	struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
 	if (fc) {
-		fuse_abort_conn(fc);
+		fuse_abort_conn(fc, 1);
 		fuse_conn_put(fc);
 	}
 	return count;
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 13c65dd2d37d..b51da52b92b9 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1234,9 +1234,10 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
 	if (err)
 		goto err_unlock;
 
-	err = -ENODEV;
-	if (!fiq->connected)
+	if (!fiq->connected) {
+		err = fiq->aborted ? -ECONNABORTED : -ENODEV;
 		goto err_unlock;
+	}
 
 	if (!list_empty(&fiq->interrupts)) {
 		req = list_entry(fiq->interrupts.next, struct fuse_req,
@@ -1287,7 +1288,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
 	spin_lock(&fpq->lock);
 	clear_bit(FR_LOCKED, &req->flags);
 	if (!fpq->connected) {
-		err = -ENODEV;
+		err = fpq->aborted ? -ECONNABORTED : -ENODEV;
 		goto out_end;
 	}
 	if (err) {
@@ -2076,7 +2077,7 @@ static void end_polls(struct fuse_conn *fc)
  * is OK, the request will in that case be removed from the list before we touch
  * it.
  */
-void fuse_abort_conn(struct fuse_conn *fc)
+void fuse_abort_conn(struct fuse_conn *fc, int is_abort)
 {
 	struct fuse_iqueue *fiq = &fc->iq;
 
@@ -2095,6 +2096,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
 
 			spin_lock(&fpq->lock);
 			fpq->connected = 0;
+			fpq->aborted = is_abort;
 			list_for_each_entry_safe(req, next, &fpq->io, list) {
 				req->out.h.error = -ECONNABORTED;
 				spin_lock(&req->waitq.lock);
@@ -2113,6 +2115,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
 
 		spin_lock(&fiq->waitq.lock);
 		fiq->connected = 0;
+		fiq->aborted = is_abort;
 		list_splice_init(&fiq->pending, &to_end2);
 		list_for_each_entry(req, &to_end2, list)
 			clear_bit(FR_PENDING, &req->flags);
@@ -2151,7 +2154,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)
 		/* Are we the last open device? */
 		if (atomic_dec_and_test(&fc->dev_count)) {
 			WARN_ON(fc->iq.fasync != NULL);
-			fuse_abort_conn(fc);
+			fuse_abort_conn(fc, 0);
 		}
 		fuse_dev_free(fud);
 	}
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index d5773ca67ad2..650e72be4174 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -387,6 +387,9 @@ struct fuse_iqueue {
 	/** Connection established */
 	unsigned connected;
 
+	/** Connection aborted via sysfs */
+	int aborted;
+
 	/** Readers of the connection are waiting on this */
 	wait_queue_head_t waitq;
 
@@ -414,6 +417,9 @@ struct fuse_pqueue {
 	/** Connection established */
 	unsigned connected;
 
+	/** Connection aborted via sysfs */
+	int aborted;
+
 	/** Lock protecting accessess to  members of this structure */
 	spinlock_t lock;
 
@@ -851,7 +857,7 @@ void fuse_request_send_background_locked(struct fuse_conn *fc,
 					 struct fuse_req *req);
 
 /* Abort all requests */
-void fuse_abort_conn(struct fuse_conn *fc);
+void fuse_abort_conn(struct fuse_conn *fc, int is_abort);
 
 /**
  * Invalidate inode attributes
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 94a745acaef8..8cc9de4ec16d 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -371,7 +371,7 @@ void fuse_unlock_inode(struct inode *inode)
 
 static void fuse_umount_begin(struct super_block *sb)
 {
-	fuse_abort_conn(get_fuse_conn_super(sb));
+	fuse_abort_conn(get_fuse_conn_super(sb), 0);
 }
 
 static void fuse_send_destroy(struct fuse_conn *fc)
@@ -393,7 +393,7 @@ static void fuse_put_super(struct super_block *sb)
 
 	fuse_send_destroy(fc);
 
-	fuse_abort_conn(fc);
+	fuse_abort_conn(fc, 0);
 	mutex_lock(&fuse_mutex);
 	list_del(&fc->entry);
 	fuse_ctl_remove_conn(fc);
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index 42fa977e3b14..4025a5599b2b 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -112,6 +112,9 @@
  *  7.26
  *  - add FUSE_HANDLE_KILLPRIV
  *  - add FUSE_POSIX_ACL
+ *
+ *  7.27
+ *  - reading from /dev/fuse after sysfs abort returns -ECONNABORTED
  */
 
 #ifndef _LINUX_FUSE_H
@@ -147,7 +150,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 26
+#define FUSE_KERNEL_MINOR_VERSION 27
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
-- 
2.15.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2] fuse: return -ECONNABORTED on /dev/fuse read after abort
  2017-11-03 15:04 ` [PATCH v2] " Szymon Lukasz
@ 2017-11-06  9:51   ` Miklos Szeredi
  2017-11-07  0:16     ` [PATCH v3] " Szymon Lukasz
  0 siblings, 1 reply; 10+ messages in thread
From: Miklos Szeredi @ 2017-11-06  9:51 UTC (permalink / raw)
  To: Szymon Lukasz; +Cc: linux-fsdevel, fuse-devel

On Fri, Nov 3, 2017 at 4:04 PM, Szymon Lukasz <noh4hss@gmail.com> wrote:
> Return -ECONNABORTED when userspace tries to read from /dev/fuse after
> the fuse connection was aborted via sysfs.
> The patch increases FUSE_KERNEL_MINOR_VERSION. However -ECONNABORTED is
> always returned, regardless of the minor version sent by userspace in
> FUSE_INIT.

I worry about that.

I'd rather have this enabled with a capability flag negotiated in INIT.

>
> Info why this patch might be useful:
> https://github.com/libfuse/libfuse/issues/122
>
> Signed-off-by: Szymon Lukasz <noh4hss@gmail.com>
> ---
>  fs/fuse/control.c         |  2 +-
>  fs/fuse/dev.c             | 13 ++++++++-----
>  fs/fuse/fuse_i.h          |  8 +++++++-
>  fs/fuse/inode.c           |  4 ++--
>  include/uapi/linux/fuse.h |  5 ++++-
>  5 files changed, 22 insertions(+), 10 deletions(-)
>
> diff --git a/fs/fuse/control.c b/fs/fuse/control.c
> index b9ea99c5b5b3..eeda05a7c882 100644
> --- a/fs/fuse/control.c
> +++ b/fs/fuse/control.c
> @@ -35,7 +35,7 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf,
>  {
>         struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
>         if (fc) {
> -               fuse_abort_conn(fc);
> +               fuse_abort_conn(fc, 1);
>                 fuse_conn_put(fc);
>         }
>         return count;
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 13c65dd2d37d..b51da52b92b9 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -1234,9 +1234,10 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
>         if (err)
>                 goto err_unlock;
>
> -       err = -ENODEV;
> -       if (!fiq->connected)
> +       if (!fiq->connected) {
> +               err = fiq->aborted ? -ECONNABORTED : -ENODEV;
>                 goto err_unlock;
> +       }
>
>         if (!list_empty(&fiq->interrupts)) {
>                 req = list_entry(fiq->interrupts.next, struct fuse_req,
> @@ -1287,7 +1288,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
>         spin_lock(&fpq->lock);
>         clear_bit(FR_LOCKED, &req->flags);
>         if (!fpq->connected) {
> -               err = -ENODEV;
> +               err = fpq->aborted ? -ECONNABORTED : -ENODEV;
>                 goto out_end;
>         }
>         if (err) {
> @@ -2076,7 +2077,7 @@ static void end_polls(struct fuse_conn *fc)
>   * is OK, the request will in that case be removed from the list before we touch
>   * it.
>   */
> -void fuse_abort_conn(struct fuse_conn *fc)
> +void fuse_abort_conn(struct fuse_conn *fc, int is_abort)
>  {
>         struct fuse_iqueue *fiq = &fc->iq;
>
> @@ -2095,6 +2096,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
>
>                         spin_lock(&fpq->lock);
>                         fpq->connected = 0;
> +                       fpq->aborted = is_abort;
>                         list_for_each_entry_safe(req, next, &fpq->io, list) {
>                                 req->out.h.error = -ECONNABORTED;
>                                 spin_lock(&req->waitq.lock);
> @@ -2113,6 +2115,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
>
>                 spin_lock(&fiq->waitq.lock);
>                 fiq->connected = 0;
> +               fiq->aborted = is_abort;
>                 list_splice_init(&fiq->pending, &to_end2);
>                 list_for_each_entry(req, &to_end2, list)
>                         clear_bit(FR_PENDING, &req->flags);
> @@ -2151,7 +2154,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)
>                 /* Are we the last open device? */
>                 if (atomic_dec_and_test(&fc->dev_count)) {
>                         WARN_ON(fc->iq.fasync != NULL);
> -                       fuse_abort_conn(fc);
> +                       fuse_abort_conn(fc, 0);
>                 }
>                 fuse_dev_free(fud);
>         }
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index d5773ca67ad2..650e72be4174 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -387,6 +387,9 @@ struct fuse_iqueue {
>         /** Connection established */
>         unsigned connected;
>
> +       /** Connection aborted via sysfs */
> +       int aborted;
> +

Does it need to be a per-queue granularity?   Isn't a single bool in
fuse_conn sufficient?

Thanks,
Miklos


>         /** Readers of the connection are waiting on this */
>         wait_queue_head_t waitq;
>
> @@ -414,6 +417,9 @@ struct fuse_pqueue {
>         /** Connection established */
>         unsigned connected;
>
> +       /** Connection aborted via sysfs */
> +       int aborted;
> +
>         /** Lock protecting accessess to  members of this structure */
>         spinlock_t lock;
>
> @@ -851,7 +857,7 @@ void fuse_request_send_background_locked(struct fuse_conn *fc,
>                                          struct fuse_req *req);
>
>  /* Abort all requests */
> -void fuse_abort_conn(struct fuse_conn *fc);
> +void fuse_abort_conn(struct fuse_conn *fc, int is_abort);
>
>  /**
>   * Invalidate inode attributes
> diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> index 94a745acaef8..8cc9de4ec16d 100644
> --- a/fs/fuse/inode.c
> +++ b/fs/fuse/inode.c
> @@ -371,7 +371,7 @@ void fuse_unlock_inode(struct inode *inode)
>
>  static void fuse_umount_begin(struct super_block *sb)
>  {
> -       fuse_abort_conn(get_fuse_conn_super(sb));
> +       fuse_abort_conn(get_fuse_conn_super(sb), 0);
>  }
>
>  static void fuse_send_destroy(struct fuse_conn *fc)
> @@ -393,7 +393,7 @@ static void fuse_put_super(struct super_block *sb)
>
>         fuse_send_destroy(fc);
>
> -       fuse_abort_conn(fc);
> +       fuse_abort_conn(fc, 0);
>         mutex_lock(&fuse_mutex);
>         list_del(&fc->entry);
>         fuse_ctl_remove_conn(fc);
> diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
> index 42fa977e3b14..4025a5599b2b 100644
> --- a/include/uapi/linux/fuse.h
> +++ b/include/uapi/linux/fuse.h
> @@ -112,6 +112,9 @@
>   *  7.26
>   *  - add FUSE_HANDLE_KILLPRIV
>   *  - add FUSE_POSIX_ACL
> + *
> + *  7.27
> + *  - reading from /dev/fuse after sysfs abort returns -ECONNABORTED
>   */
>
>  #ifndef _LINUX_FUSE_H
> @@ -147,7 +150,7 @@
>  #define FUSE_KERNEL_VERSION 7
>
>  /** Minor version number of this interface */
> -#define FUSE_KERNEL_MINOR_VERSION 26
> +#define FUSE_KERNEL_MINOR_VERSION 27
>
>  /** The node ID of the root inode */
>  #define FUSE_ROOT_ID 1
> --
> 2.15.0
>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3] fuse: return -ECONNABORTED on /dev/fuse read after abort
  2017-11-06  9:51   ` Miklos Szeredi
@ 2017-11-07  0:16     ` Szymon Lukasz
  2017-11-09 18:29       ` kbuild test robot
                         ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Szymon Lukasz @ 2017-11-07  0:16 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: linux-fsdevel, fuse-devel, Szymon Lukasz

Adds a new capability flag FUSE_ABORT_ERROR. If set and the connection
is gone because of sysfs abort, reading from the device will return
-ECONNABORTED.

Signed-off-by: Szymon Lukasz <noh4hss@gmail.com>
---
 fs/fuse/control.c         |  2 +-
 fs/fuse/dev.c             | 12 +++++++-----
 fs/fuse/fuse_i.h          |  8 +++++++-
 fs/fuse/inode.c           |  9 ++++++---
 include/uapi/linux/fuse.h |  7 ++++++-
 5 files changed, 27 insertions(+), 11 deletions(-)

diff --git a/fs/fuse/control.c b/fs/fuse/control.c
index b9ea99c5b5b3..78fb7a07c5ca 100644
--- a/fs/fuse/control.c
+++ b/fs/fuse/control.c
@@ -35,7 +35,7 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf,
 {
 	struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
 	if (fc) {
-		fuse_abort_conn(fc);
+		fuse_abort_conn(fc, true);
 		fuse_conn_put(fc);
 	}
 	return count;
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 13c65dd2d37d..2e1beda0b82b 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1234,9 +1234,10 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
 	if (err)
 		goto err_unlock;
 
-	err = -ENODEV;
-	if (!fiq->connected)
+	if (!fiq->connected) {
+		err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV;
 		goto err_unlock;
+	}
 
 	if (!list_empty(&fiq->interrupts)) {
 		req = list_entry(fiq->interrupts.next, struct fuse_req,
@@ -1287,7 +1288,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
 	spin_lock(&fpq->lock);
 	clear_bit(FR_LOCKED, &req->flags);
 	if (!fpq->connected) {
-		err = -ENODEV;
+		err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV;
 		goto out_end;
 	}
 	if (err) {
@@ -2076,7 +2077,7 @@ static void end_polls(struct fuse_conn *fc)
  * is OK, the request will in that case be removed from the list before we touch
  * it.
  */
-void fuse_abort_conn(struct fuse_conn *fc)
+void fuse_abort_conn(struct fuse_conn *fc, bool is_abort)
 {
 	struct fuse_iqueue *fiq = &fc->iq;
 
@@ -2089,6 +2090,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
 
 		fc->connected = 0;
 		fc->blocked = 0;
+		fc->aborted = is_abort;
 		fuse_set_initialized(fc);
 		list_for_each_entry(fud, &fc->devices, entry) {
 			struct fuse_pqueue *fpq = &fud->pq;
@@ -2151,7 +2153,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)
 		/* Are we the last open device? */
 		if (atomic_dec_and_test(&fc->dev_count)) {
 			WARN_ON(fc->iq.fasync != NULL);
-			fuse_abort_conn(fc);
+			fuse_abort_conn(fc, false);
 		}
 		fuse_dev_free(fud);
 	}
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index d5773ca67ad2..2f8a261d8669 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -515,6 +515,9 @@ struct fuse_conn {
 	    abort and device release */
 	unsigned connected;
 
+	/** Connection aborted via sysfs */
+	bool aborted;
+
 	/** Connection failed (version mismatch).  Cannot race with
 	    setting other bitfields since it is only set once in INIT
 	    reply, before any other request, and never cleared */
@@ -526,6 +529,9 @@ struct fuse_conn {
 	/** Do readpages asynchronously?  Only set in INIT */
 	unsigned async_read:1;
 
+	/** Return an unique read error after abort.  Only set in INIT */
+	unsigned abort_err:1;
+
 	/** Do not send separate SETATTR request before open(O_TRUNC)  */
 	unsigned atomic_o_trunc:1;
 
@@ -851,7 +857,7 @@ void fuse_request_send_background_locked(struct fuse_conn *fc,
 					 struct fuse_req *req);
 
 /* Abort all requests */
-void fuse_abort_conn(struct fuse_conn *fc);
+void fuse_abort_conn(struct fuse_conn *fc, bool is_abort);
 
 /**
  * Invalidate inode attributes
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 94a745acaef8..46a17de24e14 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -371,7 +371,7 @@ void fuse_unlock_inode(struct inode *inode)
 
 static void fuse_umount_begin(struct super_block *sb)
 {
-	fuse_abort_conn(get_fuse_conn_super(sb));
+	fuse_abort_conn(get_fuse_conn_super(sb), false);
 }
 
 static void fuse_send_destroy(struct fuse_conn *fc)
@@ -393,7 +393,7 @@ static void fuse_put_super(struct super_block *sb)
 
 	fuse_send_destroy(fc);
 
-	fuse_abort_conn(fc);
+	fuse_abort_conn(fc, false);
 	mutex_lock(&fuse_mutex);
 	list_del(&fc->entry);
 	fuse_ctl_remove_conn(fc);
@@ -918,6 +918,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
 				fc->posix_acl = 1;
 				fc->sb->s_xattr = fuse_acl_xattr_handlers;
 			}
+			if (arg->flags & FUSE_ABORT_ERROR)
+				fc->abort_err = 1;
 		} else {
 			ra_pages = fc->max_read / PAGE_SIZE;
 			fc->no_lock = 1;
@@ -948,7 +950,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
 		FUSE_FLOCK_LOCKS | FUSE_HAS_IOCTL_DIR | FUSE_AUTO_INVAL_DATA |
 		FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO |
 		FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT |
-		FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL;
+		FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL |
+		FUSE_ABORT_ERROR;
 	req->in.h.opcode = FUSE_INIT;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(*arg);
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index 42fa977e3b14..f9b11c43c8f6 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -112,6 +112,9 @@
  *  7.26
  *  - add FUSE_HANDLE_KILLPRIV
  *  - add FUSE_POSIX_ACL
+ *
+ *  7.27
+ *  - add FUSE_ABORT_ERROR
  */
 
 #ifndef _LINUX_FUSE_H
@@ -147,7 +150,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 26
+#define FUSE_KERNEL_MINOR_VERSION 27
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -244,6 +247,7 @@ struct fuse_file_lock {
  * FUSE_PARALLEL_DIROPS: allow parallel lookups and readdir
  * FUSE_HANDLE_KILLPRIV: fs handles killing suid/sgid/cap on write/chown/trunc
  * FUSE_POSIX_ACL: filesystem supports posix acls
+ * FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED
  */
 #define FUSE_ASYNC_READ		(1 << 0)
 #define FUSE_POSIX_LOCKS	(1 << 1)
@@ -266,6 +270,7 @@ struct fuse_file_lock {
 #define FUSE_PARALLEL_DIROPS    (1 << 18)
 #define FUSE_HANDLE_KILLPRIV	(1 << 19)
 #define FUSE_POSIX_ACL		(1 << 20)
+#define FUSE_ABORT_ERROR	(1 << 21)
 
 /**
  * CUSE INIT request/reply flags
-- 
2.15.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v3] fuse: return -ECONNABORTED on /dev/fuse read after abort
  2017-11-07  0:16     ` [PATCH v3] " Szymon Lukasz
@ 2017-11-09 18:29       ` kbuild test robot
  2017-11-09 19:44       ` kbuild test robot
  2017-11-09 20:23       ` [PATCH v4] " Szymon Lukasz
  2 siblings, 0 replies; 10+ messages in thread
From: kbuild test robot @ 2017-11-09 18:29 UTC (permalink / raw)
  To: Szymon Lukasz
  Cc: kbuild-all, Miklos Szeredi, linux-fsdevel, fuse-devel, Szymon Lukasz

[-- Attachment #1: Type: text/plain, Size: 9439 bytes --]

Hi Szymon,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on fuse/for-next]
[also build test ERROR on v4.14-rc8 next-20171109]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Szymon-Lukasz/fuse-return-ECONNABORTED-on-dev-fuse-read-after-abort/20171110-013308
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git for-next
config: blackfin-allyesconfig (attached as .config)
compiler: bfin-uclinux-gcc (GCC) 6.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=blackfin 

All errors (new ones prefixed by >>):

   fs//fuse/cuse.c: In function 'cuse_process_init_reply':
>> fs//fuse/cuse.c:409:2: error: too few arguments to function 'fuse_abort_conn'
     fuse_abort_conn(fc);
     ^~~~~~~~~~~~~~~
   In file included from fs//fuse/cuse.c:52:0:
   fs//fuse/fuse_i.h:860:6: note: declared here
    void fuse_abort_conn(struct fuse_conn *fc, bool is_abort);
         ^~~~~~~~~~~~~~~
   fs//fuse/cuse.c: In function 'cuse_class_abort_store':
   fs//fuse/cuse.c:584:2: error: too few arguments to function 'fuse_abort_conn'
     fuse_abort_conn(&cc->fc);
     ^~~~~~~~~~~~~~~
   In file included from fs//fuse/cuse.c:52:0:
   fs//fuse/fuse_i.h:860:6: note: declared here
    void fuse_abort_conn(struct fuse_conn *fc, bool is_abort);
         ^~~~~~~~~~~~~~~

vim +/fuse_abort_conn +409 fs//fuse/cuse.c

151060ac1 Tejun Heo      2009-04-14  299  
151060ac1 Tejun Heo      2009-04-14  300  /**
151060ac1 Tejun Heo      2009-04-14  301   * cuse_process_init_reply - finish initializing CUSE channel
151060ac1 Tejun Heo      2009-04-14  302   *
151060ac1 Tejun Heo      2009-04-14  303   * This function creates the character device and sets up all the
151060ac1 Tejun Heo      2009-04-14  304   * required data structures for it.  Please read the comment at the
151060ac1 Tejun Heo      2009-04-14  305   * top of this file for high level overview.
151060ac1 Tejun Heo      2009-04-14  306   */
151060ac1 Tejun Heo      2009-04-14  307  static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
151060ac1 Tejun Heo      2009-04-14  308  {
30783587b David Herrmann 2012-11-17  309  	struct cuse_conn *cc = fc_to_cc(fc), *pos;
07d5f69b4 Miklos Szeredi 2011-03-21  310  	struct cuse_init_out *arg = req->out.args[0].value;
151060ac1 Tejun Heo      2009-04-14  311  	struct page *page = req->pages[0];
151060ac1 Tejun Heo      2009-04-14  312  	struct cuse_devinfo devinfo = { };
151060ac1 Tejun Heo      2009-04-14  313  	struct device *dev;
151060ac1 Tejun Heo      2009-04-14  314  	struct cdev *cdev;
151060ac1 Tejun Heo      2009-04-14  315  	dev_t devt;
30783587b David Herrmann 2012-11-17  316  	int rc, i;
151060ac1 Tejun Heo      2009-04-14  317  
151060ac1 Tejun Heo      2009-04-14  318  	if (req->out.h.error ||
151060ac1 Tejun Heo      2009-04-14  319  	    arg->major != FUSE_KERNEL_VERSION || arg->minor < 11) {
151060ac1 Tejun Heo      2009-04-14  320  		goto err;
151060ac1 Tejun Heo      2009-04-14  321  	}
151060ac1 Tejun Heo      2009-04-14  322  
151060ac1 Tejun Heo      2009-04-14  323  	fc->minor = arg->minor;
151060ac1 Tejun Heo      2009-04-14  324  	fc->max_read = max_t(unsigned, arg->max_read, 4096);
151060ac1 Tejun Heo      2009-04-14  325  	fc->max_write = max_t(unsigned, arg->max_write, 4096);
151060ac1 Tejun Heo      2009-04-14  326  
151060ac1 Tejun Heo      2009-04-14  327  	/* parse init reply */
151060ac1 Tejun Heo      2009-04-14  328  	cc->unrestricted_ioctl = arg->flags & CUSE_UNRESTRICTED_IOCTL;
151060ac1 Tejun Heo      2009-04-14  329  
151060ac1 Tejun Heo      2009-04-14  330  	rc = cuse_parse_devinfo(page_address(page), req->out.args[1].size,
151060ac1 Tejun Heo      2009-04-14  331  				&devinfo);
151060ac1 Tejun Heo      2009-04-14  332  	if (rc)
151060ac1 Tejun Heo      2009-04-14  333  		goto err;
151060ac1 Tejun Heo      2009-04-14  334  
151060ac1 Tejun Heo      2009-04-14  335  	/* determine and reserve devt */
151060ac1 Tejun Heo      2009-04-14  336  	devt = MKDEV(arg->dev_major, arg->dev_minor);
151060ac1 Tejun Heo      2009-04-14  337  	if (!MAJOR(devt))
151060ac1 Tejun Heo      2009-04-14  338  		rc = alloc_chrdev_region(&devt, MINOR(devt), 1, devinfo.name);
151060ac1 Tejun Heo      2009-04-14  339  	else
151060ac1 Tejun Heo      2009-04-14  340  		rc = register_chrdev_region(devt, 1, devinfo.name);
151060ac1 Tejun Heo      2009-04-14  341  	if (rc) {
151060ac1 Tejun Heo      2009-04-14  342  		printk(KERN_ERR "CUSE: failed to register chrdev region\n");
151060ac1 Tejun Heo      2009-04-14  343  		goto err;
151060ac1 Tejun Heo      2009-04-14  344  	}
151060ac1 Tejun Heo      2009-04-14  345  
151060ac1 Tejun Heo      2009-04-14  346  	/* devt determined, create device */
151060ac1 Tejun Heo      2009-04-14  347  	rc = -ENOMEM;
151060ac1 Tejun Heo      2009-04-14  348  	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
151060ac1 Tejun Heo      2009-04-14  349  	if (!dev)
151060ac1 Tejun Heo      2009-04-14  350  		goto err_region;
151060ac1 Tejun Heo      2009-04-14  351  
151060ac1 Tejun Heo      2009-04-14  352  	device_initialize(dev);
151060ac1 Tejun Heo      2009-04-14  353  	dev_set_uevent_suppress(dev, 1);
151060ac1 Tejun Heo      2009-04-14  354  	dev->class = cuse_class;
151060ac1 Tejun Heo      2009-04-14  355  	dev->devt = devt;
151060ac1 Tejun Heo      2009-04-14  356  	dev->release = cuse_gendev_release;
151060ac1 Tejun Heo      2009-04-14  357  	dev_set_drvdata(dev, cc);
151060ac1 Tejun Heo      2009-04-14  358  	dev_set_name(dev, "%s", devinfo.name);
151060ac1 Tejun Heo      2009-04-14  359  
30783587b David Herrmann 2012-11-17  360  	mutex_lock(&cuse_lock);
30783587b David Herrmann 2012-11-17  361  
30783587b David Herrmann 2012-11-17  362  	/* make sure the device-name is unique */
30783587b David Herrmann 2012-11-17  363  	for (i = 0; i < CUSE_CONNTBL_LEN; ++i) {
30783587b David Herrmann 2012-11-17  364  		list_for_each_entry(pos, &cuse_conntbl[i], list)
30783587b David Herrmann 2012-11-17  365  			if (!strcmp(dev_name(pos->dev), dev_name(dev)))
30783587b David Herrmann 2012-11-17  366  				goto err_unlock;
30783587b David Herrmann 2012-11-17  367  	}
30783587b David Herrmann 2012-11-17  368  
151060ac1 Tejun Heo      2009-04-14  369  	rc = device_add(dev);
151060ac1 Tejun Heo      2009-04-14  370  	if (rc)
30783587b David Herrmann 2012-11-17  371  		goto err_unlock;
151060ac1 Tejun Heo      2009-04-14  372  
151060ac1 Tejun Heo      2009-04-14  373  	/* register cdev */
151060ac1 Tejun Heo      2009-04-14  374  	rc = -ENOMEM;
151060ac1 Tejun Heo      2009-04-14  375  	cdev = cdev_alloc();
151060ac1 Tejun Heo      2009-04-14  376  	if (!cdev)
30783587b David Herrmann 2012-11-17  377  		goto err_unlock;
151060ac1 Tejun Heo      2009-04-14  378  
151060ac1 Tejun Heo      2009-04-14  379  	cdev->owner = THIS_MODULE;
151060ac1 Tejun Heo      2009-04-14  380  	cdev->ops = &cuse_frontend_fops;
151060ac1 Tejun Heo      2009-04-14  381  
151060ac1 Tejun Heo      2009-04-14  382  	rc = cdev_add(cdev, devt, 1);
151060ac1 Tejun Heo      2009-04-14  383  	if (rc)
151060ac1 Tejun Heo      2009-04-14  384  		goto err_cdev;
151060ac1 Tejun Heo      2009-04-14  385  
151060ac1 Tejun Heo      2009-04-14  386  	cc->dev = dev;
151060ac1 Tejun Heo      2009-04-14  387  	cc->cdev = cdev;
151060ac1 Tejun Heo      2009-04-14  388  
151060ac1 Tejun Heo      2009-04-14  389  	/* make the device available */
151060ac1 Tejun Heo      2009-04-14  390  	list_add(&cc->list, cuse_conntbl_head(devt));
8ce03fd76 David Herrmann 2012-11-17  391  	mutex_unlock(&cuse_lock);
151060ac1 Tejun Heo      2009-04-14  392  
151060ac1 Tejun Heo      2009-04-14  393  	/* announce device availability */
151060ac1 Tejun Heo      2009-04-14  394  	dev_set_uevent_suppress(dev, 0);
151060ac1 Tejun Heo      2009-04-14  395  	kobject_uevent(&dev->kobj, KOBJ_ADD);
151060ac1 Tejun Heo      2009-04-14  396  out:
07d5f69b4 Miklos Szeredi 2011-03-21  397  	kfree(arg);
151060ac1 Tejun Heo      2009-04-14  398  	__free_page(page);
151060ac1 Tejun Heo      2009-04-14  399  	return;
151060ac1 Tejun Heo      2009-04-14  400  
151060ac1 Tejun Heo      2009-04-14  401  err_cdev:
151060ac1 Tejun Heo      2009-04-14  402  	cdev_del(cdev);
30783587b David Herrmann 2012-11-17  403  err_unlock:
30783587b David Herrmann 2012-11-17  404  	mutex_unlock(&cuse_lock);
151060ac1 Tejun Heo      2009-04-14  405  	put_device(dev);
151060ac1 Tejun Heo      2009-04-14  406  err_region:
151060ac1 Tejun Heo      2009-04-14  407  	unregister_chrdev_region(devt, 1);
151060ac1 Tejun Heo      2009-04-14  408  err:
580640ba5 Miklos Szeredi 2014-12-12 @409  	fuse_abort_conn(fc);
151060ac1 Tejun Heo      2009-04-14  410  	goto out;
151060ac1 Tejun Heo      2009-04-14  411  }
151060ac1 Tejun Heo      2009-04-14  412  

:::::: The code at line 409 was first introduced by commit
:::::: 580640ba5d331eb5631a5de46941c98f5ed90886 fuse: flush requests on umount

:::::: TO: Miklos Szeredi <mszeredi@suse.cz>
:::::: CC: Miklos Szeredi <mszeredi@suse.cz>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 46036 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v3] fuse: return -ECONNABORTED on /dev/fuse read after abort
  2017-11-07  0:16     ` [PATCH v3] " Szymon Lukasz
  2017-11-09 18:29       ` kbuild test robot
@ 2017-11-09 19:44       ` kbuild test robot
  2017-11-09 20:23       ` [PATCH v4] " Szymon Lukasz
  2 siblings, 0 replies; 10+ messages in thread
From: kbuild test robot @ 2017-11-09 19:44 UTC (permalink / raw)
  To: Szymon Lukasz
  Cc: kbuild-all, Miklos Szeredi, linux-fsdevel, fuse-devel, Szymon Lukasz

Hi Szymon,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on fuse/for-next]
[also build test WARNING on v4.14-rc8 next-20171109]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Szymon-Lukasz/fuse-return-ECONNABORTED-on-dev-fuse-read-after-abort/20171110-013308
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git for-next
reproduce:
        # apt-get install sparse
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)


vim +409 fs/fuse/cuse.c

151060ac1 Tejun Heo      2009-04-14  299  
151060ac1 Tejun Heo      2009-04-14  300  /**
151060ac1 Tejun Heo      2009-04-14  301   * cuse_process_init_reply - finish initializing CUSE channel
151060ac1 Tejun Heo      2009-04-14  302   *
151060ac1 Tejun Heo      2009-04-14  303   * This function creates the character device and sets up all the
151060ac1 Tejun Heo      2009-04-14  304   * required data structures for it.  Please read the comment at the
151060ac1 Tejun Heo      2009-04-14  305   * top of this file for high level overview.
151060ac1 Tejun Heo      2009-04-14  306   */
151060ac1 Tejun Heo      2009-04-14  307  static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
151060ac1 Tejun Heo      2009-04-14  308  {
30783587b David Herrmann 2012-11-17  309  	struct cuse_conn *cc = fc_to_cc(fc), *pos;
07d5f69b4 Miklos Szeredi 2011-03-21  310  	struct cuse_init_out *arg = req->out.args[0].value;
151060ac1 Tejun Heo      2009-04-14  311  	struct page *page = req->pages[0];
151060ac1 Tejun Heo      2009-04-14  312  	struct cuse_devinfo devinfo = { };
151060ac1 Tejun Heo      2009-04-14  313  	struct device *dev;
151060ac1 Tejun Heo      2009-04-14  314  	struct cdev *cdev;
151060ac1 Tejun Heo      2009-04-14  315  	dev_t devt;
30783587b David Herrmann 2012-11-17  316  	int rc, i;
151060ac1 Tejun Heo      2009-04-14  317  
151060ac1 Tejun Heo      2009-04-14  318  	if (req->out.h.error ||
151060ac1 Tejun Heo      2009-04-14  319  	    arg->major != FUSE_KERNEL_VERSION || arg->minor < 11) {
151060ac1 Tejun Heo      2009-04-14  320  		goto err;
151060ac1 Tejun Heo      2009-04-14  321  	}
151060ac1 Tejun Heo      2009-04-14  322  
151060ac1 Tejun Heo      2009-04-14  323  	fc->minor = arg->minor;
151060ac1 Tejun Heo      2009-04-14  324  	fc->max_read = max_t(unsigned, arg->max_read, 4096);
151060ac1 Tejun Heo      2009-04-14  325  	fc->max_write = max_t(unsigned, arg->max_write, 4096);
151060ac1 Tejun Heo      2009-04-14  326  
151060ac1 Tejun Heo      2009-04-14  327  	/* parse init reply */
151060ac1 Tejun Heo      2009-04-14  328  	cc->unrestricted_ioctl = arg->flags & CUSE_UNRESTRICTED_IOCTL;
151060ac1 Tejun Heo      2009-04-14  329  
151060ac1 Tejun Heo      2009-04-14  330  	rc = cuse_parse_devinfo(page_address(page), req->out.args[1].size,
151060ac1 Tejun Heo      2009-04-14  331  				&devinfo);
151060ac1 Tejun Heo      2009-04-14  332  	if (rc)
151060ac1 Tejun Heo      2009-04-14  333  		goto err;
151060ac1 Tejun Heo      2009-04-14  334  
151060ac1 Tejun Heo      2009-04-14  335  	/* determine and reserve devt */
151060ac1 Tejun Heo      2009-04-14  336  	devt = MKDEV(arg->dev_major, arg->dev_minor);
151060ac1 Tejun Heo      2009-04-14  337  	if (!MAJOR(devt))
151060ac1 Tejun Heo      2009-04-14  338  		rc = alloc_chrdev_region(&devt, MINOR(devt), 1, devinfo.name);
151060ac1 Tejun Heo      2009-04-14  339  	else
151060ac1 Tejun Heo      2009-04-14  340  		rc = register_chrdev_region(devt, 1, devinfo.name);
151060ac1 Tejun Heo      2009-04-14  341  	if (rc) {
151060ac1 Tejun Heo      2009-04-14  342  		printk(KERN_ERR "CUSE: failed to register chrdev region\n");
151060ac1 Tejun Heo      2009-04-14  343  		goto err;
151060ac1 Tejun Heo      2009-04-14  344  	}
151060ac1 Tejun Heo      2009-04-14  345  
151060ac1 Tejun Heo      2009-04-14  346  	/* devt determined, create device */
151060ac1 Tejun Heo      2009-04-14  347  	rc = -ENOMEM;
151060ac1 Tejun Heo      2009-04-14  348  	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
151060ac1 Tejun Heo      2009-04-14  349  	if (!dev)
151060ac1 Tejun Heo      2009-04-14  350  		goto err_region;
151060ac1 Tejun Heo      2009-04-14  351  
151060ac1 Tejun Heo      2009-04-14  352  	device_initialize(dev);
151060ac1 Tejun Heo      2009-04-14  353  	dev_set_uevent_suppress(dev, 1);
151060ac1 Tejun Heo      2009-04-14  354  	dev->class = cuse_class;
151060ac1 Tejun Heo      2009-04-14  355  	dev->devt = devt;
151060ac1 Tejun Heo      2009-04-14  356  	dev->release = cuse_gendev_release;
151060ac1 Tejun Heo      2009-04-14  357  	dev_set_drvdata(dev, cc);
151060ac1 Tejun Heo      2009-04-14  358  	dev_set_name(dev, "%s", devinfo.name);
151060ac1 Tejun Heo      2009-04-14  359  
30783587b David Herrmann 2012-11-17  360  	mutex_lock(&cuse_lock);
30783587b David Herrmann 2012-11-17  361  
30783587b David Herrmann 2012-11-17  362  	/* make sure the device-name is unique */
30783587b David Herrmann 2012-11-17  363  	for (i = 0; i < CUSE_CONNTBL_LEN; ++i) {
30783587b David Herrmann 2012-11-17  364  		list_for_each_entry(pos, &cuse_conntbl[i], list)
30783587b David Herrmann 2012-11-17  365  			if (!strcmp(dev_name(pos->dev), dev_name(dev)))
30783587b David Herrmann 2012-11-17  366  				goto err_unlock;
30783587b David Herrmann 2012-11-17  367  	}
30783587b David Herrmann 2012-11-17  368  
151060ac1 Tejun Heo      2009-04-14  369  	rc = device_add(dev);
151060ac1 Tejun Heo      2009-04-14  370  	if (rc)
30783587b David Herrmann 2012-11-17  371  		goto err_unlock;
151060ac1 Tejun Heo      2009-04-14  372  
151060ac1 Tejun Heo      2009-04-14  373  	/* register cdev */
151060ac1 Tejun Heo      2009-04-14  374  	rc = -ENOMEM;
151060ac1 Tejun Heo      2009-04-14  375  	cdev = cdev_alloc();
151060ac1 Tejun Heo      2009-04-14  376  	if (!cdev)
30783587b David Herrmann 2012-11-17  377  		goto err_unlock;
151060ac1 Tejun Heo      2009-04-14  378  
151060ac1 Tejun Heo      2009-04-14  379  	cdev->owner = THIS_MODULE;
151060ac1 Tejun Heo      2009-04-14  380  	cdev->ops = &cuse_frontend_fops;
151060ac1 Tejun Heo      2009-04-14  381  
151060ac1 Tejun Heo      2009-04-14  382  	rc = cdev_add(cdev, devt, 1);
151060ac1 Tejun Heo      2009-04-14  383  	if (rc)
151060ac1 Tejun Heo      2009-04-14  384  		goto err_cdev;
151060ac1 Tejun Heo      2009-04-14  385  
151060ac1 Tejun Heo      2009-04-14  386  	cc->dev = dev;
151060ac1 Tejun Heo      2009-04-14  387  	cc->cdev = cdev;
151060ac1 Tejun Heo      2009-04-14  388  
151060ac1 Tejun Heo      2009-04-14  389  	/* make the device available */
151060ac1 Tejun Heo      2009-04-14  390  	list_add(&cc->list, cuse_conntbl_head(devt));
8ce03fd76 David Herrmann 2012-11-17  391  	mutex_unlock(&cuse_lock);
151060ac1 Tejun Heo      2009-04-14  392  
151060ac1 Tejun Heo      2009-04-14  393  	/* announce device availability */
151060ac1 Tejun Heo      2009-04-14  394  	dev_set_uevent_suppress(dev, 0);
151060ac1 Tejun Heo      2009-04-14  395  	kobject_uevent(&dev->kobj, KOBJ_ADD);
151060ac1 Tejun Heo      2009-04-14  396  out:
07d5f69b4 Miklos Szeredi 2011-03-21  397  	kfree(arg);
151060ac1 Tejun Heo      2009-04-14  398  	__free_page(page);
151060ac1 Tejun Heo      2009-04-14  399  	return;
151060ac1 Tejun Heo      2009-04-14  400  
151060ac1 Tejun Heo      2009-04-14  401  err_cdev:
151060ac1 Tejun Heo      2009-04-14  402  	cdev_del(cdev);
30783587b David Herrmann 2012-11-17  403  err_unlock:
30783587b David Herrmann 2012-11-17  404  	mutex_unlock(&cuse_lock);
151060ac1 Tejun Heo      2009-04-14  405  	put_device(dev);
151060ac1 Tejun Heo      2009-04-14  406  err_region:
151060ac1 Tejun Heo      2009-04-14  407  	unregister_chrdev_region(devt, 1);
151060ac1 Tejun Heo      2009-04-14  408  err:
580640ba5 Miklos Szeredi 2014-12-12 @409  	fuse_abort_conn(fc);
151060ac1 Tejun Heo      2009-04-14  410  	goto out;
151060ac1 Tejun Heo      2009-04-14  411  }
151060ac1 Tejun Heo      2009-04-14  412  

:::::: The code at line 409 was first introduced by commit
:::::: 580640ba5d331eb5631a5de46941c98f5ed90886 fuse: flush requests on umount

:::::: TO: Miklos Szeredi <mszeredi@suse.cz>
:::::: CC: Miklos Szeredi <mszeredi@suse.cz>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v4] fuse: return -ECONNABORTED on /dev/fuse read after abort
  2017-11-07  0:16     ` [PATCH v3] " Szymon Lukasz
  2017-11-09 18:29       ` kbuild test robot
  2017-11-09 19:44       ` kbuild test robot
@ 2017-11-09 20:23       ` Szymon Lukasz
       [not found]         ` <20171109202335.19797-1-noh4hss-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
                           ` (2 more replies)
  2 siblings, 3 replies; 10+ messages in thread
From: Szymon Lukasz @ 2017-11-09 20:23 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: linux-fsdevel, fuse-devel, Szymon Lukasz

Adds a new capability flag FUSE_ABORT_ERROR. If set and the connection
is gone because of sysfs abort, reading from the device will return
-ECONNABORTED.

Signed-off-by: Szymon Lukasz <noh4hss@gmail.com>
---
 fs/fuse/control.c         |  2 +-
 fs/fuse/cuse.c            |  4 ++--
 fs/fuse/dev.c             | 12 +++++++-----
 fs/fuse/fuse_i.h          |  8 +++++++-
 fs/fuse/inode.c           |  9 ++++++---
 include/uapi/linux/fuse.h |  7 ++++++-
 6 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/fs/fuse/control.c b/fs/fuse/control.c
index b9ea99c5b5b3..78fb7a07c5ca 100644
--- a/fs/fuse/control.c
+++ b/fs/fuse/control.c
@@ -35,7 +35,7 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf,
 {
 	struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
 	if (fc) {
-		fuse_abort_conn(fc);
+		fuse_abort_conn(fc, true);
 		fuse_conn_put(fc);
 	}
 	return count;
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
index e9e97803442a..31d33b69957f 100644
--- a/fs/fuse/cuse.c
+++ b/fs/fuse/cuse.c
@@ -406,7 +406,7 @@ static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
 err_region:
 	unregister_chrdev_region(devt, 1);
 err:
-	fuse_abort_conn(fc);
+	fuse_abort_conn(fc, false);
 	goto out;
 }
 
@@ -581,7 +581,7 @@ static ssize_t cuse_class_abort_store(struct device *dev,
 {
 	struct cuse_conn *cc = dev_get_drvdata(dev);
 
-	fuse_abort_conn(&cc->fc);
+	fuse_abort_conn(&cc->fc, false);
 	return count;
 }
 static DEVICE_ATTR(abort, 0200, NULL, cuse_class_abort_store);
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 13c65dd2d37d..2e1beda0b82b 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1234,9 +1234,10 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
 	if (err)
 		goto err_unlock;
 
-	err = -ENODEV;
-	if (!fiq->connected)
+	if (!fiq->connected) {
+		err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV;
 		goto err_unlock;
+	}
 
 	if (!list_empty(&fiq->interrupts)) {
 		req = list_entry(fiq->interrupts.next, struct fuse_req,
@@ -1287,7 +1288,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
 	spin_lock(&fpq->lock);
 	clear_bit(FR_LOCKED, &req->flags);
 	if (!fpq->connected) {
-		err = -ENODEV;
+		err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV;
 		goto out_end;
 	}
 	if (err) {
@@ -2076,7 +2077,7 @@ static void end_polls(struct fuse_conn *fc)
  * is OK, the request will in that case be removed from the list before we touch
  * it.
  */
-void fuse_abort_conn(struct fuse_conn *fc)
+void fuse_abort_conn(struct fuse_conn *fc, bool is_abort)
 {
 	struct fuse_iqueue *fiq = &fc->iq;
 
@@ -2089,6 +2090,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
 
 		fc->connected = 0;
 		fc->blocked = 0;
+		fc->aborted = is_abort;
 		fuse_set_initialized(fc);
 		list_for_each_entry(fud, &fc->devices, entry) {
 			struct fuse_pqueue *fpq = &fud->pq;
@@ -2151,7 +2153,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)
 		/* Are we the last open device? */
 		if (atomic_dec_and_test(&fc->dev_count)) {
 			WARN_ON(fc->iq.fasync != NULL);
-			fuse_abort_conn(fc);
+			fuse_abort_conn(fc, false);
 		}
 		fuse_dev_free(fud);
 	}
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index d5773ca67ad2..2f8a261d8669 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -515,6 +515,9 @@ struct fuse_conn {
 	    abort and device release */
 	unsigned connected;
 
+	/** Connection aborted via sysfs */
+	bool aborted;
+
 	/** Connection failed (version mismatch).  Cannot race with
 	    setting other bitfields since it is only set once in INIT
 	    reply, before any other request, and never cleared */
@@ -526,6 +529,9 @@ struct fuse_conn {
 	/** Do readpages asynchronously?  Only set in INIT */
 	unsigned async_read:1;
 
+	/** Return an unique read error after abort.  Only set in INIT */
+	unsigned abort_err:1;
+
 	/** Do not send separate SETATTR request before open(O_TRUNC)  */
 	unsigned atomic_o_trunc:1;
 
@@ -851,7 +857,7 @@ void fuse_request_send_background_locked(struct fuse_conn *fc,
 					 struct fuse_req *req);
 
 /* Abort all requests */
-void fuse_abort_conn(struct fuse_conn *fc);
+void fuse_abort_conn(struct fuse_conn *fc, bool is_abort);
 
 /**
  * Invalidate inode attributes
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 94a745acaef8..46a17de24e14 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -371,7 +371,7 @@ void fuse_unlock_inode(struct inode *inode)
 
 static void fuse_umount_begin(struct super_block *sb)
 {
-	fuse_abort_conn(get_fuse_conn_super(sb));
+	fuse_abort_conn(get_fuse_conn_super(sb), false);
 }
 
 static void fuse_send_destroy(struct fuse_conn *fc)
@@ -393,7 +393,7 @@ static void fuse_put_super(struct super_block *sb)
 
 	fuse_send_destroy(fc);
 
-	fuse_abort_conn(fc);
+	fuse_abort_conn(fc, false);
 	mutex_lock(&fuse_mutex);
 	list_del(&fc->entry);
 	fuse_ctl_remove_conn(fc);
@@ -918,6 +918,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
 				fc->posix_acl = 1;
 				fc->sb->s_xattr = fuse_acl_xattr_handlers;
 			}
+			if (arg->flags & FUSE_ABORT_ERROR)
+				fc->abort_err = 1;
 		} else {
 			ra_pages = fc->max_read / PAGE_SIZE;
 			fc->no_lock = 1;
@@ -948,7 +950,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
 		FUSE_FLOCK_LOCKS | FUSE_HAS_IOCTL_DIR | FUSE_AUTO_INVAL_DATA |
 		FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO |
 		FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT |
-		FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL;
+		FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL |
+		FUSE_ABORT_ERROR;
 	req->in.h.opcode = FUSE_INIT;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(*arg);
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index 42fa977e3b14..f9b11c43c8f6 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -112,6 +112,9 @@
  *  7.26
  *  - add FUSE_HANDLE_KILLPRIV
  *  - add FUSE_POSIX_ACL
+ *
+ *  7.27
+ *  - add FUSE_ABORT_ERROR
  */
 
 #ifndef _LINUX_FUSE_H
@@ -147,7 +150,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 26
+#define FUSE_KERNEL_MINOR_VERSION 27
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -244,6 +247,7 @@ struct fuse_file_lock {
  * FUSE_PARALLEL_DIROPS: allow parallel lookups and readdir
  * FUSE_HANDLE_KILLPRIV: fs handles killing suid/sgid/cap on write/chown/trunc
  * FUSE_POSIX_ACL: filesystem supports posix acls
+ * FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED
  */
 #define FUSE_ASYNC_READ		(1 << 0)
 #define FUSE_POSIX_LOCKS	(1 << 1)
@@ -266,6 +270,7 @@ struct fuse_file_lock {
 #define FUSE_PARALLEL_DIROPS    (1 << 18)
 #define FUSE_HANDLE_KILLPRIV	(1 << 19)
 #define FUSE_POSIX_ACL		(1 << 20)
+#define FUSE_ABORT_ERROR	(1 << 21)
 
 /**
  * CUSE INIT request/reply flags
-- 
2.15.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v4] fuse: return -ECONNABORTED on /dev/fuse read after abort
       [not found]         ` <20171109202335.19797-1-noh4hss-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2017-11-21 22:16           ` Szymon Łukasz
  0 siblings, 0 replies; 10+ messages in thread
From: Szymon Łukasz @ 2017-11-21 22:16 UTC (permalink / raw)
  To: Miklos Szeredi
  Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Szymon Lukasz


[-- Attachment #1.1: Type: text/plain, Size: 8455 bytes --]

Bump

On Thu, Nov 9, 2017 at 9:23 PM, Szymon Lukasz <noh4hss-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> Adds a new capability flag FUSE_ABORT_ERROR. If set and the connection
> is gone because of sysfs abort, reading from the device will return
> -ECONNABORTED.
>
> Signed-off-by: Szymon Lukasz <noh4hss-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
>  fs/fuse/control.c         |  2 +-
>  fs/fuse/cuse.c            |  4 ++--
>  fs/fuse/dev.c             | 12 +++++++-----
>  fs/fuse/fuse_i.h          |  8 +++++++-
>  fs/fuse/inode.c           |  9 ++++++---
>  include/uapi/linux/fuse.h |  7 ++++++-
>  6 files changed, 29 insertions(+), 13 deletions(-)
>
> diff --git a/fs/fuse/control.c b/fs/fuse/control.c
> index b9ea99c5b5b3..78fb7a07c5ca 100644
> --- a/fs/fuse/control.c
> +++ b/fs/fuse/control.c
> @@ -35,7 +35,7 @@ static ssize_t fuse_conn_abort_write(struct file *file,
> const char __user *buf,
>  {
>         struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
>         if (fc) {
> -               fuse_abort_conn(fc);
> +               fuse_abort_conn(fc, true);
>                 fuse_conn_put(fc);
>         }
>         return count;
> diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
> index e9e97803442a..31d33b69957f 100644
> --- a/fs/fuse/cuse.c
> +++ b/fs/fuse/cuse.c
> @@ -406,7 +406,7 @@ static void cuse_process_init_reply(struct fuse_conn
> *fc, struct fuse_req *req)
>  err_region:
>         unregister_chrdev_region(devt, 1);
>  err:
> -       fuse_abort_conn(fc);
> +       fuse_abort_conn(fc, false);
>         goto out;
>  }
>
> @@ -581,7 +581,7 @@ static ssize_t cuse_class_abort_store(struct device
> *dev,
>  {
>         struct cuse_conn *cc = dev_get_drvdata(dev);
>
> -       fuse_abort_conn(&cc->fc);
> +       fuse_abort_conn(&cc->fc, false);
>         return count;
>  }
>  static DEVICE_ATTR(abort, 0200, NULL, cuse_class_abort_store);
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 13c65dd2d37d..2e1beda0b82b 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -1234,9 +1234,10 @@ static ssize_t fuse_dev_do_read(struct fuse_dev
> *fud, struct file *file,
>         if (err)
>                 goto err_unlock;
>
> -       err = -ENODEV;
> -       if (!fiq->connected)
> +       if (!fiq->connected) {
> +               err = (fc->aborted && fc->abort_err) ? -ECONNABORTED :
> -ENODEV;
>                 goto err_unlock;
> +       }
>
>         if (!list_empty(&fiq->interrupts)) {
>                 req = list_entry(fiq->interrupts.next, struct fuse_req,
> @@ -1287,7 +1288,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev
> *fud, struct file *file,
>         spin_lock(&fpq->lock);
>         clear_bit(FR_LOCKED, &req->flags);
>         if (!fpq->connected) {
> -               err = -ENODEV;
> +               err = (fc->aborted && fc->abort_err) ? -ECONNABORTED :
> -ENODEV;
>                 goto out_end;
>         }
>         if (err) {
> @@ -2076,7 +2077,7 @@ static void end_polls(struct fuse_conn *fc)
>   * is OK, the request will in that case be removed from the list before
> we touch
>   * it.
>   */
> -void fuse_abort_conn(struct fuse_conn *fc)
> +void fuse_abort_conn(struct fuse_conn *fc, bool is_abort)
>  {
>         struct fuse_iqueue *fiq = &fc->iq;
>
> @@ -2089,6 +2090,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
>
>                 fc->connected = 0;
>                 fc->blocked = 0;
> +               fc->aborted = is_abort;
>                 fuse_set_initialized(fc);
>                 list_for_each_entry(fud, &fc->devices, entry) {
>                         struct fuse_pqueue *fpq = &fud->pq;
> @@ -2151,7 +2153,7 @@ int fuse_dev_release(struct inode *inode, struct
> file *file)
>                 /* Are we the last open device? */
>                 if (atomic_dec_and_test(&fc->dev_count)) {
>                         WARN_ON(fc->iq.fasync != NULL);
> -                       fuse_abort_conn(fc);
> +                       fuse_abort_conn(fc, false);
>                 }
>                 fuse_dev_free(fud);
>         }
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index d5773ca67ad2..2f8a261d8669 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -515,6 +515,9 @@ struct fuse_conn {
>             abort and device release */
>         unsigned connected;
>
> +       /** Connection aborted via sysfs */
> +       bool aborted;
> +
>         /** Connection failed (version mismatch).  Cannot race with
>             setting other bitfields since it is only set once in INIT
>             reply, before any other request, and never cleared */
> @@ -526,6 +529,9 @@ struct fuse_conn {
>         /** Do readpages asynchronously?  Only set in INIT */
>         unsigned async_read:1;
>
> +       /** Return an unique read error after abort.  Only set in INIT */
> +       unsigned abort_err:1;
> +
>         /** Do not send separate SETATTR request before open(O_TRUNC)  */
>         unsigned atomic_o_trunc:1;
>
> @@ -851,7 +857,7 @@ void fuse_request_send_background_locked(struct
> fuse_conn *fc,
>                                          struct fuse_req *req);
>
>  /* Abort all requests */
> -void fuse_abort_conn(struct fuse_conn *fc);
> +void fuse_abort_conn(struct fuse_conn *fc, bool is_abort);
>
>  /**
>   * Invalidate inode attributes
> diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> index 94a745acaef8..46a17de24e14 100644
> --- a/fs/fuse/inode.c
> +++ b/fs/fuse/inode.c
> @@ -371,7 +371,7 @@ void fuse_unlock_inode(struct inode *inode)
>
>  static void fuse_umount_begin(struct super_block *sb)
>  {
> -       fuse_abort_conn(get_fuse_conn_super(sb));
> +       fuse_abort_conn(get_fuse_conn_super(sb), false);
>  }
>
>  static void fuse_send_destroy(struct fuse_conn *fc)
> @@ -393,7 +393,7 @@ static void fuse_put_super(struct super_block *sb)
>
>         fuse_send_destroy(fc);
>
> -       fuse_abort_conn(fc);
> +       fuse_abort_conn(fc, false);
>         mutex_lock(&fuse_mutex);
>         list_del(&fc->entry);
>         fuse_ctl_remove_conn(fc);
> @@ -918,6 +918,8 @@ static void process_init_reply(struct fuse_conn *fc,
> struct fuse_req *req)
>                                 fc->posix_acl = 1;
>                                 fc->sb->s_xattr = fuse_acl_xattr_handlers;
>                         }
> +                       if (arg->flags & FUSE_ABORT_ERROR)
> +                               fc->abort_err = 1;
>                 } else {
>                         ra_pages = fc->max_read / PAGE_SIZE;
>                         fc->no_lock = 1;
> @@ -948,7 +950,8 @@ static void fuse_send_init(struct fuse_conn *fc,
> struct fuse_req *req)
>                 FUSE_FLOCK_LOCKS | FUSE_HAS_IOCTL_DIR |
> FUSE_AUTO_INVAL_DATA |
>                 FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO |
> FUSE_ASYNC_DIO |
>                 FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT |
> -               FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV |
> FUSE_POSIX_ACL;
> +               FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV |
> FUSE_POSIX_ACL |
> +               FUSE_ABORT_ERROR;
>         req->in.h.opcode = FUSE_INIT;
>         req->in.numargs = 1;
>         req->in.args[0].size = sizeof(*arg);
> diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
> index 42fa977e3b14..f9b11c43c8f6 100644
> --- a/include/uapi/linux/fuse.h
> +++ b/include/uapi/linux/fuse.h
> @@ -112,6 +112,9 @@
>   *  7.26
>   *  - add FUSE_HANDLE_KILLPRIV
>   *  - add FUSE_POSIX_ACL
> + *
> + *  7.27
> + *  - add FUSE_ABORT_ERROR
>   */
>
>  #ifndef _LINUX_FUSE_H
> @@ -147,7 +150,7 @@
>  #define FUSE_KERNEL_VERSION 7
>
>  /** Minor version number of this interface */
> -#define FUSE_KERNEL_MINOR_VERSION 26
> +#define FUSE_KERNEL_MINOR_VERSION 27
>
>  /** The node ID of the root inode */
>  #define FUSE_ROOT_ID 1
> @@ -244,6 +247,7 @@ struct fuse_file_lock {
>   * FUSE_PARALLEL_DIROPS: allow parallel lookups and readdir
>   * FUSE_HANDLE_KILLPRIV: fs handles killing suid/sgid/cap on
> write/chown/trunc
>   * FUSE_POSIX_ACL: filesystem supports posix acls
> + * FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED
>   */
>  #define FUSE_ASYNC_READ                (1 << 0)
>  #define FUSE_POSIX_LOCKS       (1 << 1)
> @@ -266,6 +270,7 @@ struct fuse_file_lock {
>  #define FUSE_PARALLEL_DIROPS    (1 << 18)
>  #define FUSE_HANDLE_KILLPRIV   (1 << 19)
>  #define FUSE_POSIX_ACL         (1 << 20)
> +#define FUSE_ABORT_ERROR       (1 << 21)
>
>  /**
>   * CUSE INIT request/reply flags
> --
> 2.15.0
>
>

[-- Attachment #1.2: Type: text/html, Size: 10513 bytes --]

[-- Attachment #2: Type: text/plain, Size: 202 bytes --]

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot

[-- Attachment #3: Type: text/plain, Size: 119 bytes --]

-- 
fuse-devel mailing list
To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v4] fuse: return -ECONNABORTED on /dev/fuse read after abort
  2017-11-09 20:23       ` [PATCH v4] " Szymon Lukasz
       [not found]         ` <20171109202335.19797-1-noh4hss-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2017-11-21 22:43         ` Szymon Lukasz
  2018-03-21 11:57         ` Miklos Szeredi
  2 siblings, 0 replies; 10+ messages in thread
From: Szymon Lukasz @ 2017-11-21 22:43 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: linux-fsdevel

Bump

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v4] fuse: return -ECONNABORTED on /dev/fuse read after abort
  2017-11-09 20:23       ` [PATCH v4] " Szymon Lukasz
       [not found]         ` <20171109202335.19797-1-noh4hss-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2017-11-21 22:43         ` Szymon Lukasz
@ 2018-03-21 11:57         ` Miklos Szeredi
  2 siblings, 0 replies; 10+ messages in thread
From: Miklos Szeredi @ 2018-03-21 11:57 UTC (permalink / raw)
  To: Szymon Lukasz; +Cc: linux-fsdevel, fuse-devel

On Thu, Nov 9, 2017 at 9:23 PM, Szymon Lukasz <noh4hss@gmail.com> wrote:
> Adds a new capability flag FUSE_ABORT_ERROR. If set and the connection
> is gone because of sysfs abort, reading from the device will return
> -ECONNABORTED.

Thanks, pushed to:

  git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git for-next

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2018-03-21 11:57 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-31 18:55 [PATCH] fuse: return -ECONNABORTED on /dev/fuse read after abort Szymon Lukasz
2017-11-03 15:04 ` [PATCH v2] " Szymon Lukasz
2017-11-06  9:51   ` Miklos Szeredi
2017-11-07  0:16     ` [PATCH v3] " Szymon Lukasz
2017-11-09 18:29       ` kbuild test robot
2017-11-09 19:44       ` kbuild test robot
2017-11-09 20:23       ` [PATCH v4] " Szymon Lukasz
     [not found]         ` <20171109202335.19797-1-noh4hss-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2017-11-21 22:16           ` Szymon Łukasz
2017-11-21 22:43         ` Szymon Lukasz
2018-03-21 11:57         ` Miklos Szeredi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.