Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs fixes from Miklos Szeredi: "Fix several issues, most of them introduced in the last release" * 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: ovl: do not cleanup unsupported index entries ovl: handle ENOENT on index lookup ovl: fix EIO from lookup of non-indexed upper ovl: Return -ENOMEM if an allocation fails ovl_lookup() ovl: add NULL check in ovl_alloc_inode
This commit is contained in:
commit
c9f27f9f85
|
@ -598,18 +598,30 @@ static bool ovl_verify_inode(struct inode *inode, struct dentry *lowerdentry,
|
|||
return true;
|
||||
}
|
||||
|
||||
struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry)
|
||||
struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry,
|
||||
struct dentry *index)
|
||||
{
|
||||
struct dentry *lowerdentry = ovl_dentry_lower(dentry);
|
||||
struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL;
|
||||
struct inode *inode;
|
||||
/* Already indexed or could be indexed on copy up? */
|
||||
bool indexed = (index || (ovl_indexdir(dentry->d_sb) && !upperdentry));
|
||||
|
||||
if (WARN_ON(upperdentry && indexed && !lowerdentry))
|
||||
return ERR_PTR(-EIO);
|
||||
|
||||
if (!realinode)
|
||||
realinode = d_inode(lowerdentry);
|
||||
|
||||
if (!S_ISDIR(realinode->i_mode) &&
|
||||
(upperdentry || (lowerdentry && ovl_indexdir(dentry->d_sb)))) {
|
||||
struct inode *key = d_inode(lowerdentry ?: upperdentry);
|
||||
/*
|
||||
* Copy up origin (lower) may exist for non-indexed upper, but we must
|
||||
* not use lower as hash key in that case.
|
||||
* Hash inodes that are or could be indexed by origin inode and
|
||||
* non-indexed upper inodes that could be hard linked by upper inode.
|
||||
*/
|
||||
if (!S_ISDIR(realinode->i_mode) && (upperdentry || indexed)) {
|
||||
struct inode *key = d_inode(indexed ? lowerdentry :
|
||||
upperdentry);
|
||||
unsigned int nlink;
|
||||
|
||||
inode = iget5_locked(dentry->d_sb, (unsigned long) key,
|
||||
|
|
|
@ -405,14 +405,13 @@ int ovl_verify_index(struct dentry *index, struct path *lowerstack,
|
|||
* be treated as stale (i.e. after unlink of the overlay inode).
|
||||
* We don't know the verification rules for directory and whiteout
|
||||
* index entries, because they have not been implemented yet, so return
|
||||
* EROFS if those entries are found to avoid corrupting an index that
|
||||
* was created by a newer kernel.
|
||||
* EINVAL if those entries are found to abort the mount to avoid
|
||||
* corrupting an index that was created by a newer kernel.
|
||||
*/
|
||||
err = -EROFS;
|
||||
err = -EINVAL;
|
||||
if (d_is_dir(index) || ovl_is_whiteout(index))
|
||||
goto fail;
|
||||
|
||||
err = -EINVAL;
|
||||
if (index->d_name.len < sizeof(struct ovl_fh)*2)
|
||||
goto fail;
|
||||
|
||||
|
@ -507,6 +506,10 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry,
|
|||
index = lookup_one_len_unlocked(name.name, ofs->indexdir, name.len);
|
||||
if (IS_ERR(index)) {
|
||||
err = PTR_ERR(index);
|
||||
if (err == -ENOENT) {
|
||||
index = NULL;
|
||||
goto out;
|
||||
}
|
||||
pr_warn_ratelimited("overlayfs: failed inode index lookup (ino=%lu, key=%*s, err=%i);\n"
|
||||
"overlayfs: mount with '-o index=off' to disable inodes index.\n",
|
||||
d_inode(origin)->i_ino, name.len, name.name,
|
||||
|
@ -516,18 +519,9 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry,
|
|||
|
||||
inode = d_inode(index);
|
||||
if (d_is_negative(index)) {
|
||||
if (upper && d_inode(origin)->i_nlink > 1) {
|
||||
pr_warn_ratelimited("overlayfs: hard link with origin but no index (ino=%lu).\n",
|
||||
d_inode(origin)->i_ino);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dput(index);
|
||||
index = NULL;
|
||||
goto out_dput;
|
||||
} else if (upper && d_inode(upper) != inode) {
|
||||
pr_warn_ratelimited("overlayfs: wrong index found (index=%pd2, ino=%lu, upper ino=%lu).\n",
|
||||
index, inode->i_ino, d_inode(upper)->i_ino);
|
||||
goto fail;
|
||||
goto out_dput;
|
||||
} else if (ovl_dentry_weird(index) || ovl_is_whiteout(index) ||
|
||||
((inode->i_mode ^ d_inode(origin)->i_mode) & S_IFMT)) {
|
||||
/*
|
||||
|
@ -547,6 +541,11 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry,
|
|||
kfree(name.name);
|
||||
return index;
|
||||
|
||||
out_dput:
|
||||
dput(index);
|
||||
index = NULL;
|
||||
goto out;
|
||||
|
||||
fail:
|
||||
dput(index);
|
||||
index = ERR_PTR(-EIO);
|
||||
|
@ -635,6 +634,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
|
|||
}
|
||||
|
||||
if (d.redirect) {
|
||||
err = -ENOMEM;
|
||||
upperredirect = kstrdup(d.redirect, GFP_KERNEL);
|
||||
if (!upperredirect)
|
||||
goto out_put_upper;
|
||||
|
@ -709,7 +709,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
|
|||
upperdentry = dget(index);
|
||||
|
||||
if (upperdentry || ctr) {
|
||||
inode = ovl_get_inode(dentry, upperdentry);
|
||||
inode = ovl_get_inode(dentry, upperdentry, index);
|
||||
err = PTR_ERR(inode);
|
||||
if (IS_ERR(inode))
|
||||
goto out_free_oe;
|
||||
|
|
|
@ -286,7 +286,8 @@ int ovl_update_time(struct inode *inode, struct timespec *ts, int flags);
|
|||
bool ovl_is_private_xattr(const char *name);
|
||||
|
||||
struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, dev_t rdev);
|
||||
struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry);
|
||||
struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry,
|
||||
struct dentry *index);
|
||||
static inline void ovl_copyattr(struct inode *from, struct inode *to)
|
||||
{
|
||||
to->i_uid = from->i_uid;
|
||||
|
|
|
@ -1021,13 +1021,12 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
|
|||
break;
|
||||
}
|
||||
err = ovl_verify_index(index, lowerstack, numlower);
|
||||
if (err) {
|
||||
if (err == -EROFS)
|
||||
break;
|
||||
/* Cleanup stale and orphan index entries */
|
||||
if (err && (err == -ESTALE || err == -ENOENT))
|
||||
err = ovl_cleanup(dir, index);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
if (err)
|
||||
break;
|
||||
|
||||
dput(index);
|
||||
index = NULL;
|
||||
}
|
||||
|
|
|
@ -174,6 +174,9 @@ static struct inode *ovl_alloc_inode(struct super_block *sb)
|
|||
{
|
||||
struct ovl_inode *oi = kmem_cache_alloc(ovl_inode_cachep, GFP_KERNEL);
|
||||
|
||||
if (!oi)
|
||||
return NULL;
|
||||
|
||||
oi->cache = NULL;
|
||||
oi->redirect = NULL;
|
||||
oi->version = 0;
|
||||
|
|
Loading…
Reference in New Issue