linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().
@ 2016-12-05  3:19 cuilifei
  2016-12-06 22:15 ` Rafael J. Wysocki
  0 siblings, 1 reply; 14+ messages in thread
From: cuilifei @ 2016-12-05  3:19 UTC (permalink / raw)
  To: linux-kernel
  Cc: miklos, rjw, pavel, len.brown, linux-fsdevel, viro, piaoyingmin,
	liucai, cuilifei

Freezing process can abort when a client is waiting uninterruptibly
for a response. Add new macro wait_fatal_freezable to try to fix it.

Signed-off-by: cuilifei <cuilifei@xiaomi.com>
---
 fs/fuse/dev.c           | 30 ++++++++++++++++++++++++++----
 include/linux/freezer.h | 26 ++++++++++++++++++++++++++
 2 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 70ea57c..e33a081 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -19,6 +19,7 @@
 #include <linux/pipe_fs_i.h>
 #include <linux/swap.h>
 #include <linux/splice.h>
+#include <linux/freezer.h>
 
 MODULE_ALIAS_MISCDEV(FUSE_MINOR);
 MODULE_ALIAS("devname:fuse");
@@ -99,6 +100,19 @@ void fuse_request_free(struct fuse_req *req)
 	kmem_cache_free(fuse_req_cachep, req);
 }
 
+static void block_sigs(sigset_t *oldset)
+{
+	sigset_t mask;
+
+	siginitsetinv(&mask, sigmask(SIGKILL));
+	sigprocmask(SIG_BLOCK, &mask, oldset);
+}
+
+static void restore_sigs(sigset_t *oldset)
+{
+	sigprocmask(SIG_SETMASK, oldset, NULL);
+}
+
 void __fuse_get_request(struct fuse_req *req)
 {
 	atomic_inc(&req->count);
@@ -134,13 +148,18 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
 				       bool for_background)
 {
 	struct fuse_req *req;
+	sigset_t oldset;
+	int intr;
 	int err;
 	atomic_inc(&fc->num_waiting);
 
 	if (fuse_block_alloc(fc, for_background)) {
 		err = -EINTR;
-		if (wait_event_killable_exclusive(fc->blocked_waitq,
-				!fuse_block_alloc(fc, for_background)))
+		block_sigs(&oldset);
+		intr = wait_fatal_freezable(fc->blocked_waitq,
+				!fuse_block_alloc(fc, for_background), true);
+		restore_sigs(&oldset);
+		if (intr)
 			goto out;
 	}
 	/* Matches smp_wmb() in fuse_set_initialized() */
@@ -427,9 +446,12 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
 	}
 
 	if (!test_bit(FR_FORCE, &req->flags)) {
+		sigset_t oldset;
 		/* Only fatal signals may interrupt this */
-		err = wait_event_killable(req->waitq,
-					test_bit(FR_FINISHED, &req->flags));
+		block_sigs(&oldset);
+		err = wait_fatal_freezable(req->waitq,
+				test_bit(FR_FINISHED, &req->flags), false);
+		restore_sigs(&oldset);
 		if (!err)
 			return;
 
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
index dd03e83..2504cd0 100644
--- a/include/linux/freezer.h
+++ b/include/linux/freezer.h
@@ -256,6 +256,22 @@ static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
 	__retval;							\
 })
 
+#define wait_fatal_freezable(wq, condition, exclusive)			\
+({									\
+	int __ret = 0;							\
+	do {								\
+		if (exclusive)						\
+			__ret = wait_event_interruptible_exclusive(wq,	\
+							condition);	\
+		else							\
+			__ret = wait_event_interruptible(wq,		\
+							condition);	\
+		if (!__ret || fatal_signal_pending(current))		\
+			break;						\
+	} while (try_to_freeze());					\
+	__ret;								\
+})
+
 #else /* !CONFIG_FREEZER */
 static inline bool frozen(struct task_struct *p) { return false; }
 static inline bool freezing(struct task_struct *p) { return false; }
@@ -296,6 +312,16 @@ static inline void set_freezable(void) {}
 #define wait_event_freezekillable_unsafe(wq, condition)			\
 		wait_event_killable(wq, condition)
 
+#define wait_fatal_freezable(wq, condition, exclusive)			\
+({									\
+	int __ret = 0;							\
+	if (exclusive)							\
+		__ret = wait_event_killable_exclusive(wq, condition);	\
+	else								\
+		__ret = wait_event_killable(wq,	condition);		\
+	__ret;								\
+})
+
 #endif /* !CONFIG_FREEZER */
 
 #endif	/* FREEZER_H_INCLUDED */
-- 
1.9.1

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

* Re: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().
  2016-12-05  3:19 [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}() cuilifei
@ 2016-12-06 22:15 ` Rafael J. Wysocki
  2016-12-08  6:31   ` 答复: " 崔立飞
  0 siblings, 1 reply; 14+ messages in thread
From: Rafael J. Wysocki @ 2016-12-06 22:15 UTC (permalink / raw)
  To: cuilifei
  Cc: linux-kernel, miklos, pavel, len.brown, linux-fsdevel, viro,
	piaoyingmin, liucai, Jiri Kosina

On Monday, December 05, 2016 11:19:45 AM cuilifei wrote:
> Freezing process can abort when a client is waiting uninterruptibly
> for a response. Add new macro wait_fatal_freezable to try to fix it.
> 
> Signed-off-by: cuilifei <cuilifei@xiaomi.com>

I'm not a big fan of this to be honest.

Do we really want to suspend the system (or freeze tasks for other reasons)
if that happens?

> ---
>  fs/fuse/dev.c           | 30 ++++++++++++++++++++++++++----
>  include/linux/freezer.h | 26 ++++++++++++++++++++++++++
>  2 files changed, 52 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 70ea57c..e33a081 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -19,6 +19,7 @@
>  #include <linux/pipe_fs_i.h>
>  #include <linux/swap.h>
>  #include <linux/splice.h>
> +#include <linux/freezer.h>
>  
>  MODULE_ALIAS_MISCDEV(FUSE_MINOR);
>  MODULE_ALIAS("devname:fuse");
> @@ -99,6 +100,19 @@ void fuse_request_free(struct fuse_req *req)
>  	kmem_cache_free(fuse_req_cachep, req);
>  }
>  
> +static void block_sigs(sigset_t *oldset)
> +{
> +	sigset_t mask;
> +
> +	siginitsetinv(&mask, sigmask(SIGKILL));
> +	sigprocmask(SIG_BLOCK, &mask, oldset);
> +}
> +
> +static void restore_sigs(sigset_t *oldset)
> +{
> +	sigprocmask(SIG_SETMASK, oldset, NULL);
> +}
> +
>  void __fuse_get_request(struct fuse_req *req)
>  {
>  	atomic_inc(&req->count);
> @@ -134,13 +148,18 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
>  				       bool for_background)
>  {
>  	struct fuse_req *req;
> +	sigset_t oldset;
> +	int intr;
>  	int err;
>  	atomic_inc(&fc->num_waiting);
>  
>  	if (fuse_block_alloc(fc, for_background)) {
>  		err = -EINTR;
> -		if (wait_event_killable_exclusive(fc->blocked_waitq,
> -				!fuse_block_alloc(fc, for_background)))
> +		block_sigs(&oldset);
> +		intr = wait_fatal_freezable(fc->blocked_waitq,
> +				!fuse_block_alloc(fc, for_background), true);
> +		restore_sigs(&oldset);
> +		if (intr)
>  			goto out;
>  	}
>  	/* Matches smp_wmb() in fuse_set_initialized() */
> @@ -427,9 +446,12 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
>  	}
>  
>  	if (!test_bit(FR_FORCE, &req->flags)) {
> +		sigset_t oldset;
>  		/* Only fatal signals may interrupt this */
> -		err = wait_event_killable(req->waitq,
> -					test_bit(FR_FINISHED, &req->flags));
> +		block_sigs(&oldset);
> +		err = wait_fatal_freezable(req->waitq,
> +				test_bit(FR_FINISHED, &req->flags), false);
> +		restore_sigs(&oldset);
>  		if (!err)
>  			return;
>  
> diff --git a/include/linux/freezer.h b/include/linux/freezer.h
> index dd03e83..2504cd0 100644
> --- a/include/linux/freezer.h
> +++ b/include/linux/freezer.h
> @@ -256,6 +256,22 @@ static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
>  	__retval;							\
>  })
>  
> +#define wait_fatal_freezable(wq, condition, exclusive)			\
> +({									\
> +	int __ret = 0;							\
> +	do {								\
> +		if (exclusive)						\
> +			__ret = wait_event_interruptible_exclusive(wq,	\
> +							condition);	\
> +		else							\
> +			__ret = wait_event_interruptible(wq,		\
> +							condition);	\
> +		if (!__ret || fatal_signal_pending(current))		\
> +			break;						\
> +	} while (try_to_freeze());					\
> +	__ret;								\
> +})
> +
>  #else /* !CONFIG_FREEZER */
>  static inline bool frozen(struct task_struct *p) { return false; }
>  static inline bool freezing(struct task_struct *p) { return false; }
> @@ -296,6 +312,16 @@ static inline void set_freezable(void) {}
>  #define wait_event_freezekillable_unsafe(wq, condition)			\
>  		wait_event_killable(wq, condition)
>  
> +#define wait_fatal_freezable(wq, condition, exclusive)			\
> +({									\
> +	int __ret = 0;							\
> +	if (exclusive)							\
> +		__ret = wait_event_killable_exclusive(wq, condition);	\
> +	else								\
> +		__ret = wait_event_killable(wq,	condition);		\
> +	__ret;								\
> +})
> +
>  #endif /* !CONFIG_FREEZER */
>  
>  #endif	/* FREEZER_H_INCLUDED */
> 

Thanks,
Rafael

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

* 答复: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().
  2016-12-06 22:15 ` Rafael J. Wysocki
