Root/target/linux/generic/patches-2.6.37/102-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
125

Archive Download this file



interactive