diff options
-rw-r--r-- | fs/overlayfs/export.c | 53 | ||||
-rw-r--r-- | fs/overlayfs/namei.c | 7 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 2 |
3 files changed, 47 insertions, 15 deletions
diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c index 8e37a07b9eff..8c0172d9b922 100644 --- a/fs/overlayfs/export.c +++ b/fs/overlayfs/export.c | |||
@@ -169,16 +169,16 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb, | |||
169 | struct dentry *upper, | 169 | struct dentry *upper, |
170 | struct ovl_path *lowerpath) | 170 | struct ovl_path *lowerpath) |
171 | { | 171 | { |
172 | struct inode *inode; | 172 | struct dentry *lower = lowerpath ? lowerpath->dentry : NULL; |
173 | struct dentry *dentry; | 173 | struct dentry *dentry; |
174 | struct inode *inode; | ||
174 | struct ovl_entry *oe; | 175 | struct ovl_entry *oe; |
175 | void *fsdata = &oe; | ||
176 | 176 | ||
177 | /* TODO: obtain non pure-upper */ | 177 | /* TODO: obtain an indexed non-dir upper with origin */ |
178 | if (lowerpath) | 178 | if (lower && (upper || d_is_dir(lower))) |
179 | return ERR_PTR(-EIO); | 179 | return ERR_PTR(-EIO); |
180 | 180 | ||
181 | inode = ovl_get_inode(sb, dget(upper), NULL, NULL, 0); | 181 | inode = ovl_get_inode(sb, dget(upper), lower, NULL, !!lower); |
182 | if (IS_ERR(inode)) { | 182 | if (IS_ERR(inode)) { |
183 | dput(upper); | 183 | dput(upper); |
184 | return ERR_CAST(inode); | 184 | return ERR_CAST(inode); |
@@ -189,12 +189,17 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb, | |||
189 | dentry = d_alloc_anon(inode->i_sb); | 189 | dentry = d_alloc_anon(inode->i_sb); |
190 | if (!dentry) | 190 | if (!dentry) |
191 | goto nomem; | 191 | goto nomem; |
192 | oe = ovl_alloc_entry(0); | 192 | oe = ovl_alloc_entry(lower ? 1 : 0); |
193 | if (!oe) | 193 | if (!oe) |
194 | goto nomem; | 194 | goto nomem; |
195 | 195 | ||
196 | if (lower) { | ||
197 | oe->lowerstack->dentry = dget(lower); | ||
198 | oe->lowerstack->layer = lowerpath->layer; | ||
199 | } | ||
196 | dentry->d_fsdata = oe; | 200 | dentry->d_fsdata = oe; |
197 | ovl_dentry_set_upper_alias(dentry); | 201 | if (upper) |
202 | ovl_dentry_set_upper_alias(dentry); | ||
198 | } | 203 | } |
199 | 204 | ||
200 | return d_instantiate_anon(dentry, inode); | 205 | return d_instantiate_anon(dentry, inode); |
@@ -381,7 +386,14 @@ static struct dentry *ovl_get_dentry(struct super_block *sb, | |||
381 | struct ovl_fs *ofs = sb->s_fs_info; | 386 | struct ovl_fs *ofs = sb->s_fs_info; |
382 | struct ovl_layer upper_layer = { .mnt = ofs->upper_mnt }; | 387 | struct ovl_layer upper_layer = { .mnt = ofs->upper_mnt }; |
383 | 388 | ||
384 | /* TODO: get non-upper dentry */ | 389 | /* |
390 | * Obtain a disconnected overlay dentry from a disconnected non-dir | ||
391 | * real lower dentry. | ||
392 | */ | ||
393 | if (!upper && !d_is_dir(lowerpath->dentry)) | ||
394 | return ovl_obtain_alias(sb, NULL, lowerpath); | ||
395 | |||
396 | /* TODO: lookup connected dir from real lower dir */ | ||
385 | if (!upper) | 397 | if (!upper) |
386 | return ERR_PTR(-EACCES); | 398 | return ERR_PTR(-EACCES); |
387 | 399 | ||
@@ -423,6 +435,25 @@ static struct dentry *ovl_upper_fh_to_d(struct super_block *sb, | |||
423 | return dentry; | 435 | return dentry; |
424 | } | 436 | } |
425 | 437 | ||
438 | static struct dentry *ovl_lower_fh_to_d(struct super_block *sb, | ||
439 | struct ovl_fh *fh) | ||
440 | { | ||
441 | struct ovl_fs *ofs = sb->s_fs_info; | ||
442 | struct ovl_path origin = { }; | ||
443 | struct ovl_path *stack = &origin; | ||
444 | struct dentry *dentry = NULL; | ||
445 | int err; | ||
446 | |||
447 | err = ovl_check_origin_fh(ofs, fh, NULL, &stack); | ||
448 | if (err) | ||
449 | return ERR_PTR(err); | ||
450 | |||
451 | dentry = ovl_get_dentry(sb, NULL, &origin); | ||
452 | dput(origin.dentry); | ||
453 | |||
454 | return dentry; | ||
455 | } | ||
456 | |||
426 | static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid, | 457 | static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid, |
427 | int fh_len, int fh_type) | 458 | int fh_len, int fh_type) |
428 | { | 459 | { |
@@ -440,10 +471,10 @@ static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid, | |||
440 | if (err) | 471 | if (err) |
441 | goto out_err; | 472 | goto out_err; |
442 | 473 | ||
443 | /* TODO: decode non-upper */ | ||
444 | flags = fh->flags; | 474 | flags = fh->flags; |
445 | if (flags & OVL_FH_FLAG_PATH_UPPER) | 475 | dentry = (flags & OVL_FH_FLAG_PATH_UPPER) ? |
446 | dentry = ovl_upper_fh_to_d(sb, fh); | 476 | ovl_upper_fh_to_d(sb, fh) : |
477 | ovl_lower_fh_to_d(sb, fh); | ||
447 | err = PTR_ERR(dentry); | 478 | err = PTR_ERR(dentry); |
448 | if (IS_ERR(dentry) && err != -ESTALE) | 479 | if (IS_ERR(dentry) && err != -ESTALE) |
449 | goto out_err; | 480 | goto out_err; |
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index a35c5eaa2c01..741a42d974a3 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c | |||
@@ -310,9 +310,8 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d, | |||
310 | } | 310 | } |
311 | 311 | ||
312 | 312 | ||
313 | static int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, | 313 | int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, |
314 | struct dentry *upperdentry, | 314 | struct dentry *upperdentry, struct ovl_path **stackp) |
315 | struct ovl_path **stackp) | ||
316 | { | 315 | { |
317 | struct dentry *origin = NULL; | 316 | struct dentry *origin = NULL; |
318 | int i; | 317 | int i; |
@@ -328,7 +327,7 @@ static int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, | |||
328 | else if (IS_ERR(origin)) | 327 | else if (IS_ERR(origin)) |
329 | return PTR_ERR(origin); | 328 | return PTR_ERR(origin); |
330 | 329 | ||
331 | if (!ovl_is_whiteout(upperdentry) && | 330 | if (upperdentry && !ovl_is_whiteout(upperdentry) && |
332 | ((d_inode(origin)->i_mode ^ d_inode(upperdentry)->i_mode) & S_IFMT)) | 331 | ((d_inode(origin)->i_mode ^ d_inode(upperdentry)->i_mode) & S_IFMT)) |
333 | goto invalid; | 332 | goto invalid; |
334 | 333 | ||
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 401113a2e9c7..40ba11e412b1 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h | |||
@@ -266,6 +266,8 @@ static inline bool ovl_is_impuredir(struct dentry *dentry) | |||
266 | /* namei.c */ | 266 | /* namei.c */ |
267 | int ovl_check_fh_len(struct ovl_fh *fh, int fh_len); | 267 | int ovl_check_fh_len(struct ovl_fh *fh, int fh_len); |
268 | struct dentry *ovl_decode_fh(struct ovl_fh *fh, struct vfsmount *mnt); | 268 | struct dentry *ovl_decode_fh(struct ovl_fh *fh, struct vfsmount *mnt); |
269 | int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, | ||
270 | struct dentry *upperdentry, struct ovl_path **stackp); | ||
269 | int ovl_verify_set_fh(struct dentry *dentry, const char *name, | 271 | int ovl_verify_set_fh(struct dentry *dentry, const char *name, |
270 | struct dentry *real, bool is_upper, bool set); | 272 | struct dentry *real, bool is_upper, bool set); |
271 | int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index); | 273 | int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index); |