@ 2016-12-08  6:31   ` 崔立飞
  2016-12-14 10:09     ` 崔立飞
  2016-12-16  1:34     ` 崔立飞
  0 siblings, 2 replies; 14+ messages in thread
From: 崔立飞 @ 2016-12-08  6:31 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-kernel, miklos, pavel, len.brown, linux-fsdevel, viro,
	朴英敏, 刘才,
	Jiri Kosina, 崔立飞

Hi Rafael,

The fuse we used is without the commit "fuse: don't mess with blocking signals" committed by Al Viro.
So we find the issue SIGBUS. In the page fault, trying to read page in fuse is interrupted,
which will lead to SIGBUS issue.

All Android platforms, include Android N, have the SIGUBS issue. All the SIGBUS issues are produced
in the freezing process.

In our Android platform, the root-cause of SIGBUS is :
suspend procedure will set the signal pending flag(TIF_SIGPENDING) and then wake up the task
which is TASK_INTERRUPTIBLE status . The request_wait_answer, which calls wait_event_interruptible,
is interrupted and the fuse request is still in pending status, which leads to SIGBUS sent to caller.

This issue can be reproduced by adding delays in funciton handle_read,
which is in the Android sdcard daemon process.

So we merge the commit "fuse: don't mess with blocking signals", which just use wait_event_killable{,_exclusive}().
It fix the SIGBUS issue. But the freezing will fail, because the freezing procedure cannot wake up the task which
is in TASK_KILLABLE(TASK_WAKEKILL | TASK_UNINTERRUPTIBLE) status. And the suspend procedure will abort
until the time is out.

In this patch, we try to fix the issue mentioned above.
> ---
>   fs/fuse/dev.c           | 30 ++++++++++++++++++++++++++----
>   include/linux/freezer.h | 26 ++++++++++++++++++++++++++
>   2 files changed, 52 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 70ea57c..e33a081 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -19,6 +19,7 @@
>   #include <linux/pipe_fs_i.h>
>   #include <linux/swap.h>
>   #include <linux/splice.h>
> +#include <linux/freezer.h>
>   
>   MODULE_ALIAS_MISCDEV(FUSE_MINOR);
>   MODULE_ALIAS("devname:fuse");
> @@ -99,6 +100,19 @@ void fuse_request_free(struct fuse_req *req)
>         kmem_cache_free(fuse_req_cachep, req);
>   }
>   
> +static void block_sigs(sigset_t *oldset)
> +{
> +     sigset_t mask;
> +
> +     siginitsetinv(&mask, sigmask(SIGKILL));
> +     sigprocmask(SIG_BLOCK, &mask, oldset);
> +}
> +
> +static void restore_sigs(sigset_t *oldset)
> +{
> +     sigprocmask(SIG_SETMASK, oldset, NULL);
> +}
> +
>   void __fuse_get_request(struct fuse_req *req)
>   {
>         atomic_inc(&req->count);
> @@ -134,13 +148,18 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
>                                        bool for_background)
>   {
>         struct fuse_req *req;
> +     sigset_t oldset;
> +     int intr;
>         int err;
>         atomic_inc(&fc->num_waiting);
>   
>         if (fuse_block_alloc(fc, for_background)) {
>                 err = -EINTR;
> -             if (wait_event_killable_exclusive(fc->blocked_waitq,
> -                             !fuse_block_alloc(fc, for_background)))
> +             block_sigs(&oldset);
> +             intr = wait_fatal_freezable(fc->blocked_waitq,
> +                             !fuse_block_alloc(fc, for_background), true);
> +             restore_sigs(&oldset);
> +             if (intr)
>                         goto out;
>         }
>         /* Matches smp_wmb() in fuse_set_initialized() */
> @@ -427,9 +446,12 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
>         }
>   
>         if (!test_bit(FR_FORCE, &req->flags)) {
> +             sigset_t oldset;
>                 /* Only fatal signals may interrupt this */
> -             err = wait_event_killable(req->waitq,
> -                                     test_bit(FR_FINISHED, &req->flags));
> +             block_sigs(&oldset);
> +             err = wait_fatal_freezable(req->waitq,
> +                             test_bit(FR_FINISHED, &req->flags), false);
> +             restore_sigs(&oldset);
>                 if (!err)
>                         return;
>   
> diff --git a/include/linux/freezer.h b/include/linux/freezer.h
> index dd03e83..2504cd0 100644
> --- a/include/linux/freezer.h
> +++ b/include/linux/freezer.h
> @@ -256,6 +256,22 @@ static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
>         __retval;                                                       \
>   })
>   
> +#define wait_fatal_freezable(wq, condition, exclusive)                       \
> +({                                                                   \
> +     int __ret = 0;                                                  \
> +     do {                                                            \
> +             if (exclusive)                                          \
> +                     __ret = wait_event_interruptible_exclusive(wq,  \    //set the TASK_INTERRUPTIBLE
> +                                                     condition);     \                           //can be waked up by suspend procedure
> +             else                                                    \
> +                     __ret = wait_event_interruptible(wq,            \
> +                                                     condition);     \
> +             if (!__ret || fatal_signal_pending(current))            \           //check condition or there is fatal signal
> +                     break;                                          \                            //if true, wait finish
> +     } while (try_to_freeze());                                      \                   //if freezing is in effect, try to freeze the task
> +     __ret;                                                          \
> +})
> +
>   #else /* !CONFIG_FREEZER */
>   static inline bool frozen(struct task_struct *p) { return false; }
>   static inline bool freezing(struct task_struct *p) { return false; }
> @@ -296,6 +312,16 @@ static inline void set_freezable(void) {}
>   #define wait_event_freezekillable_unsafe(wq, condition)                      \
>                 wait_event_killable(wq, condition)
>   
> +#define wait_fatal_freezable(wq, condition, exclusive)                       \
> +({                                                                   \
> +     int __ret = 0;                                                  \
> +     if (exclusive)                                                  \
> +             __ret = wait_event_killable_exclusive(wq, condition);   \
> +     else                                                            \
> +             __ret = wait_event_killable(wq, condition);             \
> +     __ret;                                                          \
> +})
> +
>   #endif /* !CONFIG_FREEZER */
>   
>   #endif       /* FREEZER_H_INCLUDED */
> 
Thanks.

BR,
________________________________________
发件人: Rafael J. Wysocki <rjw@rjwysocki.net>
发送时间: 2016年12月7日 6:15
收件人: 崔立飞
抄送: linux-kernel@vger.kernel.org; miklos@szeredi.hu; pavel@ucw.cz; len.brown@intel.com; linux-fsdevel@vger.kernel.org; viro@zeniv.linux.org.uk; 朴英敏; 刘才; Jiri Kosina
主题: Re: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().

On Monday, December 05, 2016 11:19:45 AM cuilifei wrote:
> Freezing process can abort when a client is waiting uninterruptibly
> for a response. Add new macro wait_fatal_freezable to try to fix it.
>
> Signed-off-by: cuilifei <cuilifei@xiaomi.com>

I'm not a big fan of this to be honest.

Do we really want to suspend the system (or freeze tasks for other reasons)
if that happens?

> ---
>  fs/fuse/dev.c           | 30 ++++++++++++++++++++++++++----
>  include/linux/freezer.h | 26 ++++++++++++++++++++++++++
>  2 files changed, 52 insertions(+), 4 deletions(-)
>
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 70ea57c..e33a081 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -19,6 +19,7 @@
>  #include <linux/pipe_fs_i.h>
>  #include <linux/swap.h>
>  #include <linux/splice.h>
> +#include <linux/freezer.h>
>
>  MODULE_ALIAS_MISCDEV(FUSE_MINOR);
>  MODULE_ALIAS("devname:fuse");
> @@ -99,6 +100,19 @@ void fuse_request_free(struct fuse_req *req)
>       kmem_cache_free(fuse_req_cachep, req);
>  }
>
> +static void block_sigs(sigset_t *oldset)
> +{
> +     sigset_t mask;
> +
> +     siginitsetinv(&mask, sigmask(SIGKILL));
> +     sigprocmask(SIG_BLOCK, &mask, oldset);
> +}
> +
> +static void restore_sigs(sigset_t *oldset)
> +{
> +     sigprocmask(SIG_SETMASK, oldset, NULL);
> +}
> +
>  void __fuse_get_request(struct fuse_req *req)
>  {
>       atomic_inc(&req->count);
> @@ -134,13 +148,18 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
>                                      bool for_background)
>  {
>       struct fuse_req *req;
> +     sigset_t oldset;
> +     int intr;
>       int err;
>       atomic_inc(&fc->num_waiting);
>
>       if (fuse_block_alloc(fc, for_background)) {
>               err = -EINTR;
> -             if (wait_event_killable_exclusive(fc->blocked_waitq,
> -                             !fuse_block_alloc(fc, for_background)))
> +             block_sigs(&oldset);
> +             intr = wait_fatal_freezable(fc->blocked_waitq,
> +                             !fuse_block_alloc(fc, for_background), true);
> +             restore_sigs(&oldset);
> +             if (intr)
>                       goto out;
>       }
>       /* Matches smp_wmb() in fuse_set_initialized() */
> @@ -427,9 +446,12 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
>       }
>
>       if (!test_bit(FR_FORCE, &req->flags)) {
> +             sigset_t oldset;
>               /* Only fatal signals may interrupt this */
> -             err = wait_event_killable(req->waitq,
> -                                     test_bit(FR_FINISHED, &req->flags));
> +             block_sigs(&oldset);
> +             err = wait_fatal_freezable(req->waitq,
> +                             test_bit(FR_FINISHED, &req->flags), false);
> +             restore_sigs(&oldset);
>               if (!err)
>                       return;
>
> diff --git a/include/linux/freezer.h b/include/linux/freezer.h
> index dd03e83..2504cd0 100644
> --- a/include/linux/freezer.h
> +++ b/include/linux/freezer.h
> @@ -256,6 +256,22 @@ static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
>       __retval;                                                       \
>  })
>
> +#define wait_fatal_freezable(wq, condition, exclusive)                       \
> +({                                                                   \
> +     int __ret = 0;                                                  \
> +     do {                                                            \
> +             if (exclusive)                                          \
> +                     __ret = wait_event_interruptible_exclusive(wq,  \
> +                                                     condition);     \
> +             else                                                    \
> +                     __ret = wait_event_interruptible(wq,            \
> +                                                     condition);     \
> +             if (!__ret || fatal_signal_pending(current))            \
> +                     break;                                          \
> +     } while (try_to_freeze());                                      \
> +     __ret;                                                          \
> +})
> +
>  #else /* !CONFIG_FREEZER */
>  static inline bool frozen(struct task_struct *p) { return false; }
>  static inline bool freezing(struct task_struct *p) { return false; }
> @@ -296,6 +312,16 @@ static inline void set_freezable(void) {}
>  #define wait_event_freezekillable_unsafe(wq, condition)                      \
>               wait_event_killable(wq, condition)
>
> +#define wait_fatal_freezable(wq, condition, exclusive)                       \
> +({                                                                   \
> +     int __ret = 0;                                                  \
> +     if (exclusive)                                                  \
> +             __ret = wait_event_killable_exclusive(wq, condition);   \
> +     else                                                            \
> +             __ret = wait_event_killable(wq, condition);             \
> +     __ret;                                                          \
> +})
> +
>  #endif /* !CONFIG_FREEZER */
>
>  #endif       /* FREEZER_H_INCLUDED */
>

Thanks,
Rafael

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

* 答复: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().
  2016-12-08  6:31   ` 答复: " 崔立飞
