aboutsummaryrefslogtreecommitdiffstats
path: root/features/revoke/revoke-inode-revoke-lock-V7-From-Pekka-Enberg-penber.patch
blob: fa7dbeb49ca869b8f560b591f4fb9a6b21aea3d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
From 27372a01d5407a0856cb338eedb412a8c850367d Mon Sep 17 00:00:00 2001
From: Yongli He <yongli.he@windriver.com>
Date: Mon, 25 Aug 2008 11:06:11 +0800
Subject: [PATCH 02/12] revoke inode revoke lock V7 From: Pekka Enberg <penberg@cs.helsinki.fi>

The revoke operation cannibalizes the revoked struct inode and removes it from
the inode cache thus forcing subsequent callers to look up the real inode.
Therefore we must make sure that while the revoke operation is in progress
(e.g. flushing dirty pages to disk) no one takes a new reference to the inode
and starts I/O on it.

Cc: Alan Cox <alan@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
Integrated-by: Yongli he   <yongli.he@windriver.com>
---
 fs/inode.c         |    1 +
 fs/namei.c         |   16 +++++++++++++++-
 include/linux/fs.h |    3 +++
 3 files changed, 19 insertions(+), 1 deletions(-)

diff --git a/fs/inode.c b/fs/inode.c
index 407bf39..dfe5654 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -264,6 +264,7 @@ void inode_init_once(struct inode *inode)
 	INIT_RAW_PRIO_TREE_ROOT(&inode->i_data.i_mmap);
 	INIT_LIST_HEAD(&inode->i_data.i_mmap_nonlinear);
 	i_size_ordered_init(inode);
+	init_waitqueue_head(&inode->i_revoke_wait);
 #ifdef CONFIG_INOTIFY
 	INIT_LIST_HEAD(&inode->inotify_watches);
 	mutex_init(&inode->inotify_mutex);
diff --git a/fs/namei.c b/fs/namei.c
index f872221..d3931e9 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -729,9 +729,23 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
 			return err;
 	}
 
-	dentry = __d_lookup(nd->path.dentry, name);
+	dentry;
+
+again:
+	dentry  = __d_lookup(nd->path.dentry, name);
 	if (!dentry)
 		goto need_lookup;
+
+	if (dentry->d_inode && IS_REVOKE_LOCKED(dentry->d_inode)) {
+		int err;
+
+		err = wait_event_interruptible(dentry->d_inode->i_revoke_wait,
+			!IS_REVOKE_LOCKED(dentry->d_inode));
+		if (err)
+			return err;
+		goto again;
+	}
+
 	if (dentry->d_op && dentry->d_op->d_revalidate)
 		goto need_revalidate;
 done:
diff --git a/include/linux/fs.h b/include/linux/fs.h
index df96554..6969c7c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -240,6 +240,7 @@ struct inodes_stat_t {
 #define S_NOCMTIME	128	/* Do not update file c/mtime */
 #define S_SWAPFILE	256	/* Do not truncate: swapon got its bmaps */
 #define S_PRIVATE	512	/* Inode is fs-internal */
+#define S_REVOKE_LOCK	1024	/* Inode is being revoked */
 
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
@@ -274,6 +275,7 @@ struct inodes_stat_t {
 #define IS_NOCMTIME(inode)	((inode)->i_flags & S_NOCMTIME)
 #define IS_SWAPFILE(inode)	((inode)->i_flags & S_SWAPFILE)
 #define IS_PRIVATE(inode)	((inode)->i_flags & S_PRIVATE)
+#define IS_REVOKE_LOCKED(inode)	((inode)->i_flags & S_REVOKE_LOCK)
 
 /* the read-only stuff doesn't really belong here, but any other place is
    probably as bad and I don't want to create yet another include file. */
@@ -779,6 +781,7 @@ struct inode {
 	struct list_head	inotify_watches; /* watches on this inode */
 	struct mutex		inotify_mutex;	/* protects the watches list */
 #endif
+	wait_queue_head_t	i_revoke_wait;
 
 	unsigned long		i_state;
 	unsigned long		dirtied_when;	/* jiffies of first dirtying */
-- 
1.6.5.2