linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Miklos Szeredi <miklos@szeredi.hu>
To: Pavel Machek <pavel@ucw.cz>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>,
	Goswin von Brederlow <goswin-v-b@web.de>,
	Li Fei <fei.li@intel.com>,
	len.brown@intel.com, mingo@redhat.com, peterz@infradead.org,
	biao.wang@intel.com, linux-pm@vger.kernel.org,
	fuse-devel@lists.sourceforge.net, linux-kernel@vger.kernel.org,
	chuansheng.liu@intel.com
Subject: Re: Getting rid of freezer for suspend [was Re: [fuse-devel] [PATCH] fuse: make fuse daemon frozen along with kernel threads]
Date: Tue, 12 Feb 2013 14:17:19 +0100	[thread overview]
Message-ID: <CAJfpegvV0zQ5Lftx=ELP0MAH1-7oY5HfT-CSYEaFUWJLmXoD7A@mail.gmail.com> (raw)
In-Reply-To: <CAJfpegvdVfEFTU5haMMi94PD1iZ1XyCRjg0O9vDjDg1yyaM-yA@mail.gmail.com>

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

On Tue, Feb 12, 2013 at 2:13 PM, Miklos Szeredi <miklos@szeredi.hu> wrote:
> On Tue, Feb 12, 2013 at 11:46 AM, Pavel Machek <pavel@ucw.cz> wrote:
>
>> (After all, with FUSE, filesystem clients are just doing IPC. In ideal
>> world, that would be freezeable and killable with -9).
>
> Exactly.
>
> Attaching a patch

And this time for real...  Sorry for not sending it inline, I'm having
a Mail Client Crisis.

Thanks,
Miklos

[-- Attachment #2: make-fuse-freezable.patch --]
[-- Type: application/octet-stream, Size: 12405 bytes --]

---
 fs/fuse/dev.c              |   12 ++++---
 fs/fuse/file.c             |    4 +-
 fs/fuse/inode.c            |    3 +
 include/linux/freezer.h    |   19 ++++++++++++
 include/linux/gfp.h        |    4 +-
 include/linux/mutex.h      |    2 +
 include/linux/page-flags.h |    2 +
 include/linux/pagemap.h    |    8 +++--
 kernel/freezer.c           |    2 -
 kernel/mutex.c             |   10 +++++-
 mm/filemap.c               |   70 +++++++++++++++++++++++++++++++++++++++------
 mm/page_alloc.c            |    6 +++
 12 files changed, 121 insertions(+), 21 deletions(-)

--- 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");
@@ -106,7 +107,7 @@ struct fuse_req *fuse_get_req(struct fus
 
 	atomic_inc(&fc->num_waiting);
 	block_sigs(&oldset);
-	intr = wait_event_interruptible(fc->blocked_waitq, !fc->blocked);
+	intr = wait_event_freeze_intr(fc->blocked_waitq, !fc->blocked);
 	restore_sigs(&oldset);
 	err = -EINTR;
 	if (intr)
@@ -143,7 +144,8 @@ static struct fuse_req *get_reserved_req
 	struct fuse_file *ff = file->private_data;
 
 	do {
-		wait_event(fc->reserved_req_waitq, ff->reserved_req);
+		wait_event_freeze_nonintr(fc->reserved_req_waitq,
+					  ff->reserved_req);
 		spin_lock(&fc->lock);
 		if (ff->reserved_req) {
 			req = ff->reserved_req;
@@ -191,7 +193,7 @@ struct fuse_req *fuse_get_req_nofail(str
 	struct fuse_req *req;
 
 	atomic_inc(&fc->num_waiting);
-	wait_event(fc->blocked_waitq, !fc->blocked);
+	wait_event_freeze_nonintr(fc->blocked_waitq, !fc->blocked);
 	req = fuse_request_alloc();
 	if (!req)
 		req = get_reserved_req(fc, file);
@@ -330,7 +332,7 @@ __acquires(fc->lock)
 		return;
 
 	spin_unlock(&fc->lock);
-	wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED);
+	wait_event_freeze_intr(req->waitq, req->state == FUSE_REQ_FINISHED);
 	spin_lock(&fc->lock);
 }
 
@@ -386,7 +388,7 @@ __acquires(fc->lock)
 	 * Wait it out.
 	 */
 	spin_unlock(&fc->lock);
-	wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
+	wait_event_freeze_nonintr(req->waitq, req->state == FUSE_REQ_FINISHED);
 	spin_lock(&fc->lock);
 
 	if (!req->aborted)
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/compat.h>
 #include <linux/swap.h>
+#include <linux/freezer.h>
 
 static const struct file_operations fuse_direct_io_file_operations;
 
@@ -349,7 +350,8 @@ static int fuse_wait_on_page_writeback(s
 {
 	struct fuse_inode *fi = get_fuse_inode(inode);
 
-	wait_event(fi->page_waitq, !fuse_page_is_writeback(inode, index));
+	wait_event_freeze_nonintr(fi->page_waitq,
+				  !fuse_page_is_writeback(inode, index));
 	return 0;
 }
 
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -290,6 +290,8 @@ struct inode *fuse_iget(struct super_blo
 		inode->i_flags |= S_NOATIME|S_NOCMTIME;
 		inode->i_generation = generation;
 		inode->i_data.backing_dev_info = &fc->bdi;
+		inode->i_data.flags |= __GFP_FREEZABLE;
+		inode->i_mutex.freezable = true;
 		fuse_init_inode(inode, attr);
 		unlock_new_inode(inode);
 	} else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
@@ -1055,6 +1057,7 @@ static int fuse_fill_super(struct super_
 
 	list_add_tail(&fc->entry, &fuse_conn_list);
 	sb->s_root = root_dentry;
+	sb->s_vfs_rename_mutex.freezable = true;
 	fc->connected = 1;
 	file->private_data = fuse_conn_get(fc);
 	mutex_unlock(&fuse_mutex);
--- a/include/linux/freezer.h
+++ b/include/linux/freezer.h
@@ -163,6 +163,22 @@ static inline bool freezer_should_skip(s
  * defined in <linux/wait.h>
  */
 
+#define wait_event_freeze_nonintr(wq, condition)			\
+({									\
+	freezer_do_not_count();						\
+	wait_event(wq, (condition));					\
+	freezer_count();						\
+})
+
+#define wait_event_freeze_intr(wq, condition)				\
+({									\
+	int __retval;							\
+	freezer_do_not_count();						\
+	__retval = wait_event_interruptible(wq, (condition));		\
+	freezer_count();						\
+	__retval;							\
+})
+
 #define wait_event_freezekillable(wq, condition)			\
 ({									\
 	int __retval;							\
@@ -232,6 +248,9 @@ static inline void set_freezable(void) {
 #define wait_event_freezekillable(wq, condition)		\
 		wait_event_killable(wq, condition)
 
+#define wait_event_freeze_nonintr(wq, condition)		\
+		wait_event(wq, condition)
+
 #endif /* !CONFIG_FREEZER */
 
 #endif	/* FREEZER_H_INCLUDED */
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -35,6 +35,7 @@ struct vm_area_struct;
 #define ___GFP_NO_KSWAPD	0x400000u
 #define ___GFP_OTHER_NODE	0x800000u
 #define ___GFP_WRITE		0x1000000u
+#define ___GFP_FREEZABLE	0x2000000u
 /* If the above are modified, __GFP_BITS_SHIFT may need updating */
 
 /*
@@ -92,6 +93,7 @@ struct vm_area_struct;
 #define __GFP_OTHER_NODE ((__force gfp_t)___GFP_OTHER_NODE) /* On behalf of other node */
 #define __GFP_KMEMCG	((__force gfp_t)___GFP_KMEMCG) /* Allocation comes from a memcg-accounted resource */
 #define __GFP_WRITE	((__force gfp_t)___GFP_WRITE)	/* Allocator intends to dirty page */
+#define __GFP_FREEZABLE	((__force gfp_t)___GFP_FREEZABLE) /* Allocate freezable page */
 
 /*
  * This may seem redundant, but it's a way of annotating false positives vs.
@@ -99,7 +101,7 @@ struct vm_area_struct;
  */
 #define __GFP_NOTRACK_FALSE_POSITIVE (__GFP_NOTRACK)
 
-#define __GFP_BITS_SHIFT 25	/* Room for N __GFP_FOO bits */
+#define __GFP_BITS_SHIFT 26	/* Room for N __GFP_FOO bits */
 #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
 
 /* This equals 0, but use constants in case they ever change */
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -50,6 +50,7 @@ struct mutex {
 	atomic_t		count;
 	spinlock_t		wait_lock;
 	struct list_head	wait_list;
+	bool			freezable;
 #if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
 	struct task_struct	*owner;
 #endif
@@ -106,6 +107,7 @@ static inline void mutex_destroy(struct
 		{ .count = ATOMIC_INIT(1) \
 		, .wait_lock = __SPIN_LOCK_UNLOCKED(lockname.wait_lock) \
 		, .wait_list = LIST_HEAD_INIT(lockname.wait_list) \
+		, .freezable = false \
 		__DEBUG_MUTEX_INITIALIZER(lockname) \
 		__DEP_MAP_MUTEX_INITIALIZER(lockname) }
 
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -109,6 +109,7 @@ enum pageflags {
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	PG_compound_lock,
 #endif
+	PG_freezable,
 	__NR_PAGEFLAGS,
 
 	/* Filesystems */
@@ -208,6 +209,7 @@ PAGEFLAG(Pinned, pinned) TESTSCFLAG(Pinn
 PAGEFLAG(SavePinned, savepinned);			/* Xen */
 PAGEFLAG(Reserved, reserved) __CLEARPAGEFLAG(Reserved, reserved)
 PAGEFLAG(SwapBacked, swapbacked) __CLEARPAGEFLAG(SwapBacked, swapbacked)
+PAGEFLAG(Freezable, freezable)
 
 __PAGEFLAG(SlobFree, slob_free)
 
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -382,12 +382,14 @@ static inline int lock_page_or_retry(str
  */
 extern void wait_on_page_bit(struct page *page, int bit_nr);
 
-extern int wait_on_page_bit_killable(struct page *page, int bit_nr);
+extern void __wait_on_page_locked(struct page *page);
+
+extern int __wait_on_page_locked_killable(struct page *page);
 
 static inline int wait_on_page_locked_killable(struct page *page)
 {
 	if (PageLocked(page))
-		return wait_on_page_bit_killable(page, PG_locked);
+		return __wait_on_page_locked_killable(page);
 	return 0;
 }
 
@@ -401,7 +403,7 @@ static inline int wait_on_page_locked_ki
 static inline void wait_on_page_locked(struct page *page)
 {
 	if (PageLocked(page))
-		wait_on_page_bit(page, PG_locked);
+		__wait_on_page_locked(page);
 }
 
 /* 
--- a/kernel/freezer.c
+++ b/kernel/freezer.c
@@ -111,7 +111,7 @@ bool freeze_task(struct task_struct *p)
 	unsigned long flags;
 
 	spin_lock_irqsave(&freezer_lock, flags);
-	if (!freezing(p) || frozen(p)) {
+	if (!freezing(p) || frozen(p) || freezer_should_skip(p)) {
 		spin_unlock_irqrestore(&freezer_lock, flags);
 		return false;
 	}
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -20,6 +20,7 @@
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/export.h>
+#include <linux/freezer.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/debug_locks.h>
@@ -43,6 +44,7 @@ __mutex_init(struct mutex *lock, const c
 	spin_lock_init(&lock->wait_lock);
 	INIT_LIST_HEAD(&lock->wait_list);
 	mutex_clear_owner(lock);
+	lock->freezable = false;
 
 	debug_mutex_init(lock, name, key);
 }
@@ -240,7 +242,13 @@ __mutex_lock_common(struct mutex *lock,
 
 		/* didn't get the lock, go to sleep: */
 		spin_unlock_mutex(&lock->wait_lock, flags);
-		schedule_preempt_disabled();
+		if (likely(!lock->freezable)) {
+			schedule_preempt_disabled();
+		} else {
+			sched_preempt_enable_no_resched();
+			freezable_schedule();
+			preempt_disable();
+		}
 		spin_lock_mutex(&lock->wait_lock, flags);
 	}
 
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -33,6 +33,7 @@
 #include <linux/hardirq.h> /* for BUG_ON(!in_atomic()) only */
 #include <linux/memcontrol.h>
 #include <linux/cleancache.h>
+#include <linux/freezer.h>
 #include "internal.h"
 
 /*
@@ -544,15 +545,46 @@ void wait_on_page_bit(struct page *page,
 }
 EXPORT_SYMBOL(wait_on_page_bit);
 
-int wait_on_page_bit_killable(struct page *page, int bit_nr)
+void __wait_on_page_locked(struct page *page)
 {
-	DEFINE_WAIT_BIT(wait, &page->flags, bit_nr);
+	DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
+
+	if (PageLocked(page)) {
+		if (likely(!PageFreezable(page))) {
+			__wait_on_bit(page_waitqueue(page), &wait,
+				      sleep_on_page,
+				      TASK_UNINTERRUPTIBLE);
+		} else {
+			freezer_do_not_count();
+			__wait_on_bit(page_waitqueue(page), &wait,
+				      sleep_on_page,
+				      TASK_UNINTERRUPTIBLE);
+			freezer_count();
+		}
+	}
+}
+EXPORT_SYMBOL(__wait_on_page_locked);
+
+int __wait_on_page_locked_killable(struct page *page)
+{
+	DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
 
-	if (!test_bit(bit_nr, &page->flags))
+	if (!PageLocked(page))
 		return 0;
 
-	return __wait_on_bit(page_waitqueue(page), &wait,
-			     sleep_on_page_killable, TASK_KILLABLE);
+	if (likely(!PageFreezable(page))) {
+		return __wait_on_bit(page_waitqueue(page), &wait,
+				     sleep_on_page_killable, TASK_KILLABLE);
+	} else {
+		int ret;
+
+		freezer_do_not_count();
+		ret = __wait_on_bit(page_waitqueue(page), &wait,
+				     sleep_on_page_killable, TASK_KILLABLE);
+		freezer_count();
+
+		return ret;
+	}
 }
 
 /**
@@ -619,8 +651,15 @@ void __lock_page(struct page *page)
 {
 	DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
 
-	__wait_on_bit_lock(page_waitqueue(page), &wait, sleep_on_page,
-							TASK_UNINTERRUPTIBLE);
+	if (likely(!PageFreezable(page))) {
+		__wait_on_bit_lock(page_waitqueue(page), &wait, sleep_on_page,
+				   TASK_UNINTERRUPTIBLE);
+	} else {
+		freezer_do_not_count();
+		__wait_on_bit_lock(page_waitqueue(page), &wait, sleep_on_page,
+				   TASK_UNINTERRUPTIBLE);
+		freezer_count();
+	}
 }
 EXPORT_SYMBOL(__lock_page);
 
@@ -628,8 +667,21 @@ int __lock_page_killable(struct page *pa
 {
 	DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
 
-	return __wait_on_bit_lock(page_waitqueue(page), &wait,
-					sleep_on_page_killable, TASK_KILLABLE);
+	if (likely(!PageFreezable(page))) {
+		return __wait_on_bit_lock(page_waitqueue(page), &wait,
+					  sleep_on_page_killable,
+					  TASK_KILLABLE);
+	} else {
+		int ret;
+
+		freezer_do_not_count();
+		ret = __wait_on_bit_lock(page_waitqueue(page), &wait,
+					  sleep_on_page_killable,
+					  TASK_KILLABLE);
+		freezer_count();
+
+		return ret;
+	}
 }
 EXPORT_SYMBOL_GPL(__lock_page_killable);
 
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -532,6 +532,9 @@ static inline void __free_one_page(struc
 	unsigned long uninitialized_var(buddy_idx);
 	struct page *buddy;
 
+	if (unlikely(PageFreezable(page)))
+		ClearPageFreezable(page);
+
 	if (unlikely(PageCompound(page)))
 		if (unlikely(destroy_compound_page(page, order)))
 			return;
@@ -2628,6 +2631,8 @@ __alloc_pages_nodemask(gfp_t gfp_mask, u
 		goto retry_cpuset;
 
 	memcg_kmem_commit_charge(page, memcg, order);
+	if (unlikely(gfp_mask & __GFP_FREEZABLE))
+		SetPageFreezable(page);
 
 	return page;
 }
@@ -6107,6 +6112,7 @@ static const struct trace_print_flags pa
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	{1UL << PG_compound_lock,	"compound_lock"	},
 #endif
+	{1UL << PG_freezable,		"freezable"	},
 };
 
 static void dump_page_flags(unsigned long flags)

  reply	other threads:[~2013-02-12 13:17 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-02-06  1:11 [PATCH] fuse: make fuse daemon frozen along with kernel threads Li Fei
2013-02-06  9:27 ` Miklos Szeredi
     [not found]   ` <20130207084144.GB6168@frosties>
2013-02-07  9:59     ` [fuse-devel] " Miklos Szeredi
2013-02-08 14:11       ` Goswin von Brederlow
2013-02-09 17:49         ` Pavel Machek
2013-02-09 20:31           ` Rafael J. Wysocki
2013-02-10 10:33             ` Getting rid of freezer for suspend [was Re: [fuse-devel] [PATCH] fuse: make fuse daemon frozen along with kernel threads] Pavel Machek
2013-02-10 13:51               ` Rafael J. Wysocki
2013-02-10 14:22                 ` Rafael J. Wysocki
2013-02-10 18:55                   ` Pavel Machek
2013-02-10 23:31                     ` Rafael J. Wysocki
2013-02-11 10:11                       ` Miklos Szeredi
2013-02-11 12:08                         ` Rafael J. Wysocki
2013-02-11 13:59                           ` Miklos Szeredi
2013-02-11 19:28                             ` Rafael J. Wysocki
2013-02-12 10:46                             ` Pavel Machek
2013-02-12 13:13                               ` Miklos Szeredi
2013-02-12 13:17                                 ` Miklos Szeredi [this message]
2013-02-13 17:34                                   ` Miklos Szeredi
2013-02-13 20:16                                     ` Pavel Machek
2013-02-14 10:31                                       ` Miklos Szeredi
2013-02-13 21:21                                     ` Rafael J. Wysocki
2013-02-14 10:41                                       ` Miklos Szeredi
2013-02-14 12:11                                         ` Rafael J. Wysocki
2013-02-14 13:09                                           ` Miklos Szeredi
2013-02-14 17:38                                             ` Rafael J. Wysocki
2013-02-18  6:26                                               ` Li, Fei
2013-02-18 12:26                                                 ` Rafael J. Wysocki
2013-02-19 10:46                                                   ` Pavel Machek
2013-02-20  2:54                                                     ` Li, Fei
2013-02-20 13:13                                                       ` [fuse-devel] Getting rid of freezer for suspend [was " Miklos Szeredi
2013-02-11 10:53                       ` Getting rid of freezer for suspend [was Re: [fuse-devel] " Pavel Machek
2013-02-06  9:56 ` [fuse-devel] [PATCH] fuse: make fuse daemon frozen along with kernel threads Han-Wen Nienhuys
2013-02-06 14:59   ` Miklos Szeredi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAJfpegvV0zQ5Lftx=ELP0MAH1-7oY5HfT-CSYEaFUWJLmXoD7A@mail.gmail.com' \
    --to=miklos@szeredi.hu \
    --cc=biao.wang@intel.com \
    --cc=chuansheng.liu@intel.com \
    --cc=fei.li@intel.com \
    --cc=fuse-devel@lists.sourceforge.net \
    --cc=goswin-v-b@web.de \
    --cc=len.brown@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=pavel@ucw.cz \
    --cc=peterz@infradead.org \
    --cc=rjw@sisk.pl \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).