@ 2016-12-14 10:09     ` 崔立飞
  2016-12-15 22:40       ` Rafael J. Wysocki
  2016-12-16  1:34     ` 崔立飞
  1 sibling, 1 reply; 14+ messages in thread
From: 崔立飞 @ 2016-12-14 10:09 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-kernel, miklos, pavel, len.brown, linux-fsdevel, viro,
	朴英敏, 刘才,
	Jiri Kosina

Rafael,

Any questions about the patch, please let me know.

Thanks!

BR,
Cui Li Fei
________________________________________
发件人: 崔立飞
发送时间: 2016年12月8日 14:31
收件人: Rafael J. Wysocki
抄送: linux-kernel@vger.kernel.org; miklos@szeredi.hu; pavel@ucw.cz; len.brown@intel.com; linux-fsdevel@vger.kernel.org; viro@zeniv.linux.org.uk; 朴英敏; 刘才; Jiri Kosina; 崔立飞
主题: 答复: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().

Hi Rafael,

The fuse we used is without the commit "fuse: don't mess with blocking signals" committed by Al Viro.
So we find the issue SIGBUS. In the page fault, trying to read page in fuse is interrupted,
which will lead to SIGBUS issue.

All Android platforms, include Android N, have the SIGUBS issue. All the SIGBUS issues are produced
in the freezing process.

In our Android platform, the root-cause of SIGBUS is :
suspend procedure will set the signal pending flag(TIF_SIGPENDING) and then wake up the task
which is TASK_INTERRUPTIBLE status . The request_wait_answer, which calls wait_event_interruptible,
is interrupted and the fuse request is still in pending status, which leads to SIGBUS sent to caller.

This issue can be reproduced by adding delays in funciton handle_read,
which is in the Android sdcard daemon process.

So we merge the commit "fuse: don't mess with blocking signals", which just use wait_event_killable{,_exclusive}().
It fix the SIGBUS issue. But the freezing will fail, because the freezing procedure cannot wake up the task which
is in TASK_KILLABLE(TASK_WAKEKILL | TASK_UNINTERRUPTIBLE) status. And the suspend procedure will abort
until the time is out.

In this patch, we try to fix the issue mentioned above.
> ---
>   fs/fuse/dev.c           | 30 ++++++++++++++++++++++++++----
>   include/linux/freezer.h | 26 ++++++++++++++++++++++++++
>   2 files changed, 52 insertions(+), 4 deletions(-)
>
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 70ea57c..e33a081 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -19,6 +19,7 @@
>   #include <linux/pipe_fs_i.h>
>   #include <linux/swap.h>
>   #include <linux/splice.h>
> +#include <linux/freezer.h>
>  
>   MODULE_ALIAS_MISCDEV(FUSE_MINOR);
>   MODULE_ALIAS("devname:fuse");
> @@ -99,6 +100,19 @@ void fuse_request_free(struct fuse_req *req)
>         kmem_cache_free(fuse_req_cachep, req);
>   }
>  
> +static void block_sigs(sigset_t *oldset)
> +{
> +     sigset_t mask;
> +
> +     siginitsetinv(&mask, sigmask(SIGKILL));
> +     sigprocmask(SIG_BLOCK, &mask, oldset);
> +}
> +
> +static void restore_sigs(sigset_t *oldset)
> +{
> +     sigprocmask(SIG_SETMASK, oldset, NULL);
> +}
> +
>   void __fuse_get_request(struct fuse_req *req)
>   {
>         atomic_inc(&req->count);
> @@ -134,13 +148,18 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
>                                        bool for_background)
>   {
>         struct fuse_req *req;
> +     sigset_t oldset;
> +     int intr;
>         int err;
>         atomic_inc(&fc->num_waiting);
>  
>         if (fuse_block_alloc(fc, for_background)) {
>                 err = -EINTR;
> -             if (wait_event_killable_exclusive(fc->blocked_waitq,
> -                             !fuse_block_alloc(fc, for_background)))
> +             block_sigs(&oldset);
> +             intr = wait_fatal_freezable(fc->blocked_waitq,
> +                             !fuse_block_alloc(fc, for_background), true);
> +             restore_sigs(&oldset);
> +             if (intr)
>                         goto out;
>         }
>         /* Matches smp_wmb() in fuse_set_initialized() */
> @@ -427,9 +446,12 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
>         }
>  
>         if (!test_bit(FR_FORCE, &req->flags)) {
> +             sigset_t oldset;
>                 /* Only fatal signals may interrupt this */
> -             err = wait_event_killable(req->waitq,
> -                                     test_bit(FR_FINISHED, &req->flags));
> +             block_sigs(&oldset);
> +             err = wait_fatal_freezable(req->waitq,
> +                             test_bit(FR_FINISHED, &req->flags), false);
> +             restore_sigs(&oldset);
>                 if (!err)
>                         return;
>  
> diff --git a/include/linux/freezer.h b/include/linux/freezer.h
> index dd03e83..2504cd0 100644
> --- a/include/linux/freezer.h
> +++ b/include/linux/freezer.h
> @@ -256,6 +256,22 @@ static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
>         __retval;                                                       \
>   })
>  
> +#define wait_fatal_freezable(wq, condition, exclusive)                       \
> +({                                                                   \
> +     int __ret = 0;                                                  \
> +     do {                                                            \
> +             if (exclusive)                                          \
> +                     __ret = wait_event_interruptible_exclusive(wq,  \    //set the TASK_INTERRUPTIBLE
> +                                                     condition);     \                           //can be waked up by suspend procedure
> +             else                                                    \
> +                     __ret = wait_event_interruptible(wq,            \
> +                                                     condition);     \
> +             if (!__ret || fatal_signal_pending(current))            \           //check condition or there is fatal signal
> +                     break;                                          \                            //if true, wait finish
> +     } while (try_to_freeze());                                      \                   //if freezing is in effect, try to freeze the task
> +     __ret;                                                          \
> +})
> +
>   #else /* !CONFIG_FREEZER */
>   static inline bool frozen(struct task_struct *p) { return false; }
>   static inline bool freezing(struct task_struct *p) { return false; }
> @@ -296,6 +312,16 @@ static inline void set_freezable(void) {}
>   #define wait_event_freezekillable_unsafe(wq, condition)                      \
>                 wait_event_killable(wq, condition)
>  
> +#define wait_fatal_freezable(wq, condition, exclusive)                       \
> +({                                                                   \
> +     int __ret = 0;                                                  \
> +     if (exclusive)                                                  \
> +             __ret = wait_event_killable_exclusive(wq, condition);   \
> +     else                                                            \
> +             __ret = wait_event_killable(wq, condition);             \
> +     __ret;                                                          \
> +})
> +
>   #endif /* !CONFIG_FREEZER */
>  
>   #endif       /* FREEZER_H_INCLUDED */
>
Thanks.

BR,
________________________________________
发件人: Rafael J. Wysocki <rjw@rjwysocki.net>
发送时间: 2016年12月7日 6:15
收件人: 崔立飞
抄送: linux-kernel@vger.kernel.org; miklos@szeredi.hu; pavel@ucw.cz; len.brown@intel.com; linux-fsdevel@vger.kernel.org; viro@zeniv.linux.org.uk; 朴英敏; 刘才; Jiri Kosina
主题: Re: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().

On Monday, December 05, 2016 11:19:45 AM cuilifei wrote:
> Freezing process can abort when a client is waiting uninterruptibly
> for a response. Add new macro wait_fatal_freezable to try to fix it.
>
> Signed-off-by: cuilifei <cuilifei@xiaomi.com>

I'm not a big fan of this to be honest.

Do we really want to suspend the system (or freeze tasks for other reasons)
if that happens?

> ---
>  fs/fuse/dev.c           | 30 ++++++++++++++++++++++++++----
>  include/linux/freezer.h | 26 ++++++++++++++++++++++++++
>  2 files changed, 52 insertions(+), 4 deletions(-)
>
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 70ea57c..e33a081 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -19,6 +19,7 @@
>  #include <linux/pipe_fs_i.h>
>  #include <linux/swap.h>
>  #include <linux/splice.h>
> +#include <linux/freezer.h>
>
>  MODULE_ALIAS_MISCDEV(FUSE_MINOR);
>  MODULE_ALIAS("devname:fuse");
> @@ -99,6 +100,19 @@ void fuse_request_free(struct fuse_req *req)
>       kmem_cache_free(fuse_req_cachep, req);
>  }
>
> +static void block_sigs(sigset_t *oldset)
> +{
> +     sigset_t mask;
> +
> +     siginitsetinv(&mask, sigmask(SIGKILL));
> +     sigprocmask(SIG_BLOCK, &mask, oldset);
> +}
> +
> +static void restore_sigs(sigset_t *oldset)
> +{
> +     sigprocmask(SIG_SETMASK, oldset, NULL);
> +}
> +
>  void __fuse_get_request(struct fuse_req *req)
>  {
>       atomic_inc(&req->count);
> @@ -134,13 +148,18 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
>                                      bool for_background)
>  {
>       struct fuse_req *req;
> +     sigset_t oldset;
> +     int intr;
>       int err;
>       atomic_inc(&fc->num_waiting);
>
>       if (fuse_block_alloc(fc, for_background)) {
>               err = -EINTR;
> -             if (wait_event_killable_exclusive(fc->blocked_waitq,
> -                             !fuse_block_alloc(fc, for_background)))
> +             block_sigs(&oldset);
> +             intr = wait_fatal_freezable(fc->blocked_waitq,
> +                             !fuse_block_alloc(fc, for_background), true);
> +             restore_sigs(&oldset);
> +             if (intr)
>                       goto out;
>       }
>       /* Matches smp_wmb() in fuse_set_initialized() */
> @@ -427,9 +446,12 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
>       }
>
>       if (!test_bit(FR_FORCE, &req->flags)) {
> +             sigset_t oldset;
>               /* Only fatal signals may interrupt this */
> -             err = wait_event_killable(req->waitq,
> -                                     test_bit(FR_FINISHED, &req->flags));
> +             block_sigs(&oldset);
> +             err = wait_fatal_freezable(req->waitq,
> +                             test_bit(FR_FINISHED, &req->flags), false);
> +             restore_sigs(&oldset);
>               if (!err)
>                       return;
>
> diff --git a/include/linux/freezer.h b/include/linux/freezer.h
> index dd03e83..2504cd0 100644
> --- a/include/linux/freezer.h
> +++ b/include/linux/freezer.h
> @@ -256,6 +256,22 @@ static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
>       __retval;                                                       \
>  })
>
> +#define wait_fatal_freezable(wq, condition, exclusive)                       \
> +({                                                                   \
> +     int __ret = 0;                                                  \
> +     do {                                                            \
> +             if (exclusive)                                          \
> +                     __ret = wait_event_interruptible_exclusive(wq,  \
> +                                                     condition);     \
> +             else                                                    \
> +                     __ret = wait_event_interruptible(wq,            \
> +                                                     condition);     \
> +             if (!__ret || fatal_signal_pending(current))            \
> +                     break;                                          \
> +     } while (try_to_freeze());                                      \
> +     __ret;                                                          \
> +})
> +
>  #else /* !CONFIG_FREEZER */
>  static inline bool frozen(struct task_struct *p) { return false; }
>  static inline bool freezing(struct task_struct *p) { return false; }
> @@ -296,6 +312,16 @@ static inline void set_freezable(void) {}
>  #define wait_event_freezekillable_unsafe(wq, condition)                      \
>               wait_event_killable(wq, condition)
>
> +#define wait_fatal_freezable(wq, condition, exclusive)                       \
> +({                                                                   \
> +     int __ret = 0;                                                  \
> +     if (exclusive)                                                  \
> +             __ret = wait_event_killable_exclusive(wq, condition);   \
> +     else                                                            \
> +             __ret = wait_event_killable(wq, condition);             \
> +     __ret;                                                          \
> +})
> +
>  #endif /* !CONFIG_FREEZER */
>
>  #endif       /* FREEZER_H_INCLUDED */
>

Thanks,
Rafael

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

* Re: 答复: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().
  2016-12-14 10:09     ` 崔立飞
