Commit 926e94d7 authored by Amir Goldstein's avatar Amir Goldstein Committed by Miklos Szeredi

ovl: enable xino automatically in more cases

So far, with xino=auto, we only enable xino if we know that all
underlying filesystem use 32bit inode numbers.

When users configure overlay with xino=auto, they already declare that
they are ready to handle 64bit inode number from overlay.

It is a very common case, that underlying filesystem uses 64bit ino,
but rarely or never uses the high inode number bits (e.g. tmpfs, xfs).
Leaving it for the users to declare high ino bits are unused with
xino=on is not a recipe for many users to enjoy the benefits of xino.

There appears to be very little reason not to enable xino when users
declare xino=auto even if we do not know how many bits underlying
filesystem uses for inode numbers.

In the worst case of xino bits overflow by real inode number, we
already fall back to the non-xino behavior - real inode number with
unique pseudo dev or to non persistent inode number and overlay st_dev
(for directories).

The only annoyance from auto enabling xino is that xino bits overflow
emits a warning to kmsg. Suppress those warnings unless users explicitly
asked for xino=on, suggesting that they expected high ino bits to be
unused by underlying filesystem.
Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent dfe51d47
...@@ -99,13 +99,13 @@ static int ovl_map_dev_ino(struct dentry *dentry, struct kstat *stat, int fsid) ...@@ -99,13 +99,13 @@ static int ovl_map_dev_ino(struct dentry *dentry, struct kstat *stat, int fsid)
* This way all overlay inode numbers are unique and use the * This way all overlay inode numbers are unique and use the
* overlay st_dev. * overlay st_dev.
*/ */
if (unlikely(stat->ino >> xinoshift)) { if (likely(!(stat->ino >> xinoshift))) {
pr_warn_ratelimited("inode number too big (%pd2, ino=%llu, xinobits=%d)\n",
dentry, stat->ino, xinobits);
} else {
stat->ino |= ((u64)fsid) << (xinoshift + 1); stat->ino |= ((u64)fsid) << (xinoshift + 1);
stat->dev = dentry->d_sb->s_dev; stat->dev = dentry->d_sb->s_dev;
return 0; return 0;
} else if (ovl_xino_warn(dentry->d_sb)) {
pr_warn_ratelimited("inode number too big (%pd2, ino=%llu, xinobits=%d)\n",
dentry, stat->ino, xinobits);
} }
} }
......
...@@ -48,6 +48,12 @@ enum ovl_entry_flag { ...@@ -48,6 +48,12 @@ enum ovl_entry_flag {
OVL_E_CONNECTED, OVL_E_CONNECTED,
}; };
enum {
OVL_XINO_OFF,
OVL_XINO_AUTO,
OVL_XINO_ON,
};
/* /*
* The tuple (fh,uuid) is a universal unique identifier for a copy up origin, * The tuple (fh,uuid) is a universal unique identifier for a copy up origin,
* where: * where:
...@@ -301,6 +307,16 @@ static inline bool ovl_is_impuredir(struct dentry *dentry) ...@@ -301,6 +307,16 @@ static inline bool ovl_is_impuredir(struct dentry *dentry)
return ovl_check_dir_xattr(dentry, OVL_XATTR_IMPURE); return ovl_check_dir_xattr(dentry, OVL_XATTR_IMPURE);
} }
/*
* With xino=auto, we do best effort to keep all inodes on same st_dev and
* d_ino consistent with st_ino.
* With xino=on, we do the same effort but we warn if we failed.
*/
static inline bool ovl_xino_warn(struct super_block *sb)
{
return OVL_FS(sb)->config.xino == OVL_XINO_ON;
}
/* All layers on same fs? */ /* All layers on same fs? */
static inline bool ovl_same_fs(struct super_block *sb) static inline bool ovl_same_fs(struct super_block *sb)
{ {
......
...@@ -438,13 +438,15 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry) ...@@ -438,13 +438,15 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
/* Map inode number to lower fs unique range */ /* Map inode number to lower fs unique range */
static u64 ovl_remap_lower_ino(u64 ino, int xinobits, int fsid, static u64 ovl_remap_lower_ino(u64 ino, int xinobits, int fsid,
const char *name, int namelen) const char *name, int namelen, bool warn)
{ {
unsigned int xinoshift = 64 - xinobits; unsigned int xinoshift = 64 - xinobits;
if (unlikely(ino >> xinoshift)) { if (unlikely(ino >> xinoshift)) {
pr_warn_ratelimited("d_ino too big (%.*s, ino=%llu, xinobits=%d)\n", if (warn) {
namelen, name, ino, xinobits); pr_warn_ratelimited("d_ino too big (%.*s, ino=%llu, xinobits=%d)\n",
namelen, name, ino, xinobits);
}
return ino; return ino;
} }
...@@ -521,7 +523,8 @@ static int ovl_cache_update_ino(struct path *path, struct ovl_cache_entry *p) ...@@ -521,7 +523,8 @@ static int ovl_cache_update_ino(struct path *path, struct ovl_cache_entry *p)
} else if (xinobits && !OVL_TYPE_UPPER(type)) { } else if (xinobits && !OVL_TYPE_UPPER(type)) {
ino = ovl_remap_lower_ino(ino, xinobits, ino = ovl_remap_lower_ino(ino, xinobits,
ovl_layer_lower(this)->fsid, ovl_layer_lower(this)->fsid,
p->name, p->len); p->name, p->len,
ovl_xino_warn(dir->d_sb));
} }
out: out:
...@@ -651,6 +654,7 @@ struct ovl_readdir_translate { ...@@ -651,6 +654,7 @@ struct ovl_readdir_translate {
u64 parent_ino; u64 parent_ino;
int fsid; int fsid;
int xinobits; int xinobits;
bool xinowarn;
}; };
static int ovl_fill_real(struct dir_context *ctx, const char *name, static int ovl_fill_real(struct dir_context *ctx, const char *name,
...@@ -671,7 +675,7 @@ static int ovl_fill_real(struct dir_context *ctx, const char *name, ...@@ -671,7 +675,7 @@ static int ovl_fill_real(struct dir_context *ctx, const char *name,
ino = p->ino; ino = p->ino;
} else if (rdt->xinobits) { } else if (rdt->xinobits) {
ino = ovl_remap_lower_ino(ino, rdt->xinobits, rdt->fsid, ino = ovl_remap_lower_ino(ino, rdt->xinobits, rdt->fsid,
name, namelen); name, namelen, rdt->xinowarn);
} }
return orig_ctx->actor(orig_ctx, name, namelen, offset, ino, d_type); return orig_ctx->actor(orig_ctx, name, namelen, offset, ino, d_type);
...@@ -702,6 +706,7 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx) ...@@ -702,6 +706,7 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
.ctx.actor = ovl_fill_real, .ctx.actor = ovl_fill_real,
.orig_ctx = ctx, .orig_ctx = ctx,
.xinobits = ovl_xino_bits(dir->d_sb), .xinobits = ovl_xino_bits(dir->d_sb),
.xinowarn = ovl_xino_warn(dir->d_sb),
}; };
if (rdt.xinobits && lower_layer) if (rdt.xinobits && lower_layer)
......
...@@ -317,12 +317,6 @@ static const char *ovl_redirect_mode_def(void) ...@@ -317,12 +317,6 @@ static const char *ovl_redirect_mode_def(void)
return ovl_redirect_dir_def ? "on" : "off"; return ovl_redirect_dir_def ? "on" : "off";
} }
enum {
OVL_XINO_OFF,
OVL_XINO_AUTO,
OVL_XINO_ON,
};
static const char * const ovl_xino_str[] = { static const char * const ovl_xino_str[] = {
"off", "off",
"auto", "auto",
...@@ -1479,8 +1473,8 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs, ...@@ -1479,8 +1473,8 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
/* /*
* When all layers on same fs, overlay can use real inode numbers. * When all layers on same fs, overlay can use real inode numbers.
* With mount option "xino=on", mounter declares that there are enough * With mount option "xino=<on|auto>", mounter declares that there are
* free high bits in underlying fs to hold the unique fsid. * enough free high bits in underlying fs to hold the unique fsid.
* If overlayfs does encounter underlying inodes using the high xino * If overlayfs does encounter underlying inodes using the high xino
* bits reserved for fsid, it emits a warning and uses the original * bits reserved for fsid, it emits a warning and uses the original
* inode number or a non persistent inode number allocated from a * inode number or a non persistent inode number allocated from a
...@@ -1492,7 +1486,7 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs, ...@@ -1492,7 +1486,7 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
ofs->xino_mode = 0; ofs->xino_mode = 0;
} else if (ofs->config.xino == OVL_XINO_OFF) { } else if (ofs->config.xino == OVL_XINO_OFF) {
ofs->xino_mode = -1; ofs->xino_mode = -1;
} else if (ofs->config.xino == OVL_XINO_ON && ofs->xino_mode < 0) { } else if (ofs->xino_mode < 0) {
/* /*
* This is a roundup of number of bits needed for encoding * This is a roundup of number of bits needed for encoding
* fsid, where fsid 0 is reserved for upper fs (even with * fsid, where fsid 0 is reserved for upper fs (even with
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment