ppp: fix fallout from the size reduction patch (thx, frogonwheels)
[openwrt/svn-archive/archive.git] / target / linux / generic / patches-2.6.37 / 212-overlayfs_fix_readdir_unlink_deadlock.patch
1 --- a/fs/overlayfs/overlayfs.c
2 +++ b/fs/overlayfs/overlayfs.c
3 @@ -1686,37 +1686,56 @@ static int ovl_check_empty_dir(struct de
4 return err;
5 }
6
7 -static int ovl_unlink_whiteout(void *buf, const char *name, int namelen,
8 - loff_t offset, u64 ino, unsigned int d_type)
9 +static int ovl_fill_links(void *buf, const char *name, int namelen,
10 + loff_t offset, u64 ino, unsigned int d_type)
11 {
12 struct ovl_readdir_data *rdd = buf;
13 + struct ovl_cache_entry *p;
14
15 - rdd->count++;
16 - /* check d_type to filter out "." and ".." */
17 - if (d_type == DT_LNK) {
18 - struct dentry *dentry;
19 + if (d_type != DT_LNK)
20 + return 0;
21
22 - dentry = lookup_one_len(name, rdd->dir, namelen);
23 - if (IS_ERR(dentry)) {
24 - rdd->err = PTR_ERR(dentry);
25 - } else {
26 - rdd->err = vfs_unlink(rdd->dir->d_inode, dentry);
27 - dput(dentry);
28 - }
29 - }
30 + p = ovl_cache_entry_new(name, namelen, ino, d_type);
31 + if (!p)
32 + return -ENOMEM;
33
34 - return rdd->err;
35 + list_add(&p->l_node, rdd->list);
36 + return 0;
37 }
38
39 static int ovl_remove_whiteouts(struct dentry *dentry)
40 {
41 struct path upperpath;
42 - struct ovl_readdir_data rdd = { .list = NULL };
43 + LIST_HEAD(list);
44 + struct ovl_readdir_data rdd = { .list = &list };
45 + struct ovl_cache_entry *p, *t;
46 + int ret;
47
48 ovl_path_upper(dentry, &upperpath);
49 rdd.dir = upperpath.dentry;
50
51 - return ovl_dir_read(&upperpath, &rdd, ovl_unlink_whiteout);
52 + ret = ovl_dir_read(&upperpath, &rdd, ovl_fill_links);
53 +
54 + mutex_lock(&rdd.dir->d_inode->i_mutex);
55 + list_for_each_entry_safe(p, t, &list, l_node) {
56 + struct dentry *dentry;
57 +
58 + if (!ret) {
59 + dentry = lookup_one_len(p->name, rdd.dir, p->len);
60 + if (IS_ERR(dentry)) {
61 + ret = PTR_ERR(dentry);
62 + } else {
63 + ret = vfs_unlink(rdd.dir->d_inode, dentry);
64 + dput(dentry);
65 + }
66 + }
67 +
68 + list_del(&p->l_node);
69 + kfree(p);
70 + }
71 + mutex_unlock(&rdd.dir->d_inode->i_mutex);
72 +
73 + return ret;
74 }
75
76 static int ovl_rmdir(struct inode *dir, struct dentry *dentry)