@ 2016-12-15 22:40       ` Rafael J. Wysocki
  0 siblings, 0 replies; 14+ messages in thread
From: Rafael J. Wysocki @ 2016-12-15 22:40 UTC (permalink / raw)
  To: 崔立飞
  Cc: linux-kernel, miklos, pavel, len.brown, linux-fsdevel, viro,
	朴英敏, 刘才,
	Jiri Kosina

On Wednesday, December 14, 2016 10:09:25 AM 崔立飞 wrote:
> Rafael,
> 
> Any questions about the patch, please let me know.

To be honest, I don't particularly like it, but I wonder what FUSE maintainers
think about it.

Thanks,
Rafael

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

* 答复: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().
  2016-12-08  6:31   ` 答复: " 崔立飞
  2016-12-14 10:09     ` 崔立飞
@ 2016-12-16  1:34     ` 崔立飞
  1 sibling, 0 replies; 14+ messages in thread
From: 崔立飞 @ 2016-12-16  1:34 UTC (permalink / raw)
  To: miklos
  Cc: linux-kernel, pavel, len.brown, linux-fsdevel, viro,
	朴英敏, 刘才,
	Jiri Kosina, rjw

Hi Miklos,

Please help to review the patch.
Thanks.

________________________________________
发件人: 崔立飞
发送时间: 2016年12月8日 14:31
收件人: Rafael J. Wysocki
抄送: linux-kernel@vger.kernel.org; miklos@szeredi.hu; pavel@ucw.cz; len.brown@intel.com; linux-fsdevel@vger.kernel.org; viro@zeniv.linux.org.uk; 朴英敏; 刘才; Jiri Kosina; 崔立飞
主题: 答复: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().

Hi Rafael,

The fuse we used is without the commit "fuse: don't mess with blocking signals" committed by Al Viro.
So we find the issue SIGBUS. In the page fault, trying to read page in fuse is interrupted,
which will lead to SIGBUS issue.

All Android platforms, include Android N, have the SIGUBS issue. All the SIGBUS issues are produced
in the freezing process.

In our Android platform, the root-cause of SIGBUS is :
suspend procedure will set the signal pending flag(TIF_SIGPENDING) and then wake up the task
which is TASK_INTERRUPTIBLE status . The request_wait_answer, which calls wait_event_interruptible,
is interrupted and the fuse request is still in pending status, which leads to SIGBUS sent to caller.

This issue can be reproduced by adding delays in funciton handle_read,
which is in the Android sdcard daemon process.

So we merge the commit "fuse: don't mess with blocking signals", which just use wait_event_killable{,_exclusive}().
It fix the SIGBUS issue. But the freezing will fail, because the freezing procedure cannot wake up the task which
is in TASK_KILLABLE(TASK_WAKEKILL | TASK_UNINTERRUPTIBLE) status. And the suspend procedure will abort
until the time is out.

In this patch, we try to fix the issue mentioned above.
> ---
>   fs/fuse/dev.c           | 30 ++++++++++++++++++++++++++----
>   include/linux/freezer.h | 26 ++++++++++++++++++++++++++
>   2 files changed, 52 insertions(+), 4 deletions(-)
>
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 70ea57c..e33a081 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -19,6 +19,7 @@
>   #include <linux/pipe_fs_i.h>
>   #include <linux/swap.h>
>   #include <linux/splice.h>
> +#include <linux/freezer.h>
>  
>   MODULE_ALIAS_MISCDEV(FUSE_MINOR);
>   MODULE_ALIAS("devname:fuse");
> @@ -99,6 +100,19 @@ void fuse_request_free(struct fuse_req *req)
>         kmem_cache_free(fuse_req_cachep, req);
>   }
>  
> +static void block_sigs(sigset_t *oldset)
> +{
> +     sigset_t mask;
> +
> +     siginitsetinv(&mask, sigmask(SIGKILL));
> +     sigprocmask(SIG_BLOCK, &mask, oldset);
> +}
> +
> +static void restore_sigs(sigset_t *oldset)
> +{
> +     sigprocmask(SIG_SETMASK, oldset, NULL);
> +}
> +
>   void __fuse_get_request(struct fuse_req *req)
>   {
>         atomic_inc(&req->count);
> @@ -134,13 +148,18 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
>                                        bool for_background)
>   {
>         struct fuse_req *req;
> +     sigset_t oldset;
> +     int intr;
>         int err;
>         atomic_inc(&fc->num_waiting);
>  
>         if (fuse_block_alloc(fc, for_background)) {
>                 err = -EINTR;
> -             if (wait_event_killable_exclusive(fc->blocked_waitq,
> -                             !fuse_block_alloc(fc, for_background)))
> +             block_sigs(&oldset);
> +             intr = wait_fatal_freezable(fc->blocked_waitq,
> +                             !fuse_block_alloc(fc, for_background), true);
> +             restore_sigs(&oldset);
> +             if (intr)
>                         goto out;
>         }
>         /* Matches smp_wmb() in fuse_set_initialized() */
> @@ -427,9 +446,12 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
>         }
>  
>         if (!test_bit(FR_FORCE, &req->flags)) {
> +             sigset_t oldset;
>                 /* Only fatal signals may interrupt this */
> -             err = wait_event_killable(req->waitq,
> -                                     test_bit(FR_FINISHED, &req->flags));
> +             block_sigs(&oldset);
> +             err = wait_fatal_freezable(req->waitq,
> +                             test_bit(FR_FINISHED, &req->flags), false);
> +             restore_sigs(&oldset);
>                 if (!err)
>                         return;
>  
> diff --git a/include/linux/freezer.h b/include/linux/freezer.h
> index dd03e83..2504cd0 100644
> --- a/include/linux/freezer.h
> +++ b/include/linux/freezer.h
> @@ -256,6 +256,22 @@ static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
>         __retval;                                                       \
>   })
>  
> +#define wait_fatal_freezable(wq, condition, exclusive)                       \
> +({                                                                   \
> +     int __ret = 0;                                                  \
> +     do {                                                            \
> +             if (exclusive)                                          \
> +                     __ret = wait_event_interruptible_exclusive(wq,  \    //set the TASK_INTERRUPTIBLE
> +                                                     condition);     \                           //can be waked up by suspend procedure
> +             else                                                    \
> +                     __ret = wait_event_interruptible(wq,            \
> +                                                     condition);     \
> +             if (!__ret || fatal_signal_pending(current))            \           //check condition or there is fatal signal
> +                     break;                                          \                            //if true, wait finish
> +     } while (try_to_freeze());                                      \                   //if freezing is in effect, try to freeze the task
> +     __ret;                                                          \
> +})
> +
>   #else /* !CONFIG_FREEZER */
>   static inline bool frozen(struct task_struct *p) { return false; }
>   static inline bool freezing(struct task_struct *p) { return false; }
> @@ -296,6 +312,16 @@ static inline void set_freezable(void) {}
>   #define wait_event_freezekillable_unsafe(wq, condition)                      \
>                 wait_event_killable(wq, condition)
>  
> +#define wait_fatal_freezable(wq, condition, exclusive)                       \
> +({                                                                   \
> +     int __ret = 0;                                                  \
> +     if (exclusive)                                                  \
> +             __ret = wait_event_killable_exclusive(wq, condition);   \
> +     else                                                            \
> +             __ret = wait_event_killable(wq, condition);             \
> +     __ret;                                                          \
> +})
> +
>   #endif /* !CONFIG_FREEZER */
>  
>   #endif       /* FREEZER_H_INCLUDED */
>
Thanks.

BR,
________________________________________
发件人: Rafael J. Wysocki <rjw@rjwysocki.net>
发送时间: 2016年12月7日 6:15
收件人: 崔立飞
抄送: linux-kernel@vger.kernel.org; miklos@szeredi.hu; pavel@ucw.cz; len.brown@intel.com; linux-fsdevel@vger.kernel.org; viro@zeniv.linux.org.uk; 朴英敏; 刘才; Jiri Kosina
主题: Re: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().

On Monday, December 05, 2016 11:19:45 AM cuilifei wrote:
> Freezing process can abort when a client is waiting uninterruptibly
> for a response. Add new macro wait_fatal_freezable to try to fix it.
>
> Signed-off-by: cuilifei <cuilifei@xiaomi.com>

I'm not a big fan of this to be honest.

Do we really want to suspend the system (or freeze tasks for other reasons)
if that happens?

> ---
>  fs/fuse/dev.c           | 30 ++++++++++++++++++++++++++----
>  include/linux/freezer.h | 26 ++++++++++++++++++++++++++
>  2 files changed, 52 insertions(+), 4 deletions(-)
>
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 70ea57c..e33a081 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -19,6 +19,7 @@
>  #include <linux/pipe_fs_i.h>
>  #include <linux/swap.h>
>  #include <linux/splice.h>
> +#include <linux/freezer.h>
>
>  MODULE_ALIAS_MISCDEV(FUSE_MINOR);
>  MODULE_ALIAS("devname:fuse");
> @@ -99,6 +100,19 @@ void fuse_request_free(struct fuse_req *req)
>       kmem_cache_free(fuse_req_cachep, req);
>  }
>
> +static void block_sigs(sigset_t *oldset)
> +{
> +     sigset_t mask;
> +
> +     siginitsetinv(&mask, sigmask(SIGKILL));
> +     sigprocmask(SIG_BLOCK, &mask, oldset);
> +}
> +
> +static void restore_sigs(sigset_t *oldset)
> +{
> +     sigprocmask(SIG_SETMASK, oldset, NULL);
> +}
> +
>  void __fuse_get_request(struct fuse_req *req)
>  {
>       atomic_inc(&req->count);
> @@ -134,13 +148,18 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
>                                      bool for_background)
>  {
>       struct fuse_req *req;
> +     sigset_t oldset;
> +     int intr;
>       int err;
>       atomic_inc(&fc->num_waiting);
>
>       if (fuse_block_alloc(fc, for_background)) {
>               err = -EINTR;
> -             if (wait_event_killable_exclusive(fc->blocked_waitq,
> -                             !fuse_block_alloc(fc, for_background)))
> +             block_sigs(&oldset);
> +             intr = wait_fatal_freezable(fc->blocked_waitq,
> +                             !fuse_block_alloc(fc, for_background), true);
> +             restore_sigs(&oldset);
> +             if (intr)
>                       goto out;
>       }
>       /* Matches smp_wmb() in fuse_set_initialized() */
> @@ -427,9 +446,12 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
>       }
>
>       if (!test_bit(FR_FORCE, &req->flags)) {
> +             sigset_t oldset;
>               /* Only fatal signals may interrupt this */
> -             err = wait_event_killable(req->waitq,
> -                                     test_bit(FR_FINISHED, &req->flags));
> +             block_sigs(&oldset);
> +             err = wait_fatal_freezable(req->waitq,
> +                             test_bit(FR_FINISHED, &req->flags), false);
> +             restore_sigs(&oldset);
>               if (!err)
>                       return;
>
> diff --git a/include/linux/freezer.h b/include/linux/freezer.h
> index dd03e83..2504cd0 100644
> --- a/include/linux/freezer.h
> +++ b/include/linux/freezer.h
> @@ -256,6 +256,22 @@ static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
>       __retval;                                                       \
>  })
>
> +#define wait_fatal_freezable(wq, condition, exclusive)                       \
> +({                                                                   \
> +     int __ret = 0;                                                  \
> +     do {                                                            \
> +             if (exclusive)                                          \
> +                     __ret = wait_event_interruptible_exclusive(wq,  \
> +                                                     condition);     \
> +             else                                                    \
> +                     __ret = wait_event_interruptible(wq,            \
> +                                                     condition);     \
> +             if (!__ret || fatal_signal_pending(current))            \
> +                     break;                                          \
> +     } while (try_to_freeze());                                      \
> +     __ret;                                                          \
> +})
> +
>  #else /* !CONFIG_FREEZER */
>  static inline bool frozen(struct task_struct *p) { return false; }
>  static inline bool freezing(struct task_struct *p) { return false; }
> @@ -296,6 +312,16 @@ static inline void set_freezable(void) {}
>  #define wait_event_freezekillable_unsafe(wq, condition)                      \
>               wait_event_killable(wq, condition)
>
> +#define wait_fatal_freezable(wq, condition, exclusive)                       \
> +({                                                                   \
> +     int __ret = 0;                                                  \
> +     if (exclusive)                                                  \
> +             __ret = wait_event_killable_exclusive(wq, condition);   \
> +     else                                                            \
> +             __ret = wait_event_killable(wq, condition);             \
> +     __ret;                                                          \
> +})
> +
>  #endif /* !CONFIG_FREEZER */
>
>  #endif       /* FREEZER_H_INCLUDED */
>

Thanks,
Rafael

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

* Re: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().
  2016-12-02  7:26 cuilifei
@ 2016-12-03  8:54 ` kbuild test robot
  0 siblings, 0 replies; 14+ messages in thread
From: kbuild test robot @ 2016-12-03  8:54 UTC (permalink / raw)
  To: cuilifei; +Cc: kbuild-all, linux-kernel, miklos, cuilifei

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

Hi cuilifei,

[auto build test ERROR on fuse/for-next]
[also build test ERROR on v4.9-rc7 next-20161202]
[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/cuilifei/fuse-freezing-abort-when-use-wait_event_killable-_exclusive/20161203-120253
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git for-next
config: x86_64-rhel-7.2 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   fs/fuse/dev.c: In function '__fuse_get_req':
>> fs/fuse/dev.c:38:11: error: implicit declaration of function 'try_to_freeze' [-Werror=implicit-function-declaration]
     } while (try_to_freeze());     \
              ^
   fs/fuse/dev.c:174:10: note: in expansion of macro 'wait_fatal_freezable'
      intr = wait_fatal_freezable(fc->blocked_waitq,
             ^~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/try_to_freeze +38 fs/fuse/dev.c

    32								condition);	\
    33			else							\
    34				__ret = wait_event_interruptible(wq,		\
    35								condition);	\
    36			if (!__ret || fatal_signal_pending(current))		\
    37				break;						\
  > 38		} while (try_to_freeze());					\
    39		__ret;								\
    40	})
    41	

---
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: 37906 bytes --]

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

* Re: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().
  2016-12-01  5:43 cuilifei
  2016-12-02 16:16 ` kbuild test robot
