aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-12-16 05:02:56 -0500
committerMiklos Szeredi <mszeredi@redhat.com>2016-12-16 05:02:56 -0500
commite28edc46b8e29d2a4c10263cd7769e657582fff4 (patch)
tree1daec9814456bc7f3842d68201c27c2f593b256b
parent48fab5d7c750ff70aa77c36a44c01211020bbc98 (diff)
ovl: consolidate lookup for underlying layers
Use a common helper for lookup of upper and lower layers. This paves the way for looking up directory redirects. No functional change. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/namei.c156
1 files changed, 86 insertions, 70 deletions
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index 2e0b84c68ef6..f213297d187e 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -13,26 +13,13 @@
13#include "overlayfs.h" 13#include "overlayfs.h"
14#include "ovl_entry.h" 14#include "ovl_entry.h"
15 15
16static struct dentry *ovl_lookup_real(struct dentry *dir, 16struct ovl_lookup_data {
17 const struct qstr *name) 17 struct qstr name;
18{ 18 bool is_dir;
19 struct dentry *dentry; 19 bool opaque;
20 20 bool stop;
21 dentry = lookup_one_len_unlocked(name->name, dir, name->len); 21 bool last;
22 if (IS_ERR(dentry)) { 22};
23 if (PTR_ERR(dentry) == -ENOENT ||
24 PTR_ERR(dentry) == -ENAMETOOLONG)
25 dentry = NULL;
26 } else if (!dentry->d_inode) {
27 dput(dentry);
28 dentry = NULL;
29 } else if (ovl_dentry_weird(dentry)) {
30 dput(dentry);
31 /* Don't support traversing automounts and other weirdness */
32 dentry = ERR_PTR(-EREMOTE);
33 }
34 return dentry;
35}
36 23
37static bool ovl_is_opaquedir(struct dentry *dentry) 24static bool ovl_is_opaquedir(struct dentry *dentry)
38{ 25{
@@ -49,6 +36,64 @@ static bool ovl_is_opaquedir(struct dentry *dentry)
49 return false; 36 return false;
50} 37}
51 38
39static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
40 const char *name, unsigned int namelen,
41 struct dentry **ret)
42{
43 struct dentry *this;
44 int err;
45
46 this = lookup_one_len_unlocked(name, base, namelen);
47 if (IS_ERR(this)) {
48 err = PTR_ERR(this);
49 this = NULL;
50 if (err == -ENOENT || err == -ENAMETOOLONG)
51 goto out;
52 goto out_err;
53 }
54 if (!this->d_inode)
55 goto put_and_out;
56
57 if (ovl_dentry_weird(this)) {
58 /* Don't support traversing automounts and other weirdness */
59 err = -EREMOTE;
60 goto out_err;
61 }
62 if (ovl_is_whiteout(this)) {
63 d->stop = d->opaque = true;
64 goto put_and_out;
65 }
66 if (!d_can_lookup(this)) {
67 d->stop = true;
68 if (d->is_dir)
69 goto put_and_out;
70 goto out;
71 }
72 d->is_dir = true;
73 if (!d->last && ovl_is_opaquedir(this)) {
74 d->stop = d->opaque = true;
75 goto out;
76 }
77out:
78 *ret = this;
79 return 0;
80
81put_and_out:
82 dput(this);
83 this = NULL;
84 goto out;
85
86out_err:
87 dput(this);
88 return err;
89}
90
91static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
92 struct dentry **ret)
93{
94 return ovl_lookup_single(base, d, d->name.name, d->name.len, ret);
95}
96
52/* 97/*
53 * Returns next layer in stack starting from top. 98 * Returns next layer in stack starting from top.
54 * Returns -1 if this is the last layer. 99 * Returns -1 if this is the last layer.
@@ -82,11 +127,16 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
82 unsigned int ctr = 0; 127 unsigned int ctr = 0;
83 struct inode *inode = NULL; 128 struct inode *inode = NULL;
84 bool upperopaque = false; 129 bool upperopaque = false;
85 bool stop = false;
86 bool isdir = false;
87 struct dentry *this; 130 struct dentry *this;
88 unsigned int i; 131 unsigned int i;
89 int err; 132 int err;
133 struct ovl_lookup_data d = {
134 .name = dentry->d_name,
135 .is_dir = false,
136 .opaque = false,
137 .stop = false,
138 .last = !poe->numlower,
139 };
90 140
91 if (dentry->d_name.len > ofs->namelen) 141 if (dentry->d_name.len > ofs->namelen)
92 return ERR_PTR(-ENAMETOOLONG); 142 return ERR_PTR(-ENAMETOOLONG);
@@ -94,70 +144,36 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
94 old_cred = ovl_override_creds(dentry->d_sb); 144 old_cred = ovl_override_creds(dentry->d_sb);
95 upperdir = ovl_upperdentry_dereference(poe); 145 upperdir = ovl_upperdentry_dereference(poe);
96 if (upperdir) { 146 if (upperdir) {
97 this = ovl_lookup_real(upperdir, &dentry->d_name); 147 err = ovl_lookup_layer(upperdir, &d, &upperdentry);
98 err = PTR_ERR(this); 148 if (err)
99 if (IS_ERR(this))
100 goto out; 149 goto out;
101 150
102 if (this) { 151 if (upperdentry && unlikely(ovl_dentry_remote(upperdentry))) {
103 if (unlikely(ovl_dentry_remote(this))) { 152 dput(upperdentry);
104 dput(this); 153 err = -EREMOTE;
105 err = -EREMOTE; 154 goto out;
106 goto out;
107 }
108 if (ovl_is_whiteout(this)) {
109 dput(this);
110 this = NULL;
111 stop = upperopaque = true;
112 } else if (!d_is_dir(this)) {
113 stop = true;
114 } else {
115 isdir = true;
116 if (poe->numlower && ovl_is_opaquedir(this))
117 stop = upperopaque = true;
118 }
119 } 155 }
120 upperdentry = this; 156 upperopaque = d.opaque;
121 } 157 }
122 158
123 if (!stop && poe->numlower) { 159 if (!d.stop && poe->numlower) {
124 err = -ENOMEM; 160 err = -ENOMEM;
125 stack = kcalloc(poe->numlower, sizeof(struct path), GFP_KERNEL); 161 stack = kcalloc(poe->numlower, sizeof(struct path),
162 GFP_TEMPORARY);
126 if (!stack) 163 if (!stack)
127 goto out_put_upper; 164 goto out_put_upper;
128 } 165 }
129 166
130 for (i = 0; !stop && i < poe->numlower; i++) { 167 for (i = 0; !d.stop && i < poe->numlower; i++) {
131 struct path lowerpath = poe->lowerstack[i]; 168 struct path lowerpath = poe->lowerstack[i];
132 169
133 this = ovl_lookup_real(lowerpath.dentry, &dentry->d_name); 170 d.last = i == poe->numlower - 1;
134 err = PTR_ERR(this); 171 err = ovl_lookup_layer(lowerpath.dentry, &d, &this);
135 if (IS_ERR(this)) 172 if (err)
136 goto out_put; 173 goto out_put;
137 174
138 if (!this) 175 if (!this)
139 continue; 176 continue;
140 if (ovl_is_whiteout(this)) {
141 dput(this);
142 break;
143 }
144 /*
145 * If this is a non-directory then stop here.
146 */
147 if (!d_is_dir(this)) {
148 if (isdir) {
149 dput(this);
150 break;
151 }
152 stop = true;
153 } else {
154 /*
155 * Only makes sense to check opaque dir if this is not
156 * the lowermost layer.
157 */
158 if (i < poe->numlower - 1 && ovl_is_opaquedir(this))
159 stop = true;
160 }
161 177
162 stack[ctr].dentry = this; 178 stack[ctr].dentry = this;
163 stack[ctr].mnt = lowerpath.mnt; 179 stack[ctr].mnt = lowerpath.mnt;