| 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 | |