Merge tag 'ovl-update-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs

Pull overlayfs update from Amir Goldstein:
 "Relax the semantics of uuid=off to cater to a use case of overlayfs
  lower layers on btrfs clones, whose UUID are ephemeral and an upper
  layer on a different filesystem"

* tag 'ovl-update-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs:
  ovl: relax requirement for uuid=off,index=on
This commit is contained in:
Linus Torvalds
2026-02-17 15:08:24 -08:00
4 changed files with 24 additions and 20 deletions

View File

@@ -753,9 +753,9 @@ Note: the mount options index=off,nfs_export=on are conflicting for a
read-write mount and will result in an error.
Note: the mount option uuid=off can be used to replace UUID of the underlying
filesystem in file handles with null, and effectively disable UUID checks. This
filesystem in file handles with null, in order to relax the UUID checks. This
can be useful in case the underlying disk is copied and the UUID of this copy
is changed. This is only applicable if all lower/upper/work directories are on
is changed. This is only applicable if all lower directories are on
the same filesystem, otherwise it will fallback to normal behaviour.
@@ -769,7 +769,7 @@ controlled by the "uuid" mount option, which supports these values:
UUID of overlayfs is null. fsid is taken from upper most filesystem.
- "off":
UUID of overlayfs is null. fsid is taken from upper most filesystem.
UUID of underlying layers is ignored.
UUID of underlying layers is ignored and null used instead.
- "on":
UUID of overlayfs is generated and used to report a unique fsid.
UUID is stored in xattr "trusted.overlay.uuid", making overlayfs fsid

View File

@@ -159,6 +159,18 @@ invalid:
goto out;
}
bool ovl_uuid_match(struct ovl_fs *ofs, const struct super_block *sb,
const uuid_t *uuid)
{
/*
* Make sure that the stored uuid matches the uuid of the lower
* layer where file handle will be decoded.
* In case of uuid=off option just make sure that stored uuid is null.
*/
return ovl_origin_uuid(ofs) ? uuid_equal(uuid, &sb->s_uuid) :
uuid_is_null(uuid);
}
struct dentry *ovl_decode_real_fh(struct ovl_fs *ofs, struct ovl_fh *fh,
struct vfsmount *mnt, bool connected)
{
@@ -168,14 +180,7 @@ struct dentry *ovl_decode_real_fh(struct ovl_fs *ofs, struct ovl_fh *fh,
if (!capable(CAP_DAC_READ_SEARCH))
return NULL;
/*
* Make sure that the stored uuid matches the uuid of the lower
* layer where file handle will be decoded.
* In case of uuid=off option just make sure that stored uuid is null.
*/
if (ovl_origin_uuid(ofs) ?
!uuid_equal(&fh->fb.uuid, &mnt->mnt_sb->s_uuid) :
!uuid_is_null(&fh->fb.uuid))
if (!ovl_uuid_match(ofs, mnt->mnt_sb, &fh->fb.uuid))
return NULL;
bytes = (fh->fb.len - offsetof(struct ovl_fb, fid));

View File

@@ -710,6 +710,8 @@ static inline int ovl_check_fh_len(struct ovl_fh *fh, int fh_len)
return ovl_check_fb_len(&fh->fb, fh_len - OVL_FH_WIRE_OFFSET);
}
bool ovl_uuid_match(struct ovl_fs *ofs, const struct super_block *sb,
const uuid_t *uuid);
struct dentry *ovl_decode_real_fh(struct ovl_fs *ofs, struct ovl_fh *fh,
struct vfsmount *mnt, bool connected);
int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected,

View File

@@ -940,7 +940,7 @@ static bool ovl_lower_uuid_ok(struct ovl_fs *ofs, const uuid_t *uuid)
* disable lower file handle decoding on all of them.
*/
if (ofs->fs[i].is_lower &&
uuid_equal(&ofs->fs[i].sb->s_uuid, uuid)) {
ovl_uuid_match(ofs, ofs->fs[i].sb, uuid)) {
ofs->fs[i].bad_uuid = true;
return false;
}
@@ -952,6 +952,7 @@ static bool ovl_lower_uuid_ok(struct ovl_fs *ofs, const uuid_t *uuid)
static int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path)
{
struct super_block *sb = path->mnt->mnt_sb;
const uuid_t *uuid = ovl_origin_uuid(ofs) ? &sb->s_uuid : &uuid_null;
unsigned int i;
dev_t dev;
int err;
@@ -963,7 +964,7 @@ static int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path)
return i;
}
if (!ovl_lower_uuid_ok(ofs, &sb->s_uuid)) {
if (!ovl_lower_uuid_ok(ofs, uuid)) {
bad_uuid = true;
if (ofs->config.xino == OVL_XINO_AUTO) {
ofs->config.xino = OVL_XINO_OFF;
@@ -975,9 +976,8 @@ static int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path)
warn = true;
}
if (warn) {
pr_warn("%s uuid detected in lower fs '%pd2', falling back to xino=%s,index=off,nfs_export=off.\n",
uuid_is_null(&sb->s_uuid) ? "null" :
"conflicting",
pr_warn("%s uuid in non-single lower fs '%pd2', falling back to xino=%s,index=off,nfs_export=off.\n",
uuid_is_null(uuid) ? "null" : "conflicting",
path->dentry, ovl_xino_mode(&ofs->config));
}
}
@@ -1469,10 +1469,7 @@ static int ovl_fill_super_creds(struct fs_context *fc, struct super_block *sb)
if (!ovl_upper_mnt(ofs))
sb->s_flags |= SB_RDONLY;
if (!ovl_origin_uuid(ofs) && ofs->numfs > 1) {
pr_warn("The uuid=off requires a single fs for lower and upper, falling back to uuid=null.\n");
ofs->config.uuid = OVL_UUID_NULL;
} else if (ovl_has_fsid(ofs) && ovl_upper_mnt(ofs)) {
if (ovl_has_fsid(ofs) && ovl_upper_mnt(ofs)) {
/* Use per instance persistent uuid/fsid */
ovl_init_uuid_xattr(sb, ofs, &ctx->upper);
}