@ 2016-12-02 18:42 ` kbuild test robot
  1 sibling, 0 replies; 14+ messages in thread
From: kbuild test robot @ 2016-12-02 18:42 UTC (permalink / raw)
  To: cuilifei; +Cc: kbuild-all, linux-kernel, miklos, cuilifei

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

Hi cuilifei,

[auto build test ERROR on fuse/for-next]
[also build test ERROR on v4.9-rc7 next-20161202]
[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/cuilifei/fuse-freezing-abort-when-use-wait_event_killable-_exclusive/20161202-234345
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git for-next
config: x86_64-kexec (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   fs/fuse/dev.c: In function '__fuse_get_req':
>> fs/fuse/dev.c:38:8: error: implicit declaration of function 'freezing' [-Werror=implicit-function-declaration]
      if (!freezing(current))     \
           ^
   fs/fuse/dev.c:176:10: note: in expansion of macro 'wait_fatal_freezable'
      intr = wait_fatal_freezable(fc->blocked_waitq,
             ^~~~~~~~~~~~~~~~~~~~
>> fs/fuse/dev.c:40:11: error: implicit declaration of function 'try_to_freeze' [-Werror=implicit-function-declaration]
     } while (try_to_freeze());     \
              ^
   fs/fuse/dev.c:176:10: note: in expansion of macro 'wait_fatal_freezable'
      intr = wait_fatal_freezable(fc->blocked_waitq,
             ^~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/freezing +38 fs/fuse/dev.c

    32								condition);	\
    33			else							\
    34				__ret = wait_event_interruptible(wq,		\
    35								condition);	\
    36			if (!__ret || fatal_signal_pending(current))		\
    37				break;						\
  > 38			if (!freezing(current))					\
    39				continue;					\
  > 40		} while (try_to_freeze());					\
    41		__ret;								\
    42	})
    43	

---
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: 24266 bytes --]

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

* Re: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().
  2016-12-01  5:43 cuilifei
@ 2016-12-02 16:16 ` kbuild test robot
  2016-12-02 18:42 ` kbuild test robot
  1 sibling, 0 replies; 14+ messages in thread
From: kbuild test robot @ 2016-12-02 16:16 UTC (permalink / raw)
  To: cuilifei; +Cc: kbuild-all, linux-kernel, miklos, cuilifei

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

Hi cuilifei,

[auto build test WARNING on fuse/for-next]
[also build test WARNING on v4.9-rc7 next-20161202]
[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/cuilifei/fuse-freezing-abort-when-use-wait_event_killable-_exclusive/20161202-234345
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git for-next
config: x86_64-randconfig-x013-201648 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All warnings (new ones prefixed by >>):

   In file included from include/uapi/linux/stddef.h:1:0,
                    from include/linux/stddef.h:4,
                    from include/uapi/linux/posix_types.h:4,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/uapi/linux/fuse.h:121,
                    from fs/fuse/fuse_i.h:12,
                    from fs/fuse/dev.c:9:
   fs/fuse/dev.c: In function '__fuse_get_req':
   fs/fuse/dev.c:38:8: error: implicit declaration of function 'freezing' [-Werror=implicit-function-declaration]
      if (!freezing(current))     \
           ^
   include/linux/compiler.h:149:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^~~~
>> fs/fuse/dev.c:38:3: note: in expansion of macro 'if'
      if (!freezing(current))     \
      ^~
   fs/fuse/dev.c:176:10: note: in expansion of macro 'wait_fatal_freezable'
      intr = wait_fatal_freezable(fc->blocked_waitq,
             ^~~~~~~~~~~~~~~~~~~~
   fs/fuse/dev.c:40:11: error: implicit declaration of function 'try_to_freeze' [-Werror=implicit-function-declaration]
     } while (try_to_freeze());     \
              ^
   fs/fuse/dev.c:176:10: note: in expansion of macro 'wait_fatal_freezable'
      intr = wait_fatal_freezable(fc->blocked_waitq,
             ^~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/if +38 fs/fuse/dev.c

     3	  Copyright (C) 2001-2008  Miklos Szeredi <miklos@szeredi.hu>
     4	
     5	  This program can be distributed under the terms of the GNU GPL.
     6	  See the file COPYING.
     7	*/
     8	
   > 9	#include "fuse_i.h"
    10	
    11	#include <linux/init.h>
    12	#include <linux/module.h>
    13	#include <linux/poll.h>
    14	#include <linux/uio.h>
    15	#include <linux/miscdevice.h>
    16	#include <linux/pagemap.h>
    17	#include <linux/file.h>
    18	#include <linux/slab.h>
    19	#include <linux/pipe_fs_i.h>
    20	#include <linux/swap.h>
    21	#include <linux/splice.h>
    22	
    23	MODULE_ALIAS_MISCDEV(FUSE_MINOR);
    24	MODULE_ALIAS("devname:fuse");
    25	
    26	#define wait_fatal_freezable(wq, condition, exclusive)			\
    27	({									\
    28		int __ret = 0;							\
    29		do {								\
    30			if (exclusive)						\
    31				__ret = wait_event_interruptible_exclusive(wq,	\
    32								condition);	\
    33			else							\
    34				__ret = wait_event_interruptible(wq,		\
    35								condition);	\
    36			if (!__ret || fatal_signal_pending(current))		\
    37				break;						\
  > 38			if (!freezing(current))					\
    39				continue;					\
    40		} while (try_to_freeze());					\
    41		__ret;								\

---
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: 18547 bytes --]

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

* Re: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().
  2016-12-01  5:37 cuilifei
  2016-12-02 14:42 ` kbuild test robot
