Skip to content

Commit

Permalink
ovl: decode pure lower dir file handles
Browse files Browse the repository at this point in the history
Similar to decoding a pure upper dir file handle, decoding a pure lower
dir file handle is implemented by looking an overlay dentry of the same
path as the pure lower path and verifying that the overlay dentry's
real lower matches the decoded real lower file handle.

Unlike the case of upper dir file handle, the lookup of overlay path by
lower real path can fail or find a mismatched overlay dentry if any of
the lower parents have been copied up and renamed. To address this case
we will need to check if any of the lower parents are indexed.

Signed-off-by: Amir Goldstein <[email protected]>
Signed-off-by: Miklos Szeredi <[email protected]>
  • Loading branch information
amir73il authored and Miklos Szeredi committed Jan 24, 2018
1 parent 3b0bfc6 commit 9889251
Showing 1 changed file with 26 additions and 17 deletions.
43 changes: 26 additions & 17 deletions fs/overlayfs/export.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,23 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb,
return ERR_PTR(-ENOMEM);
}

/* Get the upper or lower dentry in stach whose on layer @idx */
static struct dentry *ovl_dentry_real_at(struct dentry *dentry, int idx)
{
struct ovl_entry *oe = dentry->d_fsdata;
int i;

if (!idx)
return ovl_dentry_upper(dentry);

for (i = 0; i < oe->numlower; i++) {
if (oe->lowerstack[i].layer->idx == idx)
return oe->lowerstack[i].dentry;
}

return NULL;
}

/*
* Lookup a child overlay dentry to get a connected overlay dentry whose real
* dentry is @real. If @real is on upper layer, we lookup a child overlay
Expand All @@ -230,10 +247,6 @@ static struct dentry *ovl_lookup_real_one(struct dentry *connected,
struct name_snapshot name;
int err;

/* TODO: lookup by lower real dentry */
if (layer->idx)
return ERR_PTR(-EACCES);

/*
* Lookup child overlay dentry by real name. The dir mutex protects us
* from racing with overlay rename. If the overlay dentry that is above
Expand All @@ -244,7 +257,7 @@ static struct dentry *ovl_lookup_real_one(struct dentry *connected,
inode_lock_nested(dir, I_MUTEX_PARENT);
err = -ECHILD;
parent = dget_parent(real);
if (ovl_dentry_upper(connected) != parent)
if (ovl_dentry_real_at(connected, layer->idx) != parent)
goto fail;

/*
Expand All @@ -262,7 +275,7 @@ static struct dentry *ovl_lookup_real_one(struct dentry *connected,
dput(this);
err = -ENOENT;
goto fail;
} else if (ovl_dentry_upper(this) != real) {
} else if (ovl_dentry_real_at(this, layer->idx) != real) {
dput(this);
err = -ESTALE;
goto fail;
Expand Down Expand Up @@ -294,14 +307,13 @@ static struct dentry *ovl_lookup_real(struct super_block *sb,
int err = 0;

/* TODO: use index when looking up by lower real dentry */
if (layer->idx)
return ERR_PTR(-EACCES);

connected = dget(sb->s_root);
while (!err) {
struct dentry *next, *this;
struct dentry *parent = NULL;
struct dentry *real_connected = ovl_dentry_upper(connected);
struct dentry *real_connected = ovl_dentry_real_at(connected,
layer->idx);

if (real_connected == real)
break;
Expand Down Expand Up @@ -391,6 +403,7 @@ static struct dentry *ovl_get_dentry(struct super_block *sb,
{
struct ovl_fs *ofs = sb->s_fs_info;
struct ovl_layer upper_layer = { .mnt = ofs->upper_mnt };
struct ovl_layer *layer = upper ? &upper_layer : lowerpath->layer;
struct dentry *real = upper ?: (index ?: lowerpath->dentry);

/*
Expand All @@ -400,19 +413,15 @@ static struct dentry *ovl_get_dentry(struct super_block *sb,
if (!d_is_dir(real))
return ovl_obtain_alias(sb, upper, lowerpath, index);

/* TODO: lookup connected dir from real lower dir */
if (!upper)
return ERR_PTR(-EACCES);

/* Removed empty directory? */
if ((upper->d_flags & DCACHE_DISCONNECTED) || d_unhashed(upper))
if ((real->d_flags & DCACHE_DISCONNECTED) || d_unhashed(real))
return ERR_PTR(-ENOENT);

/*
* If real upper dentry is connected and hashed, get a connected
* overlay dentry with the same path as the real upper dentry.
* If real dentry is connected and hashed, get a connected overlay
* dentry whose real dentry is @real.
*/
return ovl_lookup_real(sb, upper, &upper_layer);
return ovl_lookup_real(sb, real, layer);
}

static struct dentry *ovl_upper_fh_to_d(struct super_block *sb,
Expand Down

0 comments on commit 9889251

Please sign in to comment.