ovl: consistent d_ino for non-samefs with xino
When overlay layers are not all on the same fs, but all inode numbers of underlying fs do not use the high 'xino' bits, overlay st_ino values are constant and persistent. In that case, relax non-samefs constraint for consistent d_ino and always iterate non-merge dir using ovl_fill_real() actor so we can remap lower inode numbers to unique lower fs range. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
parent
12574a9f4c
commit
adbf4f7ea8
@ -120,6 +120,10 @@ static bool ovl_calc_d_ino(struct ovl_readdir_data *rdd,
|
|||||||
if (!rdd->dentry)
|
if (!rdd->dentry)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/* Always recalc d_ino when remapping lower inode numbers */
|
||||||
|
if (ovl_xino_bits(rdd->dentry->d_sb))
|
||||||
|
return true;
|
||||||
|
|
||||||
/* Always recalc d_ino for parent */
|
/* Always recalc d_ino for parent */
|
||||||
if (strcmp(p->name, "..") == 0)
|
if (strcmp(p->name, "..") == 0)
|
||||||
return true;
|
return true;
|
||||||
@ -435,6 +439,19 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
|
|||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Map inode number to lower fs unique range */
|
||||||
|
static u64 ovl_remap_lower_ino(u64 ino, int xinobits, int fsid,
|
||||||
|
const char *name, int namelen)
|
||||||
|
{
|
||||||
|
if (ino >> (64 - xinobits)) {
|
||||||
|
pr_warn_ratelimited("overlayfs: d_ino too big (%.*s, ino=%llu, xinobits=%d)\n",
|
||||||
|
namelen, name, ino, xinobits);
|
||||||
|
return ino;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ino | ((u64)fsid) << (64 - xinobits);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set d_ino for upper entries. Non-upper entries should always report
|
* Set d_ino for upper entries. Non-upper entries should always report
|
||||||
* the uppermost real inode ino and should not call this function.
|
* the uppermost real inode ino and should not call this function.
|
||||||
@ -452,9 +469,10 @@ static int ovl_cache_update_ino(struct path *path, struct ovl_cache_entry *p)
|
|||||||
struct dentry *this = NULL;
|
struct dentry *this = NULL;
|
||||||
enum ovl_path_type type;
|
enum ovl_path_type type;
|
||||||
u64 ino = p->real_ino;
|
u64 ino = p->real_ino;
|
||||||
|
int xinobits = ovl_xino_bits(dir->d_sb);
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (!ovl_same_sb(dir->d_sb))
|
if (!ovl_same_sb(dir->d_sb) && !xinobits)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (p->name[0] == '.') {
|
if (p->name[0] == '.') {
|
||||||
@ -491,6 +509,10 @@ get:
|
|||||||
|
|
||||||
WARN_ON_ONCE(dir->d_sb->s_dev != stat.dev);
|
WARN_ON_ONCE(dir->d_sb->s_dev != stat.dev);
|
||||||
ino = stat.ino;
|
ino = stat.ino;
|
||||||
|
} else if (xinobits && !OVL_TYPE_UPPER(type)) {
|
||||||
|
ino = ovl_remap_lower_ino(ino, xinobits,
|
||||||
|
ovl_layer_lower(this)->fsid,
|
||||||
|
p->name, p->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -618,6 +640,8 @@ struct ovl_readdir_translate {
|
|||||||
struct ovl_dir_cache *cache;
|
struct ovl_dir_cache *cache;
|
||||||
struct dir_context ctx;
|
struct dir_context ctx;
|
||||||
u64 parent_ino;
|
u64 parent_ino;
|
||||||
|
int fsid;
|
||||||
|
int xinobits;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ovl_fill_real(struct dir_context *ctx, const char *name,
|
static int ovl_fill_real(struct dir_context *ctx, const char *name,
|
||||||
@ -628,14 +652,17 @@ static int ovl_fill_real(struct dir_context *ctx, const char *name,
|
|||||||
container_of(ctx, struct ovl_readdir_translate, ctx);
|
container_of(ctx, struct ovl_readdir_translate, ctx);
|
||||||
struct dir_context *orig_ctx = rdt->orig_ctx;
|
struct dir_context *orig_ctx = rdt->orig_ctx;
|
||||||
|
|
||||||
if (rdt->parent_ino && strcmp(name, "..") == 0)
|
if (rdt->parent_ino && strcmp(name, "..") == 0) {
|
||||||
ino = rdt->parent_ino;
|
ino = rdt->parent_ino;
|
||||||
else if (rdt->cache) {
|
} else if (rdt->cache) {
|
||||||
struct ovl_cache_entry *p;
|
struct ovl_cache_entry *p;
|
||||||
|
|
||||||
p = ovl_cache_entry_find(&rdt->cache->root, name, namelen);
|
p = ovl_cache_entry_find(&rdt->cache->root, name, namelen);
|
||||||
if (p)
|
if (p)
|
||||||
ino = p->ino;
|
ino = p->ino;
|
||||||
|
} else if (rdt->xinobits) {
|
||||||
|
ino = ovl_remap_lower_ino(ino, rdt->xinobits, rdt->fsid,
|
||||||
|
name, namelen);
|
||||||
}
|
}
|
||||||
|
|
||||||
return orig_ctx->actor(orig_ctx, name, namelen, offset, ino, d_type);
|
return orig_ctx->actor(orig_ctx, name, namelen, offset, ino, d_type);
|
||||||
@ -646,11 +673,16 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
|
|||||||
int err;
|
int err;
|
||||||
struct ovl_dir_file *od = file->private_data;
|
struct ovl_dir_file *od = file->private_data;
|
||||||
struct dentry *dir = file->f_path.dentry;
|
struct dentry *dir = file->f_path.dentry;
|
||||||
|
struct ovl_layer *lower_layer = ovl_layer_lower(dir);
|
||||||
struct ovl_readdir_translate rdt = {
|
struct ovl_readdir_translate rdt = {
|
||||||
.ctx.actor = ovl_fill_real,
|
.ctx.actor = ovl_fill_real,
|
||||||
.orig_ctx = ctx,
|
.orig_ctx = ctx,
|
||||||
|
.xinobits = ovl_xino_bits(dir->d_sb),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (rdt.xinobits && lower_layer)
|
||||||
|
rdt.fsid = lower_layer->fsid;
|
||||||
|
|
||||||
if (OVL_TYPE_MERGE(ovl_path_type(dir->d_parent))) {
|
if (OVL_TYPE_MERGE(ovl_path_type(dir->d_parent))) {
|
||||||
struct kstat stat;
|
struct kstat stat;
|
||||||
struct path statpath = file->f_path;
|
struct path statpath = file->f_path;
|
||||||
@ -693,9 +725,10 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx)
|
|||||||
* dir is impure then need to adjust d_ino for copied up
|
* dir is impure then need to adjust d_ino for copied up
|
||||||
* entries.
|
* entries.
|
||||||
*/
|
*/
|
||||||
if (ovl_same_sb(dentry->d_sb) &&
|
if (ovl_xino_bits(dentry->d_sb) ||
|
||||||
(ovl_test_flag(OVL_IMPURE, d_inode(dentry)) ||
|
(ovl_same_sb(dentry->d_sb) &&
|
||||||
OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent)))) {
|
(ovl_test_flag(OVL_IMPURE, d_inode(dentry)) ||
|
||||||
|
OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent))))) {
|
||||||
return ovl_iterate_real(file, ctx);
|
return ovl_iterate_real(file, ctx);
|
||||||
}
|
}
|
||||||
return iterate_dir(od->realfile, ctx);
|
return iterate_dir(od->realfile, ctx);
|
||||||
|
Loading…
Reference in New Issue
Block a user