@ 2016-12-02 14:51 ` kbuild test robot
  1 sibling, 0 replies; 14+ messages in thread
From: kbuild test robot @ 2016-12-02 14:51 UTC (permalink / raw)
  To: cuilifei; +Cc: kbuild-all, linux-kernel, miklos, cuilifei

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

Hi cuilifei,

[auto build test WARNING on fuse/for-next]
[also build test WARNING on v4.9-rc7 next-20161202]
[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/cuilifei/fuse-freezing-abort-when-use-wait_event_killable-_exclusive/20161202-221508
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git for-next
config: m68k-sun3_defconfig (attached as .config)
compiler: m68k-linux-gcc (GCC) 4.9.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=m68k 

All warnings (new ones prefixed by >>):

   fs/fuse/dev.c: In function '__fuse_get_req':
   fs/fuse/dev.c:31:4: error: 'ret' undeclared (first use in this function)
       ret = wait_event_interruptible_exclusive(wq, \
       ^
>> fs/fuse/dev.c:175:10: note: in expansion of macro 'wait_fatal_freezable'
      intr = wait_fatal_freezable(fc->blocked_waitq,
             ^
   fs/fuse/dev.c:31:4: note: each undeclared identifier is reported only once for each function it appears in
       ret = wait_event_interruptible_exclusive(wq, \
       ^
>> fs/fuse/dev.c:175:10: note: in expansion of macro 'wait_fatal_freezable'
      intr = wait_fatal_freezable(fc->blocked_waitq,
             ^
   fs/fuse/dev.c:175:3: error: implicit declaration of function 'freezing' [-Werror=implicit-function-declaration]
      intr = wait_fatal_freezable(fc->blocked_waitq,
      ^
   fs/fuse/dev.c:175:3: error: implicit declaration of function 'try_to_freeze' [-Werror=implicit-function-declaration]
   fs/fuse/dev.c: In function 'request_wait_answer':
   fs/fuse/dev.c:31:4: error: 'ret' undeclared (first use in this function)
       ret = wait_event_interruptible_exclusive(wq, \
       ^
   fs/fuse/dev.c:468:9: note: in expansion of macro 'wait_fatal_freezable'
      err = wait_fatal_freezable(req->waitq,
            ^
   cc1: some warnings being treated as errors

vim +/wait_fatal_freezable +175 fs/fuse/dev.c

    25	
    26	#define wait_fatal_freezable(wq, condition, exclusive)			\
    27	({									\
    28		int __ret = 0;							\
    29		do {								\
    30			if (exclusive)						\
  > 31				ret = wait_event_interruptible_exclusive(wq,	\
    32								condition);	\
    33			else							\
    34				ret = wait_event_interruptible(wq, condition);	\
    35			if (!__ret || fatal_signal_pending(current))		\
    36				break;						\
    37			if (!freezing(current))					\
    38				continue;					\
    39		} while (try_to_freeze());					\
    40		__ret;								\
    41	})
    42	
    43	static struct kmem_cache *fuse_req_cachep;
    44	
    45	static struct fuse_dev *fuse_get_dev(struct file *file)
    46	{
    47		/*
    48		 * Lockless access is OK, because file->private data is set
    49		 * once during mount and is valid until the file is released.
    50		 */
    51		return ACCESS_ONCE(file->private_data);
    52	}
    53	
    54	static void fuse_request_init(struct fuse_req *req, struct page **pages,
    55				      struct fuse_page_desc *page_descs,
    56				      unsigned npages)
    57	{
    58		memset(req, 0, sizeof(*req));
    59		memset(pages, 0, sizeof(*pages) * npages);
    60		memset(page_descs, 0, sizeof(*page_descs) * npages);
    61		INIT_LIST_HEAD(&req->list);
    62		INIT_LIST_HEAD(&req->intr_entry);
    63		init_waitqueue_head(&req->waitq);
    64		atomic_set(&req->count, 1);
    65		req->pages = pages;
    66		req->page_descs = page_descs;
    67		req->max_pages = npages;
    68		__set_bit(FR_PENDING, &req->flags);
    69	}
    70	
    71	static struct fuse_req *__fuse_request_alloc(unsigned npages, gfp_t flags)
    72	{
    73		struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, flags);
    74		if (req) {
    75			struct page **pages;
    76			struct fuse_page_desc *page_descs;
    77	
    78			if (npages <= FUSE_REQ_INLINE_PAGES) {
    79				pages = req->inline_pages;
    80				page_descs = req->inline_page_descs;
    81			} else {
    82				pages = kmalloc(sizeof(struct page *) * npages, flags);
    83				page_descs = kmalloc(sizeof(struct fuse_page_desc) *
    84						     npages, flags);
    85			}
    86	
    87			if (!pages || !page_descs) {
    88				kfree(pages);
    89				kfree(page_descs);
    90				kmem_cache_free(fuse_req_cachep, req);
    91				return NULL;
    92			}
    93	
    94			fuse_request_init(req, pages, page_descs, npages);
    95		}
    96		return req;
    97	}
    98	
    99	struct fuse_req *fuse_request_alloc(unsigned npages)
   100	{
   101		return __fuse_request_alloc(npages, GFP_KERNEL);
   102	}
   103	EXPORT_SYMBOL_GPL(fuse_request_alloc);
   104	
   105	struct fuse_req *fuse_request_alloc_nofs(unsigned npages)
   106	{
   107		return __fuse_request_alloc(npages, GFP_NOFS);
   108	}
   109	
   110	void fuse_request_free(struct fuse_req *req)
   111	{
   112		if (req->pages != req->inline_pages) {
   113			kfree(req->pages);
   114			kfree(req->page_descs);
   115		}
   116		kmem_cache_free(fuse_req_cachep, req);
   117	}
   118	
   119	static void block_sigs(sigset_t *oldset)
   120	{
   121		sigset_t mask;
   122	
   123		siginitsetinv(&mask, sigmask(SIGKILL));
   124		sigprocmask(SIG_BLOCK, &mask, oldset);
   125	}
   126	
   127	static void restore_sigs(sigset_t *oldset)
   128	{
   129		sigprocmask(SIG_SETMASK, oldset, NULL);
   130	}
   131	
   132	void __fuse_get_request(struct fuse_req *req)
   133	{
   134		atomic_inc(&req->count);
   135	}
   136	
   137	/* Must be called with > 1 refcount */
   138	static void __fuse_put_request(struct fuse_req *req)
   139	{
   140		BUG_ON(atomic_read(&req->count) < 2);
   141		atomic_dec(&req->count);
   142	}
   143	
   144	static void fuse_req_init_context(struct fuse_req *req)
   145	{
   146		req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid());
   147		req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid());
   148		req->in.h.pid = current->pid;
   149	}
   150	
   151	void fuse_set_initialized(struct fuse_conn *fc)
   152	{
   153		/* Make sure stores before this are seen on another CPU */
   154		smp_wmb();
   155		fc->initialized = 1;
   156	}
   157	
   158	static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background)
   159	{
   160		return !fc->initialized || (for_background && fc->blocked);
   161	}
   162	
   163	static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
   164					       bool for_background)
   165	{
   166		struct fuse_req *req;
   167		sigset_t oldset;
   168		int intr;
   169		int err;
   170		atomic_inc(&fc->num_waiting);
   171	
   172		if (fuse_block_alloc(fc, for_background)) {
   173			err = -EINTR;
   174			block_sigs(&oldset);
 > 175			intr = wait_fatal_freezable(fc->blocked_waitq,
   176					!fuse_block_alloc(fc, for_background), true);
   177			restore_sigs(&oldset);
   178			if (intr)

---
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: 11509 bytes --]

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

* Re: [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().
  2016-12-01  5:37 cuilifei
@ 2016-12-02 14:42 ` kbuild test robot
  2016-12-02 14:51 ` kbuild test robot
  1 sibling, 0 replies; 14+ messages in thread
From: kbuild test robot @ 2016-12-02 14:42 UTC (permalink / raw)
  To: cuilifei; +Cc: kbuild-all, linux-kernel, miklos, cuilifei

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

Hi cuilifei,

[auto build test ERROR on fuse/for-next]
[also build test ERROR on v4.9-rc7 next-20161202]
[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/cuilifei/fuse-freezing-abort-when-use-wait_event_killable-_exclusive/20161202-221508
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git for-next
config: i386-randconfig-i0-201648 (attached as .config)
compiler: gcc-4.8 (Debian 4.8.4-1) 4.8.4
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   fs/fuse/dev.c: In function '__fuse_get_req':
>> fs/fuse/dev.c:31:4: error: 'ret' undeclared (first use in this function)
       ret = wait_event_interruptible_exclusive(wq, \
       ^
   fs/fuse/dev.c:175:10: note: in expansion of macro 'wait_fatal_freezable'
      intr = wait_fatal_freezable(fc->blocked_waitq,
             ^
   fs/fuse/dev.c:31:4: note: each undeclared identifier is reported only once for each function it appears in
       ret = wait_event_interruptible_exclusive(wq, \
       ^
   fs/fuse/dev.c:175:10: note: in expansion of macro 'wait_fatal_freezable'
      intr = wait_fatal_freezable(fc->blocked_waitq,
             ^
>> fs/fuse/dev.c:175:3: error: implicit declaration of function 'freezing' [-Werror=implicit-function-declaration]
      intr = wait_fatal_freezable(fc->blocked_waitq,
      ^
>> fs/fuse/dev.c:175:3: error: implicit declaration of function 'try_to_freeze' [-Werror=implicit-function-declaration]
   fs/fuse/dev.c: In function 'request_wait_answer':
>> fs/fuse/dev.c:31:4: error: 'ret' undeclared (first use in this function)
       ret = wait_event_interruptible_exclusive(wq, \
       ^
   fs/fuse/dev.c:468:9: note: in expansion of macro 'wait_fatal_freezable'
      err = wait_fatal_freezable(req->waitq,
            ^
   cc1: some warnings being treated as errors

vim +/ret +31 fs/fuse/dev.c

    25	
    26	#define wait_fatal_freezable(wq, condition, exclusive)			\
    27	({									\
    28		int __ret = 0;							\
    29		do {								\
    30			if (exclusive)						\
  > 31				ret = wait_event_interruptible_exclusive(wq,	\
    32								condition);	\
    33			else							\
    34				ret = wait_event_interruptible(wq, condition);	\
    35			if (!__ret || fatal_signal_pending(current))		\
    36				break;						\
    37			if (!freezing(current))					\
    38				continue;					\
    39		} while (try_to_freeze());					\
    40		__ret;								\
    41	})
    42	
    43	static struct kmem_cache *fuse_req_cachep;
    44	
    45	static struct fuse_dev *fuse_get_dev(struct file *file)
    46	{
    47		/*
    48		 * Lockless access is OK, because file->private data is set
    49		 * once during mount and is valid until the file is released.
    50		 */
    51		return ACCESS_ONCE(file->private_data);
    52	}
    53	
    54	static void fuse_request_init(struct fuse_req *req, struct page **pages,
    55				      struct fuse_page_desc *page_descs,
    56				      unsigned npages)
    57	{
    58		memset(req, 0, sizeof(*req));
    59		memset(pages, 0, sizeof(*pages) * npages);
    60		memset(page_descs, 0, sizeof(*page_descs) * npages);
    61		INIT_LIST_HEAD(&req->list);
    62		INIT_LIST_HEAD(&req->intr_entry);
    63		init_waitqueue_head(&req->waitq);
    64		atomic_set(&req->count, 1);
    65		req->pages = pages;
    66		req->page_descs = page_descs;
    67		req->max_pages = npages;
    68		__set_bit(FR_PENDING, &req->flags);
    69	}
    70	
    71	static struct fuse_req *__fuse_request_alloc(unsigned npages, gfp_t flags)
    72	{
    73		struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, flags);
    74		if (req) {
    75			struct page **pages;
    76			struct fuse_page_desc *page_descs;
    77	
    78			if (npages <= FUSE_REQ_INLINE_PAGES) {
    79				pages = req->inline_pages;
    80				page_descs = req->inline_page_descs;
    81			} else {
    82				pages = kmalloc(sizeof(struct page *) * npages, flags);
    83				page_descs = kmalloc(sizeof(struct fuse_page_desc) *
    84						     npages, flags);
    85			}
    86	
    87			if (!pages || !page_descs) {
    88				kfree(pages);
    89				kfree(page_descs);
    90				kmem_cache_free(fuse_req_cachep, req);
    91				return NULL;
    92			}
    93	
    94			fuse_request_init(req, pages, page_descs, npages);
    95		}
    96		return req;
    97	}
    98	
    99	struct fuse_req *fuse_request_alloc(unsigned npages)
   100	{
   101		return __fuse_request_alloc(npages, GFP_KERNEL);
   102	}
   103	EXPORT_SYMBOL_GPL(fuse_request_alloc);
   104	
   105	struct fuse_req *fuse_request_alloc_nofs(unsigned npages)
   106	{
   107		return __fuse_request_alloc(npages, GFP_NOFS);
   108	}
   109	
   110	void fuse_request_free(struct fuse_req *req)
   111	{
   112		if (req->pages != req->inline_pages) {
   113			kfree(req->pages);
   114			kfree(req->page_descs);
   115		}
   116		kmem_cache_free(fuse_req_cachep, req);
   117	}
   118	
   119	static void block_sigs(sigset_t *oldset)
   120	{
   121		sigset_t mask;
   122	
   123		siginitsetinv(&mask, sigmask(SIGKILL));
   124		sigprocmask(SIG_BLOCK, &mask, oldset);
   125	}
   126	
   127	static void restore_sigs(sigset_t *oldset)
   128	{
   129		sigprocmask(SIG_SETMASK, oldset, NULL);
   130	}
   131	
   132	void __fuse_get_request(struct fuse_req *req)
   133	{
   134		atomic_inc(&req->count);
   135	}
   136	
   137	/* Must be called with > 1 refcount */
   138	static void __fuse_put_request(struct fuse_req *req)
   139	{
   140		BUG_ON(atomic_read(&req->count) < 2);
   141		atomic_dec(&req->count);
   142	}
   143	
   144	static void fuse_req_init_context(struct fuse_req *req)
   145	{
   146		req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid());
   147		req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid());
   148		req->in.h.pid = current->pid;
   149	}
   150	
   151	void fuse_set_initialized(struct fuse_conn *fc)
   152	{
   153		/* Make sure stores before this are seen on another CPU */
   154		smp_wmb();
   155		fc->initialized = 1;
   156	}
   157	
   158	static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background)
   159	{
   160		return !fc->initialized || (for_background && fc->blocked);
   161	}
   162	
   163	static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
   164					       bool for_background)
   165	{
   166		struct fuse_req *req;
   167		sigset_t oldset;
   168		int intr;
   169		int err;
   170		atomic_inc(&fc->num_waiting);
   171	
   172		if (fuse_block_alloc(fc, for_background)) {
   173			err = -EINTR;
   174			block_sigs(&oldset);
 > 175			intr = wait_fatal_freezable(fc->blocked_waitq,
   176					!fuse_block_alloc(fc, for_background), true);
   177			restore_sigs(&oldset);
   178			if (intr)

---
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: 23011 bytes --]

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

* [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().
@ 2016-12-02  7:26 cuilifei
  2016-12-03  8:54 ` kbuild test robot
  0 siblings, 1 reply; 14+ messages in thread
From: cuilifei @ 2016-12-02  7:26 UTC (permalink / raw)
  To: linux-kernel; +Cc: miklos, cuilifei

Freezing process can abort when a client is waiting uninterruptibly
for a response. Add new macro wait_fatal_freezable to try to fix it.

Signed-off-by: cuilifei <cuilifei@xiaomi.com>
---
 fs/fuse/dev.c | 45 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 41 insertions(+), 4 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 70ea57c..3447ecc 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -23,6 +23,22 @@
 MODULE_ALIAS_MISCDEV(FUSE_MINOR);
 MODULE_ALIAS("devname:fuse");
 
+#define wait_fatal_freezable(wq, condition, exclusive)			\
+({									\
+	int __ret = 0;							\
+	do {								\
+		if (exclusive)						\
+			__ret = wait_event_interruptible_exclusive(wq,	\
+							condition);	\
+		else							\
+			__ret = wait_event_interruptible(wq,		\
+							condition);	\
+		if (!__ret || fatal_signal_pending(current))		\
+			break;						\
+	} while (try_to_freeze());					\
+	__ret;								\
+})
+
 static struct kmem_cache *fuse_req_cachep;
 
 static struct fuse_dev *fuse_get_dev(struct file *file)
