kernel: add a missing dependency for the mv_cesa crypto driver
[openwrt/svn-archive/archive.git] / target / linux / generic / patches-2.6.37 / 211-overlayfs_fix_readdir_deadlock.patch
1 --- a/fs/overlayfs/overlayfs.c
2 +++ b/fs/overlayfs/overlayfs.c
3 @@ -248,8 +248,7 @@ static struct ovl_cache_entry *ovl_cache
4 }
5
6 static struct ovl_cache_entry *ovl_cache_entry_new(const char *name, int len,
7 - u64 ino, unsigned int d_type,
8 - bool is_whiteout)
9 + u64 ino, unsigned int d_type)
10 {
11 struct ovl_cache_entry *p;
12
13 @@ -262,7 +261,7 @@ static struct ovl_cache_entry *ovl_cache
14 p->len = len;
15 p->type = d_type;
16 p->ino = ino;
17 - p->is_whiteout = is_whiteout;
18 + p->is_whiteout = false;
19 }
20
21 return p;
22 @@ -270,7 +269,7 @@ static struct ovl_cache_entry *ovl_cache
23
24 static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
25 const char *name, int len, u64 ino,
26 - unsigned int d_type, bool is_whiteout)
27 + unsigned int d_type)
28 {
29 struct rb_node **newp = &rdd->root->rb_node;
30 struct rb_node *parent = NULL;
31 @@ -291,11 +290,18 @@ static int ovl_cache_entry_add_rb(struct
32 return 0;
33 }
34
35 - p = ovl_cache_entry_new(name, len, ino, d_type, is_whiteout);
36 + p = ovl_cache_entry_new(name, len, ino, d_type);
37 if (p == NULL)
38 return -ENOMEM;
39
40 - list_add_tail(&p->l_node, rdd->list);
41 + /*
42 + * Add links before other types to be able to quicky mark
43 + * any whiteout entries
44 + */
45 + if (d_type == DT_LNK)
46 + list_add(&p->l_node, rdd->list);
47 + else
48 + list_add_tail(&p->l_node, rdd->list);
49 rb_link_node(&p->node, parent, newp);
50 rb_insert_color(&p->node, rdd->root);
51
52 @@ -313,7 +319,7 @@ static int ovl_fill_lower(void *buf, con
53 if (p) {
54 list_move_tail(&p->l_node, rdd->middle);
55 } else {
56 - p = ovl_cache_entry_new(name, namelen, ino, d_type, false);
57 + p = ovl_cache_entry_new(name, namelen, ino, d_type);
58 if (p == NULL)
59 rdd->err = -ENOMEM;
60 else
61 @@ -338,26 +344,9 @@ static int ovl_fill_upper(void *buf, con
62 loff_t offset, u64 ino, unsigned int d_type)
63 {
64 struct ovl_readdir_data *rdd = buf;
65 - bool is_whiteout = false;
66
67 rdd->count++;
68 - if (d_type == DT_LNK) {
69 - struct dentry *dentry;
70 -
71 - dentry = lookup_one_len(name, rdd->dir, namelen);
72 - if (IS_ERR(dentry)) {
73 - rdd->err = PTR_ERR(dentry);
74 - goto out;
75 - }
76 - is_whiteout = ovl_is_whiteout(dentry);
77 - dput(dentry);
78 - }
79 -
80 - rdd->err = ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type,
81 - is_whiteout);
82 -
83 -out:
84 - return rdd->err;
85 + return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type);
86 }
87
88 static int ovl_dir_read(struct path *realpath, struct ovl_readdir_data *rdd,
89 @@ -423,6 +412,26 @@ static void ovl_dir_reset(struct file *f
90 }
91 }
92
93 +static void ovl_dir_mark_whiteouts(struct ovl_readdir_data *rdd)
94 +{
95 + struct ovl_cache_entry *p;
96 + struct dentry *dentry;
97 +
98 + mutex_lock(&rdd->dir->d_inode->i_mutex);
99 + list_for_each_entry(p, rdd->list, l_node) {
100 + if (p->type != DT_LNK)
101 + break;
102 +
103 + dentry = lookup_one_len(p->name, rdd->dir, p->len);
104 + if (IS_ERR(dentry))
105 + continue;
106 +
107 + p->is_whiteout = ovl_is_whiteout(dentry);
108 + dput(dentry);
109 + }
110 + mutex_unlock(&rdd->dir->d_inode->i_mutex);
111 +}
112 +
113 static int ovl_dir_read_merged(struct path *upperpath, struct path *lowerpath,
114 struct ovl_readdir_data *rdd)
115 {
116 @@ -436,6 +445,8 @@ static int ovl_dir_read_merged(struct pa
117 err = ovl_dir_read(upperpath, rdd, ovl_fill_upper);
118 if (err)
119 goto out;
120 +
121 + ovl_dir_mark_whiteouts(rdd);
122 }
123 /*
124 * Insert lowerpath entries before upperpath ones, this allows