ar71xx: create a profile and build images for Compex WPE72
[openwrt.git] / 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