@@ -99,6 +115,19 @@ void fuse_request_free(struct fuse_req *req)
 	kmem_cache_free(fuse_req_cachep, req);
 }
 
+static void block_sigs(sigset_t *oldset)
+{
+	sigset_t mask;
+
+	siginitsetinv(&mask, sigmask(SIGKILL));
+	sigprocmask(SIG_BLOCK, &mask, oldset);
+}
+
+static void restore_sigs(sigset_t *oldset)
+{
+	sigprocmask(SIG_SETMASK, oldset, NULL);
+}
+
 void __fuse_get_request(struct fuse_req *req)
 {
 	atomic_inc(&req->count);
@@ -134,13 +163,18 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
 				       bool for_background)
 {
 	struct fuse_req *req;
+	sigset_t oldset;
+	int intr;
 	int err;
 	atomic_inc(&fc->num_waiting);
 
 	if (fuse_block_alloc(fc, for_background)) {
 		err = -EINTR;
-		if (wait_event_killable_exclusive(fc->blocked_waitq,
-				!fuse_block_alloc(fc, for_background)))
+		block_sigs(&oldset);
+		intr = wait_fatal_freezable(fc->blocked_waitq,
+				!fuse_block_alloc(fc, for_background), true);
+		restore_sigs(&oldset);
+		if (intr)
 			goto out;
 	}
 	/* Matches smp_wmb() in fuse_set_initialized() */
@@ -427,9 +461,12 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
 	}
 
 	if (!test_bit(FR_FORCE, &req->flags)) {
+		sigset_t oldset;
 		/* Only fatal signals may interrupt this */
-		err = wait_event_killable(req->waitq,
-					test_bit(FR_FINISHED, &req->flags));
+		block_sigs(&oldset);
+		err = wait_fatal_freezable(req->waitq,
+				test_bit(FR_FINISHED, &req->flags), false);
+		restore_sigs(&oldset);
 		if (!err)
 			return;
 
-- 
1.9.1

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

* [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().
@ 2016-12-01  5:43 cuilifei
  2016-12-02 16:16 ` kbuild test robot
  2016-12-02 18:42 ` kbuild test robot
  0 siblings, 2 replies; 14+ messages in thread
From: cuilifei @ 2016-12-01  5:43 UTC (permalink / raw)
  To: linux-kernel; +Cc: miklos, cuilifei

Freezing process can abort when a client is waiting uninterruptibly
for a response. Add new macro wait_fatal_freezable to try to fix it.

Signed-off-by: cuilifei <cuilifei@xiaomi.com>
---
 fs/fuse/dev.c | 47 +++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 43 insertions(+), 4 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 70ea57c..40aea7d 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -23,6 +23,24 @@
 MODULE_ALIAS_MISCDEV(FUSE_MINOR);
 MODULE_ALIAS("devname:fuse");
 
+#define wait_fatal_freezable(wq, condition, exclusive)			\
+({									\
+	int __ret = 0;							\
+	do {								\
+		if (exclusive)						\
+			__ret = wait_event_interruptible_exclusive(wq,	\
+							condition);	\
+		else							\
+			__ret = wait_event_interruptible(wq,		\
+							condition);	\
+		if (!__ret || fatal_signal_pending(current))		\
+			break;						\
+		if (!freezing(current))					\
+			continue;					\
+	} while (try_to_freeze());					\
+	__ret;								\
+})
+
 static struct kmem_cache *fuse_req_cachep;
 
 static struct fuse_dev *fuse_get_dev(struct file *file)
@@ -99,6 +117,19 @@ void fuse_request_free(struct fuse_req *req)
 	kmem_cache_free(fuse_req_cachep, req);
 }
 
+static void block_sigs(sigset_t *oldset)
+{
+	sigset_t mask;
+
+	siginitsetinv(&mask, sigmask(SIGKILL));
+	sigprocmask(SIG_BLOCK, &mask, oldset);
+}
+
+static void restore_sigs(sigset_t *oldset)
+{
+	sigprocmask(SIG_SETMASK, oldset, NULL);
+}
+
 void __fuse_get_request(struct fuse_req *req)
 {
 	atomic_inc(&req->count);
@@ -134,13 +165,18 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
 				       bool for_background)
 {
 	struct fuse_req *req;
+	sigset_t oldset;
+	int intr;
 	int err;
 	atomic_inc(&fc->num_waiting);
 
 	if (fuse_block_alloc(fc, for_background)) {
 		err = -EINTR;
-		if (wait_event_killable_exclusive(fc->blocked_waitq,
-				!fuse_block_alloc(fc, for_background)))
+		block_sigs(&oldset);
+		intr = wait_fatal_freezable(fc->blocked_waitq,
+				!fuse_block_alloc(fc, for_background), true);
+		restore_sigs(&oldset);
+		if (intr)
 			goto out;
 	}
 	/* Matches smp_wmb() in fuse_set_initialized() */
@@ -427,9 +463,12 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
 	}
 
 	if (!test_bit(FR_FORCE, &req->flags)) {
+		sigset_t oldset;
 		/* Only fatal signals may interrupt this */
-		err = wait_event_killable(req->waitq,
-					test_bit(FR_FINISHED, &req->flags));
+		block_sigs(&oldset);
+		err = wait_fatal_freezable(req->waitq,
+				test_bit(FR_FINISHED, &req->flags), false);
+		restore_sigs(&oldset);
 		if (!err)
 			return;
 
-- 
1.9.1

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

* [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}().
@ 2016-12-01  5:37 cuilifei
  2016-12-02 14:42 ` kbuild test robot
  2016-12-02 14:51 ` kbuild test robot
  0 siblings, 2 replies; 14+ messages in thread
From: cuilifei @ 2016-12-01  5:37 UTC (permalink / raw)
  To: linux-kernel; +Cc: miklos, cuilifei

Freezing process can abort when a client is waiting uninterruptibly
for a response. Add new macro wait_fatal_freezable to try to fix it.

Signed-off-by: cuilifei <cuilifei@xiaomi.com>
---
 fs/fuse/dev.c | 46 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 42 insertions(+), 4 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 70ea57c..5c63518 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -23,6 +23,23 @@
 MODULE_ALIAS_MISCDEV(FUSE_MINOR);
 MODULE_ALIAS("devname:fuse");
 
+#define wait_fatal_freezable(wq, condition, exclusive)			\
+({									\
+	int __ret = 0;							\
+	do {								\
+		if (exclusive)						\
+			ret = wait_event_interruptible_exclusive(wq,	\
+							condition);	\
+		else							\
+			ret = wait_event_interruptible(wq, condition);	\
+		if (!__ret || fatal_signal_pending(current))		\
+			break;						\
+		if (!freezing(current))					\
+			continue;					\
+	} while (try_to_freeze());					\
+	__ret;								\
+})
+
 static struct kmem_cache *fuse_req_cachep;
 
 static struct fuse_dev *fuse_get_dev(struct file *file)
@@ -99,6 +116,19 @@ void fuse_request_free(struct fuse_req *req)
 	kmem_cache_free(fuse_req_cachep, req);
 }
 
+static void block_sigs(sigset_t *oldset)
+{
+	sigset_t mask;
+
+	siginitsetinv(&mask, sigmask(SIGKILL));
+	sigprocmask(SIG_BLOCK, &mask, oldset);
+}
+
+static void restore_sigs(sigset_t *oldset)
+{
+	sigprocmask(SIG_SETMASK, oldset, NULL);
+}
+
 void __fuse_get_request(struct fuse_req *req)
 {
 	atomic_inc(&req->count);
@@ -134,13 +164,18 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
 				       bool for_background)
 {
 	struct fuse_req *req;
+	sigset_t oldset;
+	int intr;
 	int err;
 	atomic_inc(&fc->num_waiting);
 
 	if (fuse_block_alloc(fc, for_background)) {
 		err = -EINTR;
-		if (wait_event_killable_exclusive(fc->blocked_waitq,
-				!fuse_block_alloc(fc, for_background)))
+		block_sigs(&oldset);
+		intr = wait_fatal_freezable(fc->blocked_waitq,
+				!fuse_block_alloc(fc, for_background), true);
+		restore_sigs(&oldset);
+		if (intr)
 			goto out;
 	}
 	/* Matches smp_wmb() in fuse_set_initialized() */
@@ -427,9 +462,12 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
 	}
 
 	if (!test_bit(FR_FORCE, &req->flags)) {
+		sigset_t oldset;
 		/* Only fatal signals may interrupt this */
-		err = wait_event_killable(req->waitq,
-					test_bit(FR_FINISHED, &req->flags));
+		block_sigs(&oldset);
+		err = wait_fatal_freezable(req->waitq,
+				test_bit(FR_FINISHED, &req->flags), false);
+		restore_sigs(&oldset);
 		if (!err)
 			return;
 
-- 
1.9.1

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

end of thread, other threads:[~2016-12-16  1:35 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-05  3:19 [PATCH] fuse: freezing abort when use wait_event_killable{,_exclusive}() cuilifei
2016-12-06 22:15 ` Rafael J. Wysocki
2016-12-08  6:31   ` 答复: " 崔立飞
2016-12-14 10:09     ` 崔立飞
2016-12-15 22:40       ` Rafael J. Wysocki
2016-12-16  1:34     ` 崔立飞
  -- strict thread matches above, loose matches on Subject: below --
2016-12-02  7:26 cuilifei
2016-12-03  8:54 ` kbuild test robot
2016-12-01  5:43 cuilifei
2016-12-02 16:16 ` kbuild test robot
2016-12-02 18:42 ` kbuild test robot
2016-12-01  5:37 cuilifei
2016-12-02 14:42 ` kbuild test robot
2016-12-02 14:51 ` kbuild test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).