forked from Minki/linux
ovl: fix corner case of non-constant st_dev;st_ino
On non-samefs overlay without xino, non pure upper inodes should use a pseudo_dev assigned to each unique lower fs, but if lower layer is on the same fs and upper layer, it has no pseudo_dev assigned. In this overlay layers setup: - two filesystems, A and B - upper layer is on A - lower layer 1 is also on A - lower layer 2 is on B Non pure upper overlay inode, whose origin is in layer 1 will have the st_dev;st_ino values of the real lower inode before copy up and the st_dev;st_ino values of the real upper inode after copy up. Fix this inconsitency by assigning a unique pseudo_dev also for upper fs, that will be used as st_dev value along with the lower inode st_dev for overlay inodes in the case above. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
parent
1b81dddd35
commit
b7bf9908e1
@ -121,13 +121,12 @@ static int ovl_map_dev_ino(struct dentry *dentry, struct kstat *stat, int fsid)
|
|||||||
*/
|
*/
|
||||||
stat->dev = dentry->d_sb->s_dev;
|
stat->dev = dentry->d_sb->s_dev;
|
||||||
stat->ino = dentry->d_inode->i_ino;
|
stat->ino = dentry->d_inode->i_ino;
|
||||||
} else if (fsid) {
|
} else {
|
||||||
/*
|
/*
|
||||||
* For non-samefs setup, if we cannot map all layers st_ino
|
* For non-samefs setup, if we cannot map all layers st_ino
|
||||||
* to a unified address space, we need to make sure that st_dev
|
* to a unified address space, we need to make sure that st_dev
|
||||||
* is unique per lower fs. Upper layer uses real st_dev and
|
* is unique per underlying fs, so we use the unique anonymous
|
||||||
* lower layers use the unique anonymous bdev assigned to the
|
* bdev assigned to the underlying fs.
|
||||||
* lower fs.
|
|
||||||
*/
|
*/
|
||||||
stat->dev = OVL_FS(dentry->d_sb)->fs[fsid].pseudo_dev;
|
stat->dev = OVL_FS(dentry->d_sb)->fs[fsid].pseudo_dev;
|
||||||
}
|
}
|
||||||
@ -143,7 +142,6 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
|
|||||||
struct path realpath;
|
struct path realpath;
|
||||||
const struct cred *old_cred;
|
const struct cred *old_cred;
|
||||||
bool is_dir = S_ISDIR(dentry->d_inode->i_mode);
|
bool is_dir = S_ISDIR(dentry->d_inode->i_mode);
|
||||||
bool samefs = ovl_same_fs(dentry->d_sb);
|
|
||||||
int fsid = 0;
|
int fsid = 0;
|
||||||
int err;
|
int err;
|
||||||
bool metacopy_blocks = false;
|
bool metacopy_blocks = false;
|
||||||
@ -198,12 +196,6 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
|
|||||||
(!ovl_verify_lower(dentry->d_sb) &&
|
(!ovl_verify_lower(dentry->d_sb) &&
|
||||||
(is_dir || lowerstat.nlink == 1))) {
|
(is_dir || lowerstat.nlink == 1))) {
|
||||||
fsid = ovl_layer_lower(dentry)->fsid;
|
fsid = ovl_layer_lower(dentry)->fsid;
|
||||||
/*
|
|
||||||
* Cannot use origin st_dev;st_ino because
|
|
||||||
* origin inode content may differ from overlay
|
|
||||||
* inode content.
|
|
||||||
*/
|
|
||||||
if (samefs || fsid)
|
|
||||||
stat->ino = lowerstat.ino;
|
stat->ino = lowerstat.ino;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,8 +229,7 @@ static void ovl_free_fs(struct ovl_fs *ofs)
|
|||||||
mntput(ofs->layers[i].mnt);
|
mntput(ofs->layers[i].mnt);
|
||||||
}
|
}
|
||||||
kfree(ofs->layers);
|
kfree(ofs->layers);
|
||||||
/* fs[0].pseudo_dev is either null or real upper st_dev */
|
for (i = 0; i < ofs->numfs; i++)
|
||||||
for (i = 1; i < ofs->numfs; i++)
|
|
||||||
free_anon_bdev(ofs->fs[i].pseudo_dev);
|
free_anon_bdev(ofs->fs[i].pseudo_dev);
|
||||||
kfree(ofs->fs);
|
kfree(ofs->fs);
|
||||||
|
|
||||||
@ -1341,13 +1340,19 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
|
|||||||
ofs->numlayer = 1;
|
ofs->numlayer = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All lower layers that share the same fs as upper layer, use the real
|
* All lower layers that share the same fs as upper layer, use the same
|
||||||
* upper st_dev.
|
* pseudo_dev as upper layer. Allocate fs[0].pseudo_dev even for lower
|
||||||
|
* only overlay to simplify ovl_fs_free().
|
||||||
* is_lower will be set if upper fs is shared with a lower layer.
|
* is_lower will be set if upper fs is shared with a lower layer.
|
||||||
*/
|
*/
|
||||||
|
err = get_anon_bdev(&ofs->fs[0].pseudo_dev);
|
||||||
|
if (err) {
|
||||||
|
pr_err("failed to get anonymous bdev for upper fs\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (ofs->upper_mnt) {
|
if (ofs->upper_mnt) {
|
||||||
ofs->fs[0].sb = ofs->upper_mnt->mnt_sb;
|
ofs->fs[0].sb = ofs->upper_mnt->mnt_sb;
|
||||||
ofs->fs[0].pseudo_dev = ofs->upper_mnt->mnt_sb->s_dev;
|
|
||||||
ofs->fs[0].is_lower = false;
|
ofs->fs[0].is_lower = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user