[kernel] r16884 - in dists/squeeze/linux-2.6/debian: . patches/features/all/aufs2 patches/series

Ben Hutchings benh at alioth.debian.org
Mon Feb 14 23:02:54 UTC 2011


Author: benh
Date: Mon Feb 14 23:02:41 2011
New Revision: 16884

Log:
aufs: Fix VM race leading to kernel panic (Closes: #607879)

Added:
   dists/squeeze/linux-2.6/debian/patches/features/all/aufs2/Revert-aufs-bugfix-unlock-mmap_sem-temporary-using-B.patch
   dists/squeeze/linux-2.6/debian/patches/features/all/aufs2/Revert-aufs-narrow-down-the-BKL-region.patch
   dists/squeeze/linux-2.6/debian/patches/features/all/aufs2/aufs-bugfix-another-approach-to-keep-the-lock-order-.patch
   dists/squeeze/linux-2.6/debian/patches/features/all/aufs2/aufs-bugfix-separate-the-workqueue-for-preprocessing.patch
Modified:
   dists/squeeze/linux-2.6/debian/changelog
   dists/squeeze/linux-2.6/debian/patches/series/31

Modified: dists/squeeze/linux-2.6/debian/changelog
==============================================================================
--- dists/squeeze/linux-2.6/debian/changelog	Sun Feb 13 19:52:58 2011	(r16883)
+++ dists/squeeze/linux-2.6/debian/changelog	Mon Feb 14 23:02:41 2011	(r16884)
@@ -14,6 +14,7 @@
   * r8169: Keep firmware in memory (Closes: #609538)
   * linux-base: Convert LILO entries for /boot/vmlinuz, /boot/vmlinuz.old
     (Closes: #613200)
+  * aufs: Fix VM race leading to kernel panic (Closes: #607879)
 
   [ dann frazier ]
   * xfs: fix information leak using stale NFS handle (CVE-2010-2943)

Added: dists/squeeze/linux-2.6/debian/patches/features/all/aufs2/Revert-aufs-bugfix-unlock-mmap_sem-temporary-using-B.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/aufs2/Revert-aufs-bugfix-unlock-mmap_sem-temporary-using-B.patch	Mon Feb 14 23:02:41 2011	(r16884)
@@ -0,0 +1,59 @@
+From: J. R. Okajima <hooanon05 at yahoo.co.jp>
+Date: Mon, 1 Mar 2010 23:13:34 +0900
+Subject: [PATCH 2/4] Revert "aufs: bugfix, unlock mmap_sem temporary using BKL"
+
+commit 639e607997502dfe7dbe140c8de5d81ba99d4240 in aufs2-2.6
+
+This reverts commit 4b70e6f04d4292d8b5ce6cd7ac7371e68eab9175.
+BKL doesn't help the multi threaded application.
+Lockdep says mmap_sem is circular here. It may be correct, but I am not
+sure whether it is false positive or not in real world.
+
+Reported-by: "James ." <jazzrz86 at gmail.com>
+---
+ fs/aufs/f_op.c |   15 ---------------
+ 1 files changed, 0 insertions(+), 15 deletions(-)
+
+diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c
+index 4c4ef82..6f89992 100644
+--- a/fs/aufs/f_op.c
++++ b/fs/aufs/f_op.c
+@@ -25,7 +25,6 @@
+ #include <linux/mman.h>
+ #include <linux/mm.h>
+ #include <linux/security.h>
+-#include <linux/smp_lock.h>
+ #include "aufs.h"
+ 
+ /* common function to regular file and dir */
+@@ -583,18 +582,6 @@ static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
+ 	dentry = file->f_dentry;
+ 	wlock = !!(file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED);
+ 	sb = dentry->d_sb;
+-	/*
+-	 * Very ugly BKL approach to keep the order of locks.
+-	 * Here mm->mmap_sem is acquired by our caller.
+-	 *
+-	 * native readdir, i_mutex, copy_to_user, mmap_sem
+-	 * aufs readdir, i_mutex, rwsem, nested-i_mutex, copy_to_user, mmap_sem
+-	 * aufs mmap, mmap_sem, rwsem
+-	 *
+-	 * Unlock it temporary.
+-	 */
+-	lock_kernel();
+-	up_write(&current->mm->mmap_sem);
+ 	si_read_lock(sb, AuLock_FLUSH);
+ 	err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
+ 	if (unlikely(err))
+@@ -662,8 +649,6 @@ static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
+ 	fi_write_unlock(file);
+  out:
+ 	si_read_unlock(sb);
+-	down_write(&current->mm->mmap_sem);
+-	unlock_kernel();
+ 	return err;
+ }
+ 
+-- 
+1.7.2.3
+

Added: dists/squeeze/linux-2.6/debian/patches/features/all/aufs2/Revert-aufs-narrow-down-the-BKL-region.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/aufs2/Revert-aufs-narrow-down-the-BKL-region.patch	Mon Feb 14 23:02:41 2011	(r16884)
@@ -0,0 +1,64 @@
+From: J. R. Okajima <hooanon05 at yahoo.co.jp>
+Date: Mon, 1 Mar 2010 17:52:50 +0900
+Subject: [PATCH 1/4] Revert "aufs: narrow down the BKL region"
+
+commit e62ca9737674cf9b70a961cb8d1efed4a7cff976 in aufs2-2.6
+
+This reverts commit d84deeb079e09b33c2339bc7a54cf7d15c3b8a85.
+BKL doesn't help the multi threaded application.
+Lockdep says mmap_sem is circular here. It may be correct, but I am not
+sure whether it is false positive or not in real world.
+
+Reported-by: "James ." <jazzrz86 at gmail.com>
+Signed-off-by: J. R. Okajima <hooanon05 at yahoo.co.jp>
+---
+ fs/aufs/f_op.c |   14 ++++----------
+ 1 files changed, 4 insertions(+), 10 deletions(-)
+
+diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c
+index 3e9e47d..4c4ef82 100644
+--- a/fs/aufs/f_op.c
++++ b/fs/aufs/f_op.c
+@@ -597,11 +597,8 @@ static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
+ 	up_write(&current->mm->mmap_sem);
+ 	si_read_lock(sb, AuLock_FLUSH);
+ 	err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
+-	if (unlikely(err)) {
+-		down_write(&current->mm->mmap_sem);
+-		unlock_kernel();
++	if (unlikely(err))
+ 		goto out;
+-	}
+ 
+ 	mmapped = !!au_test_mmapped(file);
+ 	if (wlock) {
+@@ -609,16 +606,11 @@ static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
+ 
+ 		err = au_ready_to_write(file, -1, &pin);
+ 		di_downgrade_lock(dentry, AuLock_IR);
+-		if (unlikely(err)) {
+-			down_write(&current->mm->mmap_sem);
+-			unlock_kernel();
++		if (unlikely(err))
+ 			goto out_unlock;
+-		}
+ 		au_unpin(&pin);
+ 	} else
+ 		di_downgrade_lock(dentry, AuLock_IR);
+-	down_write(&current->mm->mmap_sem);
+-	unlock_kernel();
+ 
+ 	h_file = au_h_fptr(file, au_fbstart(file));
+ 	if (!mmapped && au_test_fs_bad_mapping(h_file->f_dentry->d_sb)) {
+@@ -670,6 +662,8 @@ static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
+ 	fi_write_unlock(file);
+  out:
+ 	si_read_unlock(sb);
++	down_write(&current->mm->mmap_sem);
++	unlock_kernel();
+ 	return err;
+ }
+ 
+-- 
+1.7.2.3
+

Added: dists/squeeze/linux-2.6/debian/patches/features/all/aufs2/aufs-bugfix-another-approach-to-keep-the-lock-order-.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/aufs2/aufs-bugfix-another-approach-to-keep-the-lock-order-.patch	Mon Feb 14 23:02:41 2011	(r16884)
@@ -0,0 +1,265 @@
+From: J. R. Okajima <hooanon05 at yahoo.co.jp>
+Date: Mon, 8 Mar 2010 23:45:56 +0900
+Subject: [PATCH 3/4] aufs: bugfix, another approach to keep the lock order of mmap_sem
+
+commit d986fa5a8557f6861fcac4106b6d75301bf5d118 in aufs2-2.6
+
+The previous approach
+	4b70e6f aufs: bugfix, unlock mmap_sem temporary using BKL
+was bad and already reverted.
+This approach is ugly too, but it works.
+
+- split aufs_mmap() into two parts.
+- the first part is for copy-ing up which requires rwsem and executed by
+  aufsd workqueue.
+- the second part is generic_file_mmap() and customizing vm_ops, and
+  executed by the original context.
+- to protect customizing vm_ops from race between two mmaps, introduce a
+  new mutex in au_finfo. lock in the first phase, and release it in the
+  second. this is the most ugly part of this approach. if we could use
+  fi_rwsem for this use, we would use it. but there is no 'set_owner'
+  method for rwsem, but mutex has.
+
+Signed-off-by: J. R. Okajima <hooanon05 at yahoo.co.jp>
+[bwh: Adjust for 2.6.32]
+---
+ fs/aufs/f_op.c  |  113 +++++++++++++++++++++++++++++++++++++++++++------------
+ fs/aufs/file.h  |    3 +
+ fs/aufs/finfo.c |   17 ++++++++
+ 3 files changed, 109 insertions(+), 24 deletions(-)
+
+diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c
+index 6f89992..32cc36f 100644
+--- a/fs/aufs/f_op.c
++++ b/fs/aufs/f_op.c
+@@ -77,6 +77,7 @@ int au_do_open_nondir(struct file *file, int flags)
+ 	finfo = au_fi(file);
+ 	finfo->fi_h_vm_ops = NULL;
+ 	finfo->fi_vm_ops = NULL;
++	mutex_init(&finfo->fi_mmap); /* regular file only? */
+ 	bindex = au_dbstart(dentry);
+ 	/* O_TRUNC is processed already */
+ 	BUG_ON(au_test_ro(dentry->d_sb, bindex, dentry->d_inode)
+@@ -544,7 +545,7 @@ static int au_custom_vm_ops(struct au_finfo *finfo, struct vm_area_struct *vma)
+ 	int err;
+ 	struct vm_operations_struct *h_ops;
+ 
+-	AuRwMustAnyLock(&finfo->fi_rwsem);
++	MtxMustLock(&finfo->fi_mmap);
+ 
+ 	err = 0;
+ 	h_ops = finfo->fi_h_vm_ops;
+@@ -570,49 +571,115 @@ static int au_custom_vm_ops(struct au_finfo *finfo, struct vm_area_struct *vma)
+ 	return err;
+ }
+ 
+-static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
++/*
++ * This is another ugly approach to keep the lock order, particularly
++ * mm->mmap_sem and aufs rwsem. The previous approach was reverted and you can
++ * find it in git-log, if you want.
++ *
++ * native readdir: i_mutex, copy_to_user, mmap_sem
++ * aufs readdir: i_mutex, rwsem, nested-i_mutex, copy_to_user, mmap_sem
++ *
++ * Before aufs_mmap() mmap_sem is acquired already, but aufs_mmap() has to
++ * acquire aufs rwsem. It introduces a circular locking dependency.
++ * To address this problem, aufs_mmap() delegates the part which requires aufs
++ * rwsem to its internal workqueue.
++ */
++
++/* very ugly approach */
++#ifdef CONFIG_DEBUG_MUTEXES
++#include <../kernel/mutex-debug.h>
++#else
++#include <../kernel/mutex.h>
++#endif
++
++struct au_mmap_pre_args {
++	/* input */
++	struct file *file;
++	struct vm_area_struct *vma;
++
++	/* output */
++	int *errp;
++	struct file *h_file;
++	int mmapped;
++};
++
++static int au_mmap_pre(struct file *file, struct vm_area_struct *vma,
++		       struct file **h_file, int *mmapped)
+ {
+ 	int err;
+-	unsigned char wlock, mmapped;
++	const unsigned char wlock
++		= !!(file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED);
+ 	struct dentry *dentry;
+ 	struct super_block *sb;
+-	struct file *h_file;
+-	struct vm_operations_struct *vm_ops;
+ 
+ 	dentry = file->f_dentry;
+-	wlock = !!(file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED);
+ 	sb = dentry->d_sb;
+-	si_read_lock(sb, AuLock_FLUSH);
++	si_read_lock(sb, !AuLock_FLUSH);
+ 	err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1);
+ 	if (unlikely(err))
+ 		goto out;
+ 
+-	mmapped = !!au_test_mmapped(file);
++	*mmapped = !!au_test_mmapped(file);
+ 	if (wlock) {
+ 		struct au_pin pin;
+ 
+ 		err = au_ready_to_write(file, -1, &pin);
+-		di_downgrade_lock(dentry, AuLock_IR);
++		di_write_unlock(dentry);
+ 		if (unlikely(err))
+ 			goto out_unlock;
+ 		au_unpin(&pin);
+ 	} else
+-		di_downgrade_lock(dentry, AuLock_IR);
++		di_write_unlock(dentry);
++	*h_file = au_h_fptr(file, au_fbstart(file));
++	get_file(*h_file);
++	au_fi_mmap_lock(file);
+ 
+-	h_file = au_h_fptr(file, au_fbstart(file));
+-	if (!mmapped && au_test_fs_bad_mapping(h_file->f_dentry->d_sb)) {
++out_unlock:
++	fi_write_unlock(file);
++out:
++	si_read_unlock(sb);
++	return err;
++}
++
++static void au_call_mmap_pre(void *args)
++{
++	struct au_mmap_pre_args *a = args;
++	*a->errp = au_mmap_pre(a->file, a->vma, &a->h_file, &a->mmapped);
++}
++
++static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
++{
++	int err, wkq_err;
++	struct au_finfo *finfo;
++	struct dentry *h_dentry;
++	struct vm_operations_struct *vm_ops;
++	struct au_mmap_pre_args args = {
++		.file		= file,
++		.vma		= vma,
++		.errp		= &err
++	};
++
++	wkq_err = au_wkq_wait(au_call_mmap_pre, &args);
++	if (unlikely(wkq_err))
++		err = wkq_err;
++	if (unlikely(err))
++		goto out;
++	finfo = au_fi(file);
++
++	h_dentry = args.h_file->f_dentry;
++	if (!args.mmapped && au_test_fs_bad_mapping(h_dentry->d_sb)) {
+ 		/*
+ 		 * by this assignment, f_mapping will differs from aufs inode
+ 		 * i_mapping.
+ 		 * if someone else mixes the use of f_dentry->d_inode and
+ 		 * f_mapping->host, then a problem may arise.
+ 		 */
+-		file->f_mapping = h_file->f_mapping;
++		file->f_mapping = args.h_file->f_mapping;
+ 	}
+ 
+ 	vm_ops = NULL;
+-	if (!mmapped) {
+-		vm_ops = au_vm_ops(h_file, vma);
++	if (!args.mmapped) {
++		vm_ops = au_vm_ops(args.h_file, vma);
+ 		err = PTR_ERR(vm_ops);
+ 		if (IS_ERR(vm_ops))
+ 			goto out_unlock;
+@@ -630,25 +698,22 @@ static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
+ 		goto out_unlock;
+ 
+ 	vma->vm_ops = &aufs_vm_ops;
+-	if (!mmapped) {
+-		struct au_finfo *finfo = au_fi(file);
+-
++	if (!args.mmapped) {
+ 		finfo->fi_h_vm_ops = vm_ops;
+ 		mutex_init(&finfo->fi_vm_mtx);
+ 	}
+ 
+-	err = au_custom_vm_ops(au_fi(file), vma);
++	err = au_custom_vm_ops(finfo, vma);
+ 	if (unlikely(err))
+ 		goto out_unlock;
+ 
+-	vfsub_file_accessed(h_file);
+-	fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode);
++	vfsub_file_accessed(args.h_file);
++	fsstack_copy_attr_atime(file->f_dentry->d_inode, h_dentry->d_inode);
+ 
+  out_unlock:
+-	di_read_unlock(dentry, AuLock_IR);
+-	fi_write_unlock(file);
++	au_fi_mmap_unlock(file);
++	fput(args.h_file);
+  out:
+-	si_read_unlock(sb);
+ 	return err;
+ }
+ 
+diff --git a/fs/aufs/file.h b/fs/aufs/file.h
+index 4aaea9e..1d1d9d6 100644
+--- a/fs/aufs/file.h
++++ b/fs/aufs/file.h
+@@ -49,6 +49,7 @@ struct au_finfo {
+ 			struct vm_operations_struct	*fi_h_vm_ops;
+ 			struct vm_operations_struct	*fi_vm_ops;
+ 			struct mutex			fi_vm_mtx;
++			struct mutex			fi_mmap;
+ 		};
+ 
+ 		/* dir only */
+@@ -114,6 +115,8 @@ void au_set_h_fptr(struct file *file, aufs_bindex_t bindex,
+ 		   struct file *h_file);
+ 
+ void au_update_figen(struct file *file);
++void au_fi_mmap_lock(struct file *file);
++void au_fi_mmap_unlock(struct file *file);
+ 
+ void au_finfo_fin(struct file *file);
+ int au_finfo_init(struct file *file);
+diff --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c
+index 4ab55e4..24ed4a1 100644
+--- a/fs/aufs/finfo.c
++++ b/fs/aufs/finfo.c
+@@ -56,6 +56,23 @@ void au_update_figen(struct file *file)
+ 
+ /* ---------------------------------------------------------------------- */
+ 
++void au_fi_mmap_lock(struct file *file)
++{
++	FiMustWriteLock(file);
++	lockdep_off();
++	mutex_lock(&au_fi(file)->fi_mmap);
++	lockdep_on();
++}
++
++void au_fi_mmap_unlock(struct file *file)
++{
++	lockdep_off();
++	mutex_unlock(&au_fi(file)->fi_mmap);
++	lockdep_on();
++}
++
++/* ---------------------------------------------------------------------- */
++
+ void au_finfo_fin(struct file *file)
+ {
+ 	struct au_finfo *finfo;
+-- 
+1.7.2.3
+

Added: dists/squeeze/linux-2.6/debian/patches/features/all/aufs2/aufs-bugfix-separate-the-workqueue-for-preprocessing.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/features/all/aufs2/aufs-bugfix-separate-the-workqueue-for-preprocessing.patch	Mon Feb 14 23:02:41 2011	(r16884)
@@ -0,0 +1,213 @@
+From: J. R. Okajima <hooanon05 at yahoo.co.jp>
+Date: Tue, 29 Jun 2010 14:32:26 +0900
+Subject: [PATCH 4/4] aufs: bugfix, separate the workqueue for preprocessing mmap
+
+commit b0372e021a903e33f39dd515ceebd8506b1c52aa in aufs2-2.6
+
+variation of common AB-BA deadlock problem.
+
+ProcessA:
+- aufs_mmap
+  + pre-process with using a workqueue
+  + wait until return from the workqueue
+
+Workqueue task for ProcessA:
+- acquire aufs rwsem
+
+Processb
+- lookup or readdir in aufs
+  + acquire aufs rwsem
+  + assign a new inode number
+  + write the value to the XINO file using a workqueue
+  + wait until return from the workqueue
+
+Since the workqueue handles the request one by one, both of processA and
+B waits forever.
+
+This bug was introduced by the commit
+d986fa5 2010-03-08
+	aufs: bugfix, another approach to keep the lock order of mmap_sem
+which is the last added workqueue task.
+And this is the only one task which acquires such lock in workqueue.
+To fix it, introduce another workqueue which is for preprocessing mmap only.
+This commit will make the approach more ugly, I don't have another option.
+
+Reported-by: Oliver Welter <mail at oliwel.de>
+Signed-off-by: J. R. Okajima <hooanon05 at yahoo.co.jp>
+[bwh: Adjust context for Debian's 2.6.32]
+---
+ fs/aufs/f_op.c            |    2 +-
+ fs/aufs/wkq.c             |   62 ++++++++++++++++++++++++++++++++++++--------
+ fs/aufs/wkq.h             |   13 ++++++++-
+ include/linux/aufs_type.h |    1 +
+ 4 files changed, 64 insertions(+), 14 deletions(-)
+
+diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c
+index 6abec9c..99982e5 100644
+--- a/fs/aufs/f_op.c
++++ b/fs/aufs/f_op.c
+@@ -666,7 +666,7 @@ static int aufs_mmap(struct file *file, struct vm_area_struct *vma)
+ 		.errp		= &err
+ 	};
+ 
+-	wkq_err = au_wkq_wait(au_call_mmap_pre, &args);
++	wkq_err = au_wkq_wait_pre(au_call_mmap_pre, &args);
+ 	if (unlikely(wkq_err))
+ 		err = wkq_err;
+ 	if (unlikely(err))
+diff --git a/fs/aufs/wkq.c b/fs/aufs/wkq.c
+index 307b1c4..c867e70 100644
+--- a/fs/aufs/wkq.c
++++ b/fs/aufs/wkq.c
+@@ -24,8 +24,23 @@
+ #include <linux/module.h>
+ #include "aufs.h"
+ 
+-/* internal workqueue named AUFS_WKQ_NAME */
+-static struct workqueue_struct *au_wkq;
++/* internal workqueue named AUFS_WKQ_NAME and AUFS_WKQ_PRE_NAME */
++enum {
++	AuWkq_INORMAL,
++	AuWkq_IPRE
++};
++
++static struct {
++	char *name;
++	struct workqueue_struct *wkq;
++} au_wkq[] = {
++	[AuWkq_INORMAL] = {
++		.name = AUFS_WKQ_NAME
++	},
++	[AuWkq_IPRE] = {
++		.name = AUFS_WKQ_PRE_NAME
++	}
++};
+ 
+ struct au_wkinfo {
+ 	struct work_struct wk;
+@@ -96,29 +111,34 @@ static void au_wkq_comp_free(struct completion *comp __maybe_unused)
+ }
+ #endif /* 4KSTACKS */
+ 
+-static void au_wkq_run(struct au_wkinfo *wkinfo, int do_wait)
++static void au_wkq_run(struct au_wkinfo *wkinfo, unsigned int flags)
+ {
++	struct workqueue_struct *wkq;
++
+ 	au_dbg_verify_kthread();
+ 	INIT_WORK(&wkinfo->wk, wkq_func);
+-	if (do_wait)
+-		queue_work(au_wkq, &wkinfo->wk);
+-	else
++	if (flags & AuWkq_WAIT) {
++		wkq = au_wkq[AuWkq_INORMAL].wkq;
++		if (flags & AuWkq_PRE)
++			wkq = au_wkq[AuWkq_IPRE].wkq;
++		queue_work(wkq, &wkinfo->wk);
++	} else
+ 		schedule_work(&wkinfo->wk);
+ }
+ 
+-int au_wkq_wait(au_wkq_func_t func, void *args)
++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args)
+ {
+ 	int err;
+ 	AuWkqCompDeclare(comp);
+ 	struct au_wkinfo wkinfo = {
+-		.flags	= AuWkq_WAIT,
++		.flags	= flags,
+ 		.func	= func,
+ 		.args	= args
+ 	};
+ 
+ 	err = au_wkq_comp_alloc(&wkinfo, &comp);
+ 	if (!err) {
+-		au_wkq_run(&wkinfo, AuWkq_WAIT);
++		au_wkq_run(&wkinfo, flags);
+ 		/* no timeout, no interrupt */
+ 		wait_for_completion(wkinfo.comp);
+ 		au_wkq_comp_free(comp);
+@@ -170,11 +190,29 @@ void au_nwt_init(struct au_nowait_tasks *nwt)
+ 
+ void au_wkq_fin(void)
+ {
+-	destroy_workqueue(au_wkq);
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(au_wkq); i++)
++		if (au_wkq[i].wkq)
++			destroy_workqueue(au_wkq[i].wkq);
+ }
+ 
+ int __init au_wkq_init(void)
+ {
+-	au_wkq = create_workqueue(AUFS_WKQ_NAME);
+-	return 0;
++	int err, i;
++
++	err = 0;
++	for (i = 0; !err && i < ARRAY_SIZE(au_wkq); i++) {
++		au_wkq[i].wkq = create_workqueue(au_wkq[i].name);
++		if (IS_ERR(au_wkq[i].wkq))
++			err = PTR_ERR(au_wkq[i].wkq);
++		else if (!au_wkq[i].wkq)
++			err = -ENOMEM;
++		if (unlikely(err))
++			au_wkq[i].wkq = NULL;
++	}
++	if (unlikely(err))
++		au_wkq_fin();
++
++	return err;
+ }
+diff --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h
+index 3fe36b3..3e6f5b5 100644
+--- a/fs/aufs/wkq.h
++++ b/fs/aufs/wkq.h
+@@ -48,12 +48,13 @@ typedef void (*au_wkq_func_t)(void *args);
+ 
+ /* wkq flags */
+ #define AuWkq_WAIT	1
++#define AuWkq_PRE	(1 << 1)
+ #define au_ftest_wkq(flags, name)	((flags) & AuWkq_##name)
+ #define au_fset_wkq(flags, name)	{ (flags) |= AuWkq_##name; }
+ #define au_fclr_wkq(flags, name)	{ (flags) &= ~AuWkq_##name; }
+ 
+ /* wkq.c */
+-int au_wkq_wait(au_wkq_func_t func, void *args);
++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args);
+ int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb);
+ void au_nwt_init(struct au_nowait_tasks *nwt);
+ int __init au_wkq_init(void);
+@@ -61,6 +62,16 @@ void au_wkq_fin(void);
+ 
+ /* ---------------------------------------------------------------------- */
+ 
++static inline int au_wkq_wait_pre(au_wkq_func_t func, void *args)
++{
++	return au_wkq_do_wait(AuWkq_WAIT | AuWkq_PRE, func, args);
++}
++
++static inline int au_wkq_wait(au_wkq_func_t func, void *args)
++{
++	return au_wkq_do_wait(AuWkq_WAIT, func, args);
++}
++
+ static inline int au_test_wkq(struct task_struct *tsk)
+ {
+ 	return !tsk->mm
+diff --git a/include/linux/aufs_type.h b/include/linux/aufs_type.h
+index 3ca3948..b13cfc1 100644
+--- a/include/linux/aufs_type.h
++++ b/include/linux/aufs_type.h
+@@ -75,6 +75,7 @@ typedef __s16 aufs_bindex_t;
+ #define AUFS_RDBLK_DEF		512 /* bytes */
+ #define AUFS_RDHASH_DEF		32
+ #define AUFS_WKQ_NAME		AUFS_NAME "d"
++#define AUFS_WKQ_PRE_NAME	AUFS_WKQ_NAME "_pre"
+ #define AUFS_MFS_SECOND_DEF	30 /* seconds */
+ #define AUFS_PLINK_WARN		100 /* number of plinks */
+ 
+-- 
+1.7.2.3
+

Modified: dists/squeeze/linux-2.6/debian/patches/series/31
==============================================================================
--- dists/squeeze/linux-2.6/debian/patches/series/31	Sun Feb 13 19:52:58 2011	(r16883)
+++ dists/squeeze/linux-2.6/debian/patches/series/31	Mon Feb 14 23:02:41 2011	(r16884)
@@ -14,3 +14,7 @@
 + bugfix/all/init-sched-Fix-race-between-init-and-kthreadd.patch
 + features/all/hwmon-gpio.patch
 + features/arm/ls-chl-support.patch
++ features/all/aufs2/Revert-aufs-narrow-down-the-BKL-region.patch
++ features/all/aufs2/Revert-aufs-bugfix-unlock-mmap_sem-temporary-using-B.patch
++ features/all/aufs2/aufs-bugfix-another-approach-to-keep-the-lock-order-.patch
++ features/all/aufs2/aufs-bugfix-separate-the-workqueue-for-preprocessing.patch



More information about the Kernel-svn-changes mailing list