2019-06-04 16:11:33 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Copyright (C) 2011 Novell Inc.
|
|
|
|
*/
|
|
|
|
|
2017-02-03 00:54:15 +08:00
|
|
|
#include <uapi/linux/magic.h>
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/namei.h>
|
|
|
|
#include <linux/xattr.h>
|
|
|
|
#include <linux/mount.h>
|
|
|
|
#include <linux/parser.h>
|
|
|
|
#include <linux/module.h>
|
2014-10-24 06:14:38 +08:00
|
|
|
#include <linux/statfs.h>
|
2014-10-24 06:14:38 +08:00
|
|
|
#include <linux/seq_file.h>
|
2016-07-29 18:05:24 +08:00
|
|
|
#include <linux/posix_acl_xattr.h>
|
2017-11-07 19:55:04 +08:00
|
|
|
#include <linux/exportfs.h>
|
2022-09-24 13:00:00 +08:00
|
|
|
#include <linux/file.h>
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
#include "overlayfs.h"
|
|
|
|
|
|
|
|
MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
|
|
|
|
MODULE_DESCRIPTION("Overlay filesystem");
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
|
|
|
|
|
|
|
|
struct ovl_dir_cache;
|
|
|
|
|
2014-12-13 07:59:52 +08:00
|
|
|
#define OVL_MAX_STACK 500
|
|
|
|
|
2016-12-16 18:02:57 +08:00
|
|
|
static bool ovl_redirect_dir_def = IS_ENABLED(CONFIG_OVERLAY_FS_REDIRECT_DIR);
|
|
|
|
module_param_named(redirect_dir, ovl_redirect_dir_def, bool, 0644);
|
2019-06-17 15:39:00 +08:00
|
|
|
MODULE_PARM_DESC(redirect_dir,
|
2016-12-16 18:02:57 +08:00
|
|
|
"Default to on or off for the redirect_dir feature");
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
|
2017-12-11 18:28:10 +08:00
|
|
|
static bool ovl_redirect_always_follow =
|
|
|
|
IS_ENABLED(CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW);
|
|
|
|
module_param_named(redirect_always_follow, ovl_redirect_always_follow,
|
|
|
|
bool, 0644);
|
2019-06-17 15:39:00 +08:00
|
|
|
MODULE_PARM_DESC(redirect_always_follow,
|
2017-12-11 18:28:10 +08:00
|
|
|
"Follow redirects even if redirect_dir feature is turned off");
|
|
|
|
|
2017-06-21 20:28:36 +08:00
|
|
|
static bool ovl_index_def = IS_ENABLED(CONFIG_OVERLAY_FS_INDEX);
|
|
|
|
module_param_named(index, ovl_index_def, bool, 0644);
|
2019-06-17 15:39:00 +08:00
|
|
|
MODULE_PARM_DESC(index,
|
2017-06-21 20:28:36 +08:00
|
|
|
"Default to on or off for the inodes index feature");
|
|
|
|
|
2018-01-19 17:26:53 +08:00
|
|
|
static bool ovl_nfs_export_def = IS_ENABLED(CONFIG_OVERLAY_FS_NFS_EXPORT);
|
|
|
|
module_param_named(nfs_export, ovl_nfs_export_def, bool, 0644);
|
2019-06-17 15:39:00 +08:00
|
|
|
MODULE_PARM_DESC(nfs_export,
|
2018-01-19 17:26:53 +08:00
|
|
|
"Default to on or off for the NFS export feature");
|
|
|
|
|
2018-03-29 14:08:18 +08:00
|
|
|
static bool ovl_xino_auto_def = IS_ENABLED(CONFIG_OVERLAY_FS_XINO_AUTO);
|
|
|
|
module_param_named(xino_auto, ovl_xino_auto_def, bool, 0644);
|
2019-06-17 15:39:00 +08:00
|
|
|
MODULE_PARM_DESC(xino_auto,
|
2018-03-29 14:08:18 +08:00
|
|
|
"Auto enable xino feature");
|
|
|
|
|
2017-11-10 16:39:15 +08:00
|
|
|
static void ovl_entry_stack_free(struct ovl_entry *oe)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < oe->numlower; i++)
|
|
|
|
dput(oe->lowerstack[i].dentry);
|
|
|
|
}
|
|
|
|
|
2018-05-11 23:49:27 +08:00
|
|
|
static bool ovl_metacopy_def = IS_ENABLED(CONFIG_OVERLAY_FS_METACOPY);
|
|
|
|
module_param_named(metacopy, ovl_metacopy_def, bool, 0644);
|
2019-06-17 15:39:00 +08:00
|
|
|
MODULE_PARM_DESC(metacopy,
|
2018-05-11 23:49:27 +08:00
|
|
|
"Default to on or off for the metadata only copy up feature");
|
|
|
|
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
static void ovl_dentry_release(struct dentry *dentry)
|
|
|
|
{
|
|
|
|
struct ovl_entry *oe = dentry->d_fsdata;
|
|
|
|
|
|
|
|
if (oe) {
|
2017-11-10 16:39:15 +08:00
|
|
|
ovl_entry_stack_free(oe);
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
kfree_rcu(oe, rcu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-30 14:53:27 +08:00
|
|
|
static struct dentry *ovl_d_real(struct dentry *dentry,
|
2018-07-18 21:44:44 +08:00
|
|
|
const struct inode *inode)
|
2016-03-27 04:14:37 +08:00
|
|
|
{
|
2020-11-12 18:31:55 +08:00
|
|
|
struct dentry *real = NULL, *lower;
|
2016-03-27 04:14:37 +08:00
|
|
|
|
2018-07-18 21:44:41 +08:00
|
|
|
/* It's an overlay file */
|
|
|
|
if (inode && d_inode(dentry) == inode)
|
|
|
|
return dentry;
|
|
|
|
|
2016-12-16 18:02:55 +08:00
|
|
|
if (!d_is_reg(dentry)) {
|
2016-03-27 04:14:37 +08:00
|
|
|
if (!inode || inode == d_inode(dentry))
|
|
|
|
return dentry;
|
|
|
|
goto bug;
|
|
|
|
}
|
|
|
|
|
|
|
|
real = ovl_dentry_upper(dentry);
|
2018-05-11 23:49:31 +08:00
|
|
|
if (real && (inode == d_inode(real)))
|
2016-03-27 04:14:37 +08:00
|
|
|
return real;
|
|
|
|
|
2018-05-11 23:49:31 +08:00
|
|
|
if (real && !inode && ovl_has_upperdata(d_inode(dentry)))
|
|
|
|
return real;
|
|
|
|
|
2020-11-12 18:31:55 +08:00
|
|
|
lower = ovl_dentry_lowerdata(dentry);
|
|
|
|
if (!lower)
|
2016-03-27 04:14:37 +08:00
|
|
|
goto bug;
|
2020-11-12 18:31:55 +08:00
|
|
|
real = lower;
|
2016-03-27 04:14:37 +08:00
|
|
|
|
2016-11-29 17:20:24 +08:00
|
|
|
/* Handle recursion */
|
2018-07-18 21:44:44 +08:00
|
|
|
real = d_real(real, inode);
|
2016-11-29 17:20:24 +08:00
|
|
|
|
2016-03-27 04:14:37 +08:00
|
|
|
if (!inode || inode == d_inode(real))
|
|
|
|
return real;
|
|
|
|
bug:
|
2020-11-12 18:31:55 +08:00
|
|
|
WARN(1, "%s(%pd4, %s:%lu): real dentry (%p/%lu) not found\n",
|
|
|
|
__func__, dentry, inode ? inode->i_sb->s_id : "NULL",
|
|
|
|
inode ? inode->i_ino : 0, real,
|
|
|
|
real && d_inode(real) ? d_inode(real)->i_ino : 0);
|
2016-03-27 04:14:37 +08:00
|
|
|
return dentry;
|
|
|
|
}
|
|
|
|
|
2020-03-17 22:04:22 +08:00
|
|
|
static int ovl_revalidate_real(struct dentry *d, unsigned int flags, bool weak)
|
2015-06-22 19:53:48 +08:00
|
|
|
{
|
|
|
|
int ret = 1;
|
|
|
|
|
2020-03-17 22:04:22 +08:00
|
|
|
if (weak) {
|
|
|
|
if (d->d_flags & DCACHE_OP_WEAK_REVALIDATE)
|
|
|
|
ret = d->d_op->d_weak_revalidate(d, flags);
|
|
|
|
} else if (d->d_flags & DCACHE_OP_REVALIDATE) {
|
|
|
|
ret = d->d_op->d_revalidate(d, flags);
|
|
|
|
if (!ret) {
|
|
|
|
if (!(flags & LOOKUP_RCU))
|
|
|
|
d_invalidate(d);
|
|
|
|
ret = -ESTALE;
|
2015-06-22 19:53:48 +08:00
|
|
|
}
|
|
|
|
}
|
2020-03-17 22:04:22 +08:00
|
|
|
return ret;
|
2015-06-22 19:53:48 +08:00
|
|
|
}
|
|
|
|
|
2020-03-17 22:04:22 +08:00
|
|
|
static int ovl_dentry_revalidate_common(struct dentry *dentry,
|
|
|
|
unsigned int flags, bool weak)
|
2015-06-22 19:53:48 +08:00
|
|
|
{
|
|
|
|
struct ovl_entry *oe = dentry->d_fsdata;
|
2020-03-17 22:04:22 +08:00
|
|
|
struct dentry *upper;
|
2015-06-22 19:53:48 +08:00
|
|
|
unsigned int i;
|
|
|
|
int ret = 1;
|
|
|
|
|
2020-03-17 22:04:22 +08:00
|
|
|
upper = ovl_dentry_upper(dentry);
|
|
|
|
if (upper)
|
|
|
|
ret = ovl_revalidate_real(upper, flags, weak);
|
|
|
|
|
2020-03-17 22:04:22 +08:00
|
|
|
for (i = 0; ret > 0 && i < oe->numlower; i++) {
|
|
|
|
ret = ovl_revalidate_real(oe->lowerstack[i].dentry, flags,
|
|
|
|
weak);
|
2015-06-22 19:53:48 +08:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-03-17 22:04:22 +08:00
|
|
|
static int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags)
|
|
|
|
{
|
|
|
|
return ovl_dentry_revalidate_common(dentry, flags, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags)
|
|
|
|
{
|
|
|
|
return ovl_dentry_revalidate_common(dentry, flags, true);
|
|
|
|
}
|
|
|
|
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
static const struct dentry_operations ovl_dentry_operations = {
|
|
|
|
.d_release = ovl_dentry_release,
|
2016-03-27 04:14:37 +08:00
|
|
|
.d_real = ovl_d_real,
|
2015-06-22 19:53:48 +08:00
|
|
|
.d_revalidate = ovl_dentry_revalidate,
|
|
|
|
.d_weak_revalidate = ovl_dentry_weak_revalidate,
|
|
|
|
};
|
|
|
|
|
2017-06-12 14:54:40 +08:00
|
|
|
static struct kmem_cache *ovl_inode_cachep;
|
|
|
|
|
|
|
|
static struct inode *ovl_alloc_inode(struct super_block *sb)
|
|
|
|
{
|
2022-03-23 05:41:03 +08:00
|
|
|
struct ovl_inode *oi = alloc_inode_sb(sb, ovl_inode_cachep, GFP_KERNEL);
|
2017-06-12 14:54:40 +08:00
|
|
|
|
2017-09-26 02:09:53 +08:00
|
|
|
if (!oi)
|
|
|
|
return NULL;
|
|
|
|
|
2017-07-05 04:03:16 +08:00
|
|
|
oi->cache = NULL;
|
2017-07-05 04:03:16 +08:00
|
|
|
oi->redirect = NULL;
|
2017-07-05 04:03:16 +08:00
|
|
|
oi->version = 0;
|
2017-07-05 04:03:16 +08:00
|
|
|
oi->flags = 0;
|
2017-07-05 04:03:16 +08:00
|
|
|
oi->__upperdentry = NULL;
|
2022-04-04 18:51:53 +08:00
|
|
|
oi->lowerpath.dentry = NULL;
|
|
|
|
oi->lowerpath.layer = NULL;
|
2018-05-11 23:49:30 +08:00
|
|
|
oi->lowerdata = NULL;
|
2017-06-21 20:28:51 +08:00
|
|
|
mutex_init(&oi->lock);
|
2017-07-05 04:03:16 +08:00
|
|
|
|
2017-06-12 14:54:40 +08:00
|
|
|
return &oi->vfs_inode;
|
|
|
|
}
|
|
|
|
|
2019-04-16 10:52:17 +08:00
|
|
|
static void ovl_free_inode(struct inode *inode)
|
2017-06-12 14:54:40 +08:00
|
|
|
{
|
2019-04-16 10:52:17 +08:00
|
|
|
struct ovl_inode *oi = OVL_I(inode);
|
2017-06-12 14:54:40 +08:00
|
|
|
|
2019-04-16 10:52:17 +08:00
|
|
|
kfree(oi->redirect);
|
|
|
|
mutex_destroy(&oi->lock);
|
|
|
|
kmem_cache_free(ovl_inode_cachep, oi);
|
2017-06-12 14:54:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ovl_destroy_inode(struct inode *inode)
|
|
|
|
{
|
2017-07-05 04:03:16 +08:00
|
|
|
struct ovl_inode *oi = OVL_I(inode);
|
|
|
|
|
|
|
|
dput(oi->__upperdentry);
|
2022-04-04 18:51:53 +08:00
|
|
|
dput(oi->lowerpath.dentry);
|
2018-05-11 23:49:30 +08:00
|
|
|
if (S_ISDIR(inode->i_mode))
|
|
|
|
ovl_dir_cache_free(inode);
|
|
|
|
else
|
|
|
|
iput(oi->lowerdata);
|
2017-06-12 14:54:40 +08:00
|
|
|
}
|
|
|
|
|
2017-11-10 16:39:16 +08:00
|
|
|
static void ovl_free_fs(struct ovl_fs *ofs)
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
{
|
2020-06-04 16:48:19 +08:00
|
|
|
struct vfsmount **mounts;
|
2014-12-13 07:59:43 +08:00
|
|
|
unsigned i;
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
|
2019-07-12 20:24:34 +08:00
|
|
|
iput(ofs->workbasedir_trap);
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
iput(ofs->indexdir_trap);
|
|
|
|
iput(ofs->workdir_trap);
|
2020-04-24 10:55:17 +08:00
|
|
|
dput(ofs->whiteout);
|
2017-11-10 16:39:16 +08:00
|
|
|
dput(ofs->indexdir);
|
|
|
|
dput(ofs->workdir);
|
|
|
|
if (ofs->workdir_locked)
|
|
|
|
ovl_inuse_unlock(ofs->workbasedir);
|
|
|
|
dput(ofs->workbasedir);
|
|
|
|
if (ofs->upperdir_locked)
|
2020-06-04 16:48:19 +08:00
|
|
|
ovl_inuse_unlock(ovl_upper_mnt(ofs)->mnt_root);
|
2020-06-04 16:48:19 +08:00
|
|
|
|
|
|
|
/* Hack! Reuse ofs->layers as a vfsmount array before freeing it */
|
|
|
|
mounts = (struct vfsmount **) ofs->layers;
|
2020-06-04 16:48:19 +08:00
|
|
|
for (i = 0; i < ofs->numlayer; i++) {
|
2019-11-15 20:12:40 +08:00
|
|
|
iput(ofs->layers[i].trap);
|
2020-06-04 16:48:19 +08:00
|
|
|
mounts[i] = ofs->layers[i].mnt;
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
}
|
2020-06-04 16:48:19 +08:00
|
|
|
kern_unmount_array(mounts, ofs->numlayer);
|
2019-11-15 20:12:40 +08:00
|
|
|
kfree(ofs->layers);
|
2020-01-15 04:17:25 +08:00
|
|
|
for (i = 0; i < ofs->numfs; i++)
|
2020-01-15 03:59:22 +08:00
|
|
|
free_anon_bdev(ofs->fs[i].pseudo_dev);
|
|
|
|
kfree(ofs->fs);
|
2017-11-10 16:39:16 +08:00
|
|
|
|
|
|
|
kfree(ofs->config.lowerdir);
|
|
|
|
kfree(ofs->config.upperdir);
|
|
|
|
kfree(ofs->config.workdir);
|
2017-12-11 18:28:10 +08:00
|
|
|
kfree(ofs->config.redirect_mode);
|
2017-11-10 16:39:16 +08:00
|
|
|
if (ofs->creator_cred)
|
|
|
|
put_cred(ofs->creator_cred);
|
|
|
|
kfree(ofs);
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
}
|
|
|
|
|
2017-11-10 16:39:15 +08:00
|
|
|
static void ovl_put_super(struct super_block *sb)
|
|
|
|
{
|
|
|
|
struct ovl_fs *ofs = sb->s_fs_info;
|
|
|
|
|
|
|
|
ovl_free_fs(ofs);
|
|
|
|
}
|
|
|
|
|
2017-11-29 10:01:32 +08:00
|
|
|
/* Sync real dirty inodes in upper filesystem (if it exists) */
|
2017-01-23 20:32:21 +08:00
|
|
|
static int ovl_sync_fs(struct super_block *sb, int wait)
|
|
|
|
{
|
2017-11-10 16:39:16 +08:00
|
|
|
struct ovl_fs *ofs = sb->s_fs_info;
|
2017-01-23 20:32:21 +08:00
|
|
|
struct super_block *upper_sb;
|
|
|
|
int ret;
|
|
|
|
|
ovl: implement volatile-specific fsync error behaviour
Overlayfs's volatile option allows the user to bypass all forced sync calls
to the upperdir filesystem. This comes at the cost of safety. We can never
ensure that the user's data is intact, but we can make a best effort to
expose whether or not the data is likely to be in a bad state.
The best way to handle this in the time being is that if an overlayfs's
upperdir experiences an error after a volatile mount occurs, that error
will be returned on fsync, fdatasync, sync, and syncfs. This is
contradictory to the traditional behaviour of VFS which fails the call
once, and only raises an error if a subsequent fsync error has occurred,
and been raised by the filesystem.
One awkward aspect of the patch is that we have to manually set the
superblock's errseq_t after the sync_fs callback as opposed to just
returning an error from syncfs. This is because the call chain looks
something like this:
sys_syncfs ->
sync_filesystem ->
__sync_filesystem ->
/* The return value is ignored here
sb->s_op->sync_fs(sb)
_sync_blockdev
/* Where the VFS fetches the error to raise to userspace */
errseq_check_and_advance
Because of this we call errseq_set every time the sync_fs callback occurs.
Due to the nature of this seen / unseen dichotomy, if the upperdir is an
inconsistent state at the initial mount time, overlayfs will refuse to
mount, as overlayfs cannot get a snapshot of the upperdir's errseq that
will increment on error until the user calls syncfs.
Signed-off-by: Sargun Dhillon <sargun@sargun.me>
Suggested-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Fixes: c86243b090bc ("ovl: provide a mount option "volatile"")
Cc: stable@vger.kernel.org
Reviewed-by: Vivek Goyal <vgoyal@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2021-01-08 08:10:43 +08:00
|
|
|
ret = ovl_sync_status(ofs);
|
|
|
|
/*
|
|
|
|
* We have to always set the err, because the return value isn't
|
|
|
|
* checked in syncfs, and instead indirectly return an error via
|
|
|
|
* the sb's writeback errseq, which VFS inspects after this call.
|
|
|
|
*/
|
|
|
|
if (ret < 0) {
|
|
|
|
errseq_set(&sb->s_wb_err, -EIO);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
return ret;
|
2017-11-29 10:01:32 +08:00
|
|
|
|
|
|
|
/*
|
2020-04-09 16:29:47 +08:00
|
|
|
* Not called for sync(2) call or an emergency sync (SB_I_SKIP_SYNC).
|
|
|
|
* All the super blocks will be iterated, including upper_sb.
|
2017-11-29 10:01:32 +08:00
|
|
|
*
|
|
|
|
* If this is a syncfs(2) call, then we do need to call
|
|
|
|
* sync_filesystem() on upper_sb, but enough if we do it when being
|
|
|
|
* called with wait == 1.
|
|
|
|
*/
|
|
|
|
if (!wait)
|
2017-01-23 20:32:21 +08:00
|
|
|
return 0;
|
|
|
|
|
2020-06-04 16:48:19 +08:00
|
|
|
upper_sb = ovl_upper_mnt(ofs)->mnt_sb;
|
2017-11-29 10:01:32 +08:00
|
|
|
|
2017-01-23 20:32:21 +08:00
|
|
|
down_read(&upper_sb->s_umount);
|
2017-11-29 10:01:32 +08:00
|
|
|
ret = sync_filesystem(upper_sb);
|
2017-01-23 20:32:21 +08:00
|
|
|
up_read(&upper_sb->s_umount);
|
2017-11-29 10:01:32 +08:00
|
|
|
|
2017-01-23 20:32:21 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-10-24 06:14:38 +08:00
|
|
|
/**
|
|
|
|
* ovl_statfs
|
2022-06-01 10:28:14 +08:00
|
|
|
* @dentry: The dentry to query
|
2014-10-24 06:14:38 +08:00
|
|
|
* @buf: The struct kstatfs to fill in with stats
|
|
|
|
*
|
|
|
|
* Get the filesystem statistics. As writes always target the upper layer
|
2014-12-13 07:59:46 +08:00
|
|
|
* filesystem pass the statfs to the upper filesystem (if it exists)
|
2014-10-24 06:14:38 +08:00
|
|
|
*/
|
|
|
|
static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|
|
|
{
|
|
|
|
struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
|
|
|
|
struct dentry *root_dentry = dentry->d_sb->s_root;
|
|
|
|
struct path path;
|
|
|
|
int err;
|
|
|
|
|
2014-12-13 07:59:46 +08:00
|
|
|
ovl_path_real(root_dentry, &path);
|
2014-10-24 06:14:38 +08:00
|
|
|
|
|
|
|
err = vfs_statfs(&path, buf);
|
|
|
|
if (!err) {
|
2016-12-16 18:02:56 +08:00
|
|
|
buf->f_namelen = ofs->namelen;
|
2014-10-24 06:14:38 +08:00
|
|
|
buf->f_type = OVERLAYFS_SUPER_MAGIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2017-06-21 20:28:36 +08:00
|
|
|
/* Will this overlay be forced to mount/remount ro? */
|
2017-11-10 16:39:16 +08:00
|
|
|
static bool ovl_force_readonly(struct ovl_fs *ofs)
|
2017-06-21 20:28:36 +08:00
|
|
|
{
|
2020-06-04 16:48:19 +08:00
|
|
|
return (!ovl_upper_mnt(ofs) || !ofs->workdir);
|
2017-06-21 20:28:36 +08:00
|
|
|
}
|
|
|
|
|
2017-12-11 18:28:10 +08:00
|
|
|
static const char *ovl_redirect_mode_def(void)
|
|
|
|
{
|
|
|
|
return ovl_redirect_dir_def ? "on" : "off";
|
|
|
|
}
|
|
|
|
|
2018-03-29 14:08:18 +08:00
|
|
|
static const char * const ovl_xino_str[] = {
|
|
|
|
"off",
|
|
|
|
"auto",
|
|
|
|
"on",
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline int ovl_xino_def(void)
|
|
|
|
{
|
|
|
|
return ovl_xino_auto_def ? OVL_XINO_AUTO : OVL_XINO_OFF;
|
|
|
|
}
|
|
|
|
|
2014-10-24 06:14:38 +08:00
|
|
|
/**
|
|
|
|
* ovl_show_options
|
2022-06-01 10:28:14 +08:00
|
|
|
* @m: the seq_file handle
|
|
|
|
* @dentry: The dentry to query
|
2014-10-24 06:14:38 +08:00
|
|
|
*
|
|
|
|
* Prints the mount options for a given superblock.
|
|
|
|
* Returns zero; does not fail.
|
|
|
|
*/
|
|
|
|
static int ovl_show_options(struct seq_file *m, struct dentry *dentry)
|
|
|
|
{
|
|
|
|
struct super_block *sb = dentry->d_sb;
|
2017-11-10 16:39:16 +08:00
|
|
|
struct ovl_fs *ofs = sb->s_fs_info;
|
2014-10-24 06:14:38 +08:00
|
|
|
|
2017-11-10 16:39:16 +08:00
|
|
|
seq_show_option(m, "lowerdir", ofs->config.lowerdir);
|
|
|
|
if (ofs->config.upperdir) {
|
|
|
|
seq_show_option(m, "upperdir", ofs->config.upperdir);
|
|
|
|
seq_show_option(m, "workdir", ofs->config.workdir);
|
2014-12-13 07:59:51 +08:00
|
|
|
}
|
2017-11-10 16:39:16 +08:00
|
|
|
if (ofs->config.default_permissions)
|
2015-10-12 23:11:44 +08:00
|
|
|
seq_puts(m, ",default_permissions");
|
2017-12-11 18:28:10 +08:00
|
|
|
if (strcmp(ofs->config.redirect_mode, ovl_redirect_mode_def()) != 0)
|
|
|
|
seq_printf(m, ",redirect_dir=%s", ofs->config.redirect_mode);
|
2017-11-10 16:39:16 +08:00
|
|
|
if (ofs->config.index != ovl_index_def)
|
2017-12-11 18:28:10 +08:00
|
|
|
seq_printf(m, ",index=%s", ofs->config.index ? "on" : "off");
|
ovl: introduce new "uuid=off" option for inodes index feature
This replaces uuid with null in overlayfs file handles and thus relaxes
uuid checks for overlay index feature. It is only possible in case there is
only one filesystem for all the work/upper/lower directories and bare file
handles from this backing filesystem are unique. In other case when we have
multiple filesystems lets just fallback to "uuid=on" which is and
equivalent of how it worked before with all uuid checks.
This is needed when overlayfs is/was mounted in a container with index
enabled (e.g.: to be able to resolve inotify watch file handles on it to
paths in CRIU), and this container is copied and started alongside with the
original one. This way the "copy" container can't have the same uuid on the
superblock and mounting the overlayfs from it later would fail.
That is an example of the problem on top of loop+ext4:
dd if=/dev/zero of=loopbackfile.img bs=100M count=10
losetup -fP loopbackfile.img
losetup -a
#/dev/loop0: [64768]:35 (/loop-test/loopbackfile.img)
mkfs.ext4 loopbackfile.img
mkdir loop-mp
mount -o loop /dev/loop0 loop-mp
mkdir loop-mp/{lower,upper,work,merged}
mount -t overlay overlay -oindex=on,lowerdir=loop-mp/lower,\
upperdir=loop-mp/upper,workdir=loop-mp/work loop-mp/merged
umount loop-mp/merged
umount loop-mp
e2fsck -f /dev/loop0
tune2fs -U random /dev/loop0
mount -o loop /dev/loop0 loop-mp
mount -t overlay overlay -oindex=on,lowerdir=loop-mp/lower,\
upperdir=loop-mp/upper,workdir=loop-mp/work loop-mp/merged
#mount: /loop-test/loop-mp/merged:
#mount(2) system call failed: Stale file handle.
If you just change the uuid of the backing filesystem, overlay is not
mounting any more. In Virtuozzo we copy container disks (ploops) when
create the copy of container and we require fs uuid to be unique for a new
container.
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2020-10-13 22:59:54 +08:00
|
|
|
if (!ofs->config.uuid)
|
|
|
|
seq_puts(m, ",uuid=off");
|
2018-01-19 17:26:53 +08:00
|
|
|
if (ofs->config.nfs_export != ovl_nfs_export_def)
|
|
|
|
seq_printf(m, ",nfs_export=%s", ofs->config.nfs_export ?
|
|
|
|
"on" : "off");
|
2019-11-17 00:14:41 +08:00
|
|
|
if (ofs->config.xino != ovl_xino_def() && !ovl_same_fs(sb))
|
2018-03-29 14:08:18 +08:00
|
|
|
seq_printf(m, ",xino=%s", ovl_xino_str[ofs->config.xino]);
|
2018-05-11 23:49:27 +08:00
|
|
|
if (ofs->config.metacopy != ovl_metacopy_def)
|
|
|
|
seq_printf(m, ",metacopy=%s",
|
|
|
|
ofs->config.metacopy ? "on" : "off");
|
2020-09-01 02:15:29 +08:00
|
|
|
if (ofs->config.ovl_volatile)
|
|
|
|
seq_puts(m, ",volatile");
|
2021-03-05 00:45:15 +08:00
|
|
|
if (ofs->config.userxattr)
|
|
|
|
seq_puts(m, ",userxattr");
|
2014-10-24 06:14:38 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-03 01:26:49 +08:00
|
|
|
static int ovl_remount(struct super_block *sb, int *flags, char *data)
|
|
|
|
{
|
2017-11-10 16:39:16 +08:00
|
|
|
struct ovl_fs *ofs = sb->s_fs_info;
|
2020-04-22 12:28:43 +08:00
|
|
|
struct super_block *upper_sb;
|
|
|
|
int ret = 0;
|
2015-01-03 01:26:49 +08:00
|
|
|
|
2017-11-28 05:05:09 +08:00
|
|
|
if (!(*flags & SB_RDONLY) && ovl_force_readonly(ofs))
|
2015-01-03 01:26:49 +08:00
|
|
|
return -EROFS;
|
|
|
|
|
2020-04-22 12:28:43 +08:00
|
|
|
if (*flags & SB_RDONLY && !sb_rdonly(sb)) {
|
2020-06-04 16:48:19 +08:00
|
|
|
upper_sb = ovl_upper_mnt(ofs)->mnt_sb;
|
2020-09-01 02:15:29 +08:00
|
|
|
if (ovl_should_sync(ofs)) {
|
|
|
|
down_read(&upper_sb->s_umount);
|
|
|
|
ret = sync_filesystem(upper_sb);
|
|
|
|
up_read(&upper_sb->s_umount);
|
|
|
|
}
|
2020-04-22 12:28:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2015-01-03 01:26:49 +08:00
|
|
|
}
|
|
|
|
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
static const struct super_operations ovl_super_operations = {
|
2017-06-12 14:54:40 +08:00
|
|
|
.alloc_inode = ovl_alloc_inode,
|
2019-04-16 10:52:17 +08:00
|
|
|
.free_inode = ovl_free_inode,
|
2017-06-12 14:54:40 +08:00
|
|
|
.destroy_inode = ovl_destroy_inode,
|
|
|
|
.drop_inode = generic_delete_inode,
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
.put_super = ovl_put_super,
|
2017-01-23 20:32:21 +08:00
|
|
|
.sync_fs = ovl_sync_fs,
|
2014-10-24 06:14:38 +08:00
|
|
|
.statfs = ovl_statfs,
|
2014-10-24 06:14:38 +08:00
|
|
|
.show_options = ovl_show_options,
|
2015-01-03 01:26:49 +08:00
|
|
|
.remount_fs = ovl_remount,
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
OPT_LOWERDIR,
|
|
|
|
OPT_UPPERDIR,
|
|
|
|
OPT_WORKDIR,
|
2015-10-12 23:11:44 +08:00
|
|
|
OPT_DEFAULT_PERMISSIONS,
|
2017-12-11 18:28:10 +08:00
|
|
|
OPT_REDIRECT_DIR,
|
2017-06-21 20:28:36 +08:00
|
|
|
OPT_INDEX_ON,
|
|
|
|
OPT_INDEX_OFF,
|
ovl: introduce new "uuid=off" option for inodes index feature
This replaces uuid with null in overlayfs file handles and thus relaxes
uuid checks for overlay index feature. It is only possible in case there is
only one filesystem for all the work/upper/lower directories and bare file
handles from this backing filesystem are unique. In other case when we have
multiple filesystems lets just fallback to "uuid=on" which is and
equivalent of how it worked before with all uuid checks.
This is needed when overlayfs is/was mounted in a container with index
enabled (e.g.: to be able to resolve inotify watch file handles on it to
paths in CRIU), and this container is copied and started alongside with the
original one. This way the "copy" container can't have the same uuid on the
superblock and mounting the overlayfs from it later would fail.
That is an example of the problem on top of loop+ext4:
dd if=/dev/zero of=loopbackfile.img bs=100M count=10
losetup -fP loopbackfile.img
losetup -a
#/dev/loop0: [64768]:35 (/loop-test/loopbackfile.img)
mkfs.ext4 loopbackfile.img
mkdir loop-mp
mount -o loop /dev/loop0 loop-mp
mkdir loop-mp/{lower,upper,work,merged}
mount -t overlay overlay -oindex=on,lowerdir=loop-mp/lower,\
upperdir=loop-mp/upper,workdir=loop-mp/work loop-mp/merged
umount loop-mp/merged
umount loop-mp
e2fsck -f /dev/loop0
tune2fs -U random /dev/loop0
mount -o loop /dev/loop0 loop-mp
mount -t overlay overlay -oindex=on,lowerdir=loop-mp/lower,\
upperdir=loop-mp/upper,workdir=loop-mp/work loop-mp/merged
#mount: /loop-test/loop-mp/merged:
#mount(2) system call failed: Stale file handle.
If you just change the uuid of the backing filesystem, overlay is not
mounting any more. In Virtuozzo we copy container disks (ploops) when
create the copy of container and we require fs uuid to be unique for a new
container.
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2020-10-13 22:59:54 +08:00
|
|
|
OPT_UUID_ON,
|
|
|
|
OPT_UUID_OFF,
|
2018-01-19 17:26:53 +08:00
|
|
|
OPT_NFS_EXPORT_ON,
|
2020-12-14 22:26:14 +08:00
|
|
|
OPT_USERXATTR,
|
2018-01-19 17:26:53 +08:00
|
|
|
OPT_NFS_EXPORT_OFF,
|
2018-03-29 14:08:18 +08:00
|
|
|
OPT_XINO_ON,
|
|
|
|
OPT_XINO_OFF,
|
|
|
|
OPT_XINO_AUTO,
|
2018-05-11 23:49:27 +08:00
|
|
|
OPT_METACOPY_ON,
|
|
|
|
OPT_METACOPY_OFF,
|
2020-09-01 02:15:29 +08:00
|
|
|
OPT_VOLATILE,
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
OPT_ERR,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const match_table_t ovl_tokens = {
|
|
|
|
{OPT_LOWERDIR, "lowerdir=%s"},
|
|
|
|
{OPT_UPPERDIR, "upperdir=%s"},
|
|
|
|
{OPT_WORKDIR, "workdir=%s"},
|
2015-10-12 23:11:44 +08:00
|
|
|
{OPT_DEFAULT_PERMISSIONS, "default_permissions"},
|
2017-12-11 18:28:10 +08:00
|
|
|
{OPT_REDIRECT_DIR, "redirect_dir=%s"},
|
2017-06-21 20:28:36 +08:00
|
|
|
{OPT_INDEX_ON, "index=on"},
|
|
|
|
{OPT_INDEX_OFF, "index=off"},
|
2020-12-14 22:26:14 +08:00
|
|
|
{OPT_USERXATTR, "userxattr"},
|
ovl: introduce new "uuid=off" option for inodes index feature
This replaces uuid with null in overlayfs file handles and thus relaxes
uuid checks for overlay index feature. It is only possible in case there is
only one filesystem for all the work/upper/lower directories and bare file
handles from this backing filesystem are unique. In other case when we have
multiple filesystems lets just fallback to "uuid=on" which is and
equivalent of how it worked before with all uuid checks.
This is needed when overlayfs is/was mounted in a container with index
enabled (e.g.: to be able to resolve inotify watch file handles on it to
paths in CRIU), and this container is copied and started alongside with the
original one. This way the "copy" container can't have the same uuid on the
superblock and mounting the overlayfs from it later would fail.
That is an example of the problem on top of loop+ext4:
dd if=/dev/zero of=loopbackfile.img bs=100M count=10
losetup -fP loopbackfile.img
losetup -a
#/dev/loop0: [64768]:35 (/loop-test/loopbackfile.img)
mkfs.ext4 loopbackfile.img
mkdir loop-mp
mount -o loop /dev/loop0 loop-mp
mkdir loop-mp/{lower,upper,work,merged}
mount -t overlay overlay -oindex=on,lowerdir=loop-mp/lower,\
upperdir=loop-mp/upper,workdir=loop-mp/work loop-mp/merged
umount loop-mp/merged
umount loop-mp
e2fsck -f /dev/loop0
tune2fs -U random /dev/loop0
mount -o loop /dev/loop0 loop-mp
mount -t overlay overlay -oindex=on,lowerdir=loop-mp/lower,\
upperdir=loop-mp/upper,workdir=loop-mp/work loop-mp/merged
#mount: /loop-test/loop-mp/merged:
#mount(2) system call failed: Stale file handle.
If you just change the uuid of the backing filesystem, overlay is not
mounting any more. In Virtuozzo we copy container disks (ploops) when
create the copy of container and we require fs uuid to be unique for a new
container.
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2020-10-13 22:59:54 +08:00
|
|
|
{OPT_UUID_ON, "uuid=on"},
|
|
|
|
{OPT_UUID_OFF, "uuid=off"},
|
2018-01-19 17:26:53 +08:00
|
|
|
{OPT_NFS_EXPORT_ON, "nfs_export=on"},
|
|
|
|
{OPT_NFS_EXPORT_OFF, "nfs_export=off"},
|
2018-03-29 14:08:18 +08:00
|
|
|
{OPT_XINO_ON, "xino=on"},
|
|
|
|
{OPT_XINO_OFF, "xino=off"},
|
|
|
|
{OPT_XINO_AUTO, "xino=auto"},
|
2018-05-11 23:49:27 +08:00
|
|
|
{OPT_METACOPY_ON, "metacopy=on"},
|
|
|
|
{OPT_METACOPY_OFF, "metacopy=off"},
|
2020-09-01 02:15:29 +08:00
|
|
|
{OPT_VOLATILE, "volatile"},
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
{OPT_ERR, NULL}
|
|
|
|
};
|
|
|
|
|
2014-11-20 23:40:00 +08:00
|
|
|
static char *ovl_next_opt(char **s)
|
|
|
|
{
|
|
|
|
char *sbegin = *s;
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
if (sbegin == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (p = sbegin; *p; p++) {
|
|
|
|
if (*p == '\\') {
|
|
|
|
p++;
|
|
|
|
if (!*p)
|
|
|
|
break;
|
|
|
|
} else if (*p == ',') {
|
|
|
|
*p = '\0';
|
|
|
|
*s = p + 1;
|
|
|
|
return sbegin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*s = NULL;
|
|
|
|
return sbegin;
|
|
|
|
}
|
|
|
|
|
2017-12-11 18:28:10 +08:00
|
|
|
static int ovl_parse_redirect_mode(struct ovl_config *config, const char *mode)
|
|
|
|
{
|
|
|
|
if (strcmp(mode, "on") == 0) {
|
|
|
|
config->redirect_dir = true;
|
|
|
|
/*
|
|
|
|
* Does not make sense to have redirect creation without
|
|
|
|
* redirect following.
|
|
|
|
*/
|
|
|
|
config->redirect_follow = true;
|
|
|
|
} else if (strcmp(mode, "follow") == 0) {
|
|
|
|
config->redirect_follow = true;
|
|
|
|
} else if (strcmp(mode, "off") == 0) {
|
|
|
|
if (ovl_redirect_always_follow)
|
|
|
|
config->redirect_follow = true;
|
|
|
|
} else if (strcmp(mode, "nofollow") != 0) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("bad mount option \"redirect_dir=%s\"\n",
|
2017-12-11 18:28:10 +08:00
|
|
|
mode);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
static int ovl_parse_opt(char *opt, struct ovl_config *config)
|
|
|
|
{
|
|
|
|
char *p;
|
2018-05-11 23:49:27 +08:00
|
|
|
int err;
|
2018-11-02 04:31:39 +08:00
|
|
|
bool metacopy_opt = false, redirect_opt = false;
|
2020-04-09 23:58:34 +08:00
|
|
|
bool nfs_export_opt = false, index_opt = false;
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
|
2017-12-11 18:28:10 +08:00
|
|
|
config->redirect_mode = kstrdup(ovl_redirect_mode_def(), GFP_KERNEL);
|
|
|
|
if (!config->redirect_mode)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2014-11-20 23:40:00 +08:00
|
|
|
while ((p = ovl_next_opt(&opt)) != NULL) {
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
int token;
|
|
|
|
substring_t args[MAX_OPT_ARGS];
|
|
|
|
|
|
|
|
if (!*p)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
token = match_token(p, ovl_tokens, args);
|
|
|
|
switch (token) {
|
|
|
|
case OPT_UPPERDIR:
|
|
|
|
kfree(config->upperdir);
|
|
|
|
config->upperdir = match_strdup(&args[0]);
|
|
|
|
if (!config->upperdir)
|
|
|
|
return -ENOMEM;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OPT_LOWERDIR:
|
|
|
|
kfree(config->lowerdir);
|
|
|
|
config->lowerdir = match_strdup(&args[0]);
|
|
|
|
if (!config->lowerdir)
|
|
|
|
return -ENOMEM;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OPT_WORKDIR:
|
|
|
|
kfree(config->workdir);
|
|
|
|
config->workdir = match_strdup(&args[0]);
|
|
|
|
if (!config->workdir)
|
|
|
|
return -ENOMEM;
|
|
|
|
break;
|
|
|
|
|
2015-10-12 23:11:44 +08:00
|
|
|
case OPT_DEFAULT_PERMISSIONS:
|
|
|
|
config->default_permissions = true;
|
|
|
|
break;
|
|
|
|
|
2017-12-11 18:28:10 +08:00
|
|
|
case OPT_REDIRECT_DIR:
|
|
|
|
kfree(config->redirect_mode);
|
|
|
|
config->redirect_mode = match_strdup(&args[0]);
|
|
|
|
if (!config->redirect_mode)
|
|
|
|
return -ENOMEM;
|
2018-11-02 04:31:39 +08:00
|
|
|
redirect_opt = true;
|
2016-12-16 18:02:56 +08:00
|
|
|
break;
|
|
|
|
|
2017-06-21 20:28:36 +08:00
|
|
|
case OPT_INDEX_ON:
|
|
|
|
config->index = true;
|
2020-04-09 23:58:34 +08:00
|
|
|
index_opt = true;
|
2017-06-21 20:28:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OPT_INDEX_OFF:
|
|
|
|
config->index = false;
|
2020-04-09 23:58:34 +08:00
|
|
|
index_opt = true;
|
2017-06-21 20:28:36 +08:00
|
|
|
break;
|
|
|
|
|
ovl: introduce new "uuid=off" option for inodes index feature
This replaces uuid with null in overlayfs file handles and thus relaxes
uuid checks for overlay index feature. It is only possible in case there is
only one filesystem for all the work/upper/lower directories and bare file
handles from this backing filesystem are unique. In other case when we have
multiple filesystems lets just fallback to "uuid=on" which is and
equivalent of how it worked before with all uuid checks.
This is needed when overlayfs is/was mounted in a container with index
enabled (e.g.: to be able to resolve inotify watch file handles on it to
paths in CRIU), and this container is copied and started alongside with the
original one. This way the "copy" container can't have the same uuid on the
superblock and mounting the overlayfs from it later would fail.
That is an example of the problem on top of loop+ext4:
dd if=/dev/zero of=loopbackfile.img bs=100M count=10
losetup -fP loopbackfile.img
losetup -a
#/dev/loop0: [64768]:35 (/loop-test/loopbackfile.img)
mkfs.ext4 loopbackfile.img
mkdir loop-mp
mount -o loop /dev/loop0 loop-mp
mkdir loop-mp/{lower,upper,work,merged}
mount -t overlay overlay -oindex=on,lowerdir=loop-mp/lower,\
upperdir=loop-mp/upper,workdir=loop-mp/work loop-mp/merged
umount loop-mp/merged
umount loop-mp
e2fsck -f /dev/loop0
tune2fs -U random /dev/loop0
mount -o loop /dev/loop0 loop-mp
mount -t overlay overlay -oindex=on,lowerdir=loop-mp/lower,\
upperdir=loop-mp/upper,workdir=loop-mp/work loop-mp/merged
#mount: /loop-test/loop-mp/merged:
#mount(2) system call failed: Stale file handle.
If you just change the uuid of the backing filesystem, overlay is not
mounting any more. In Virtuozzo we copy container disks (ploops) when
create the copy of container and we require fs uuid to be unique for a new
container.
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2020-10-13 22:59:54 +08:00
|
|
|
case OPT_UUID_ON:
|
|
|
|
config->uuid = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OPT_UUID_OFF:
|
|
|
|
config->uuid = false;
|
|
|
|
break;
|
|
|
|
|
2018-01-19 17:26:53 +08:00
|
|
|
case OPT_NFS_EXPORT_ON:
|
|
|
|
config->nfs_export = true;
|
2020-04-09 23:58:34 +08:00
|
|
|
nfs_export_opt = true;
|
2018-01-19 17:26:53 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OPT_NFS_EXPORT_OFF:
|
|
|
|
config->nfs_export = false;
|
2020-04-09 23:58:34 +08:00
|
|
|
nfs_export_opt = true;
|
2018-01-19 17:26:53 +08:00
|
|
|
break;
|
|
|
|
|
2018-03-29 14:08:18 +08:00
|
|
|
case OPT_XINO_ON:
|
|
|
|
config->xino = OVL_XINO_ON;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OPT_XINO_OFF:
|
|
|
|
config->xino = OVL_XINO_OFF;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OPT_XINO_AUTO:
|
|
|
|
config->xino = OVL_XINO_AUTO;
|
|
|
|
break;
|
|
|
|
|
2018-05-11 23:49:27 +08:00
|
|
|
case OPT_METACOPY_ON:
|
|
|
|
config->metacopy = true;
|
2018-11-02 04:31:39 +08:00
|
|
|
metacopy_opt = true;
|
2018-05-11 23:49:27 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OPT_METACOPY_OFF:
|
|
|
|
config->metacopy = false;
|
2020-04-09 23:58:34 +08:00
|
|
|
metacopy_opt = true;
|
2018-05-11 23:49:27 +08:00
|
|
|
break;
|
|
|
|
|
2020-09-01 02:15:29 +08:00
|
|
|
case OPT_VOLATILE:
|
|
|
|
config->ovl_volatile = true;
|
|
|
|
break;
|
|
|
|
|
2020-12-14 22:26:14 +08:00
|
|
|
case OPT_USERXATTR:
|
|
|
|
config->userxattr = true;
|
|
|
|
break;
|
|
|
|
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
default:
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("unrecognized mount option \"%s\" or missing value\n",
|
|
|
|
p);
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
2015-01-15 13:20:57 +08:00
|
|
|
|
2020-07-13 22:19:44 +08:00
|
|
|
/* Workdir/index are useless in non-upper mount */
|
|
|
|
if (!config->upperdir) {
|
|
|
|
if (config->workdir) {
|
|
|
|
pr_info("option \"workdir=%s\" is useless in a non-upper mount, ignore\n",
|
|
|
|
config->workdir);
|
|
|
|
kfree(config->workdir);
|
|
|
|
config->workdir = NULL;
|
|
|
|
}
|
|
|
|
if (config->index && index_opt) {
|
|
|
|
pr_info("option \"index=on\" is useless in a non-upper mount, ignore\n");
|
|
|
|
index_opt = false;
|
|
|
|
}
|
|
|
|
config->index = false;
|
2015-01-15 13:20:57 +08:00
|
|
|
}
|
|
|
|
|
2020-09-01 02:15:29 +08:00
|
|
|
if (!config->upperdir && config->ovl_volatile) {
|
|
|
|
pr_info("option \"volatile\" is meaningless in a non-upper mount, ignoring it.\n");
|
|
|
|
config->ovl_volatile = false;
|
|
|
|
}
|
|
|
|
|
2018-05-11 23:49:27 +08:00
|
|
|
err = ovl_parse_redirect_mode(config, config->redirect_mode);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2018-11-02 04:31:39 +08:00
|
|
|
/*
|
|
|
|
* This is to make the logic below simpler. It doesn't make any other
|
|
|
|
* difference, since config->redirect_dir is only used for upper.
|
|
|
|
*/
|
|
|
|
if (!config->upperdir && config->redirect_follow)
|
|
|
|
config->redirect_dir = true;
|
|
|
|
|
|
|
|
/* Resolve metacopy -> redirect_dir dependency */
|
|
|
|
if (config->metacopy && !config->redirect_dir) {
|
|
|
|
if (metacopy_opt && redirect_opt) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("conflicting options: metacopy=on,redirect_dir=%s\n",
|
2018-11-02 04:31:39 +08:00
|
|
|
config->redirect_mode);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (redirect_opt) {
|
|
|
|
/*
|
|
|
|
* There was an explicit redirect_dir=... that resulted
|
|
|
|
* in this conflict.
|
|
|
|
*/
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_info("disabling metacopy due to redirect_dir=%s\n",
|
2018-11-02 04:31:39 +08:00
|
|
|
config->redirect_mode);
|
|
|
|
config->metacopy = false;
|
|
|
|
} else {
|
|
|
|
/* Automatically enable redirect otherwise. */
|
|
|
|
config->redirect_follow = config->redirect_dir = true;
|
|
|
|
}
|
2018-05-11 23:49:27 +08:00
|
|
|
}
|
|
|
|
|
2020-04-09 23:58:34 +08:00
|
|
|
/* Resolve nfs_export -> index dependency */
|
|
|
|
if (config->nfs_export && !config->index) {
|
2020-07-13 22:19:44 +08:00
|
|
|
if (!config->upperdir && config->redirect_follow) {
|
|
|
|
pr_info("NFS export requires \"redirect_dir=nofollow\" on non-upper mount, falling back to nfs_export=off.\n");
|
|
|
|
config->nfs_export = false;
|
|
|
|
} else if (nfs_export_opt && index_opt) {
|
2020-04-09 23:58:34 +08:00
|
|
|
pr_err("conflicting options: nfs_export=on,index=off\n");
|
|
|
|
return -EINVAL;
|
2020-07-13 22:19:44 +08:00
|
|
|
} else if (index_opt) {
|
2020-04-09 23:58:34 +08:00
|
|
|
/*
|
|
|
|
* There was an explicit index=off that resulted
|
|
|
|
* in this conflict.
|
|
|
|
*/
|
|
|
|
pr_info("disabling nfs_export due to index=off\n");
|
|
|
|
config->nfs_export = false;
|
|
|
|
} else {
|
|
|
|
/* Automatically enable index otherwise. */
|
|
|
|
config->index = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Resolve nfs_export -> !metacopy dependency */
|
|
|
|
if (config->nfs_export && config->metacopy) {
|
|
|
|
if (nfs_export_opt && metacopy_opt) {
|
|
|
|
pr_err("conflicting options: nfs_export=on,metacopy=on\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (metacopy_opt) {
|
|
|
|
/*
|
|
|
|
* There was an explicit metacopy=on that resulted
|
|
|
|
* in this conflict.
|
|
|
|
*/
|
|
|
|
pr_info("disabling nfs_export due to metacopy=on\n");
|
|
|
|
config->nfs_export = false;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* There was an explicit nfs_export=on that resulted
|
|
|
|
* in this conflict.
|
|
|
|
*/
|
|
|
|
pr_info("disabling metacopy due to nfs_export=on\n");
|
|
|
|
config->metacopy = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-14 22:26:14 +08:00
|
|
|
|
|
|
|
/* Resolve userxattr -> !redirect && !metacopy dependency */
|
|
|
|
if (config->userxattr) {
|
|
|
|
if (config->redirect_follow && redirect_opt) {
|
|
|
|
pr_err("conflicting options: userxattr,redirect_dir=%s\n",
|
|
|
|
config->redirect_mode);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (config->metacopy && metacopy_opt) {
|
|
|
|
pr_err("conflicting options: userxattr,metacopy=on\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Silently disable default setting of redirect and metacopy.
|
|
|
|
* This shall be the default in the future as well: these
|
|
|
|
* options must be explicitly enabled if used together with
|
|
|
|
* userxattr.
|
|
|
|
*/
|
|
|
|
config->redirect_dir = config->redirect_follow = false;
|
|
|
|
config->metacopy = false;
|
|
|
|
}
|
|
|
|
|
2018-05-11 23:49:27 +08:00
|
|
|
return 0;
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#define OVL_WORKDIR_NAME "work"
|
2017-06-21 20:28:36 +08:00
|
|
|
#define OVL_INDEXDIR_NAME "index"
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
|
2017-11-10 16:39:16 +08:00
|
|
|
static struct dentry *ovl_workdir_create(struct ovl_fs *ofs,
|
2017-06-21 20:28:35 +08:00
|
|
|
const char *name, bool persist)
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
{
|
2017-11-10 16:39:16 +08:00
|
|
|
struct inode *dir = ofs->workbasedir->d_inode;
|
2020-06-04 16:48:19 +08:00
|
|
|
struct vfsmount *mnt = ovl_upper_mnt(ofs);
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
struct dentry *work;
|
|
|
|
int err;
|
|
|
|
bool retried = false;
|
|
|
|
|
2016-01-23 04:40:57 +08:00
|
|
|
inode_lock_nested(dir, I_MUTEX_PARENT);
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
retry:
|
2022-04-04 18:51:49 +08:00
|
|
|
work = ovl_lookup_upper(ofs, name, ofs->workbasedir, strlen(name));
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
|
|
|
|
if (!IS_ERR(work)) {
|
2016-09-01 17:11:59 +08:00
|
|
|
struct iattr attr = {
|
|
|
|
.ia_valid = ATTR_MODE,
|
2016-12-05 01:33:17 +08:00
|
|
|
.ia_mode = S_IFDIR | 0,
|
2016-09-01 17:11:59 +08:00
|
|
|
};
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
|
|
|
|
if (work->d_inode) {
|
|
|
|
err = -EEXIST;
|
|
|
|
if (retried)
|
|
|
|
goto out_dput;
|
|
|
|
|
2017-06-21 20:28:35 +08:00
|
|
|
if (persist)
|
|
|
|
goto out_unlock;
|
|
|
|
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
retried = true;
|
2022-04-04 18:51:43 +08:00
|
|
|
err = ovl_workdir_cleanup(ofs, dir, mnt, work, 0);
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
dput(work);
|
2020-08-31 04:28:03 +08:00
|
|
|
if (err == -EINVAL) {
|
|
|
|
work = ERR_PTR(err);
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
2022-04-04 18:51:43 +08:00
|
|
|
err = ovl_mkdir_real(ofs, dir, &work, attr.ia_mode);
|
2021-11-04 17:55:34 +08:00
|
|
|
if (err)
|
|
|
|
goto out_dput;
|
|
|
|
|
|
|
|
/* Weird filesystem returning with hashed negative (kernfs)? */
|
|
|
|
err = -EINVAL;
|
|
|
|
if (d_really_is_negative(work))
|
|
|
|
goto out_dput;
|
2016-09-01 17:11:59 +08:00
|
|
|
|
2016-10-04 20:40:44 +08:00
|
|
|
/*
|
|
|
|
* Try to remove POSIX ACL xattrs from workdir. We are good if:
|
|
|
|
*
|
|
|
|
* a) success (there was a POSIX ACL xattr and was removed)
|
|
|
|
* b) -ENODATA (there was no POSIX ACL xattr)
|
|
|
|
* c) -EOPNOTSUPP (POSIX ACL xattrs are not supported)
|
|
|
|
*
|
|
|
|
* There are various other error values that could effectively
|
|
|
|
* mean that the xattr doesn't exist (e.g. -ERANGE is returned
|
|
|
|
* if the xattr name is too long), but the set of filesystems
|
|
|
|
* allowed as upper are limited to "normal" ones, where checking
|
|
|
|
* for the above two errors is sufficient.
|
|
|
|
*/
|
2022-04-04 18:51:42 +08:00
|
|
|
err = ovl_do_removexattr(ofs, work,
|
|
|
|
XATTR_NAME_POSIX_ACL_DEFAULT);
|
2016-09-05 19:55:20 +08:00
|
|
|
if (err && err != -ENODATA && err != -EOPNOTSUPP)
|
2016-09-01 17:11:59 +08:00
|
|
|
goto out_dput;
|
|
|
|
|
2022-04-04 18:51:42 +08:00
|
|
|
err = ovl_do_removexattr(ofs, work,
|
|
|
|
XATTR_NAME_POSIX_ACL_ACCESS);
|
2016-09-05 19:55:20 +08:00
|
|
|
if (err && err != -ENODATA && err != -EOPNOTSUPP)
|
2016-09-01 17:11:59 +08:00
|
|
|
goto out_dput;
|
|
|
|
|
|
|
|
/* Clear any inherited mode bits */
|
|
|
|
inode_lock(work->d_inode);
|
2022-04-04 18:51:48 +08:00
|
|
|
err = ovl_do_notify_change(ofs, work, &attr);
|
2016-09-01 17:11:59 +08:00
|
|
|
inode_unlock(work->d_inode);
|
|
|
|
if (err)
|
|
|
|
goto out_dput;
|
2017-06-21 20:28:35 +08:00
|
|
|
} else {
|
|
|
|
err = PTR_ERR(work);
|
|
|
|
goto out_err;
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
}
|
|
|
|
out_unlock:
|
2020-06-07 17:04:06 +08:00
|
|
|
inode_unlock(dir);
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
return work;
|
|
|
|
|
|
|
|
out_dput:
|
|
|
|
dput(work);
|
2017-06-21 20:28:35 +08:00
|
|
|
out_err:
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_warn("failed to create directory %s/%s (errno: %i); mounting read-only\n",
|
2017-11-10 16:39:16 +08:00
|
|
|
ofs->config.workdir, name, -err);
|
2017-06-21 20:28:35 +08:00
|
|
|
work = NULL;
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
|
2014-11-20 23:40:00 +08:00
|
|
|
static void ovl_unescape(char *s)
|
|
|
|
{
|
|
|
|
char *d = s;
|
|
|
|
|
|
|
|
for (;; s++, d++) {
|
|
|
|
if (*s == '\\')
|
|
|
|
s++;
|
|
|
|
*d = *s;
|
|
|
|
if (!*s)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-13 07:59:49 +08:00
|
|
|
static int ovl_mount_dir_noesc(const char *name, struct path *path)
|
|
|
|
{
|
2014-12-13 07:59:52 +08:00
|
|
|
int err = -EINVAL;
|
2014-12-13 07:59:49 +08:00
|
|
|
|
2014-12-13 07:59:52 +08:00
|
|
|
if (!*name) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("empty lowerdir\n");
|
2014-12-13 07:59:52 +08:00
|
|
|
goto out;
|
|
|
|
}
|
2014-12-13 07:59:49 +08:00
|
|
|
err = kern_path(name, LOOKUP_FOLLOW, path);
|
|
|
|
if (err) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("failed to resolve '%s': %i\n", name, err);
|
2014-12-13 07:59:49 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
err = -EINVAL;
|
2015-06-22 19:53:48 +08:00
|
|
|
if (ovl_dentry_weird(path->dentry)) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("filesystem on '%s' not supported\n", name);
|
2014-12-13 07:59:49 +08:00
|
|
|
goto out_put;
|
|
|
|
}
|
2016-12-16 18:02:56 +08:00
|
|
|
if (!d_is_dir(path->dentry)) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("'%s' not a directory\n", name);
|
2014-12-13 07:59:49 +08:00
|
|
|
goto out_put;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
out_put:
|
2017-11-09 17:23:28 +08:00
|
|
|
path_put_init(path);
|
2014-12-13 07:59:49 +08:00
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ovl_mount_dir(const char *name, struct path *path)
|
|
|
|
{
|
|
|
|
int err = -ENOMEM;
|
|
|
|
char *tmp = kstrdup(name, GFP_KERNEL);
|
|
|
|
|
|
|
|
if (tmp) {
|
|
|
|
ovl_unescape(tmp);
|
|
|
|
err = ovl_mount_dir_noesc(tmp, path);
|
2015-06-22 19:53:48 +08:00
|
|
|
|
2020-03-17 22:04:22 +08:00
|
|
|
if (!err && path->dentry->d_flags & DCACHE_OP_REAL) {
|
2020-03-17 22:04:22 +08:00
|
|
|
pr_err("filesystem on '%s' not supported as upperdir\n",
|
|
|
|
tmp);
|
|
|
|
path_put_init(path);
|
|
|
|
err = -EINVAL;
|
|
|
|
}
|
2014-12-13 07:59:49 +08:00
|
|
|
kfree(tmp);
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-08-05 01:11:15 +08:00
|
|
|
static int ovl_check_namelen(const struct path *path, struct ovl_fs *ofs,
|
2016-12-16 18:02:56 +08:00
|
|
|
const char *name)
|
2014-12-13 07:59:49 +08:00
|
|
|
{
|
|
|
|
struct kstatfs statfs;
|
2016-12-16 18:02:56 +08:00
|
|
|
int err = vfs_statfs(path, &statfs);
|
|
|
|
|
|
|
|
if (err)
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("statfs failed on '%s'\n", name);
|
2016-12-16 18:02:56 +08:00
|
|
|
else
|
|
|
|
ofs->namelen = max(ofs->namelen, statfs.f_namelen);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ovl_lower_dir(const char *name, struct path *path,
|
2020-03-17 22:04:22 +08:00
|
|
|
struct ovl_fs *ofs, int *stack_depth)
|
2016-12-16 18:02:56 +08:00
|
|
|
{
|
2017-11-07 19:55:04 +08:00
|
|
|
int fh_type;
|
2016-12-16 18:02:56 +08:00
|
|
|
int err;
|
2014-12-13 07:59:49 +08:00
|
|
|
|
2014-12-13 07:59:52 +08:00
|
|
|
err = ovl_mount_dir_noesc(name, path);
|
2014-12-13 07:59:49 +08:00
|
|
|
if (err)
|
2020-06-04 16:48:19 +08:00
|
|
|
return err;
|
2014-12-13 07:59:49 +08:00
|
|
|
|
2016-12-16 18:02:56 +08:00
|
|
|
err = ovl_check_namelen(path, ofs, name);
|
|
|
|
if (err)
|
2020-06-04 16:48:19 +08:00
|
|
|
return err;
|
2016-12-16 18:02:56 +08:00
|
|
|
|
2014-12-13 07:59:49 +08:00
|
|
|
*stack_depth = max(*stack_depth, path->mnt->mnt_sb->s_stack_depth);
|
|
|
|
|
2017-06-21 20:28:36 +08:00
|
|
|
/*
|
2018-01-19 17:26:53 +08:00
|
|
|
* The inodes index feature and NFS export need to encode and decode
|
|
|
|
* file handles, so they require that all layers support them.
|
2017-06-21 20:28:36 +08:00
|
|
|
*/
|
2017-11-07 19:55:04 +08:00
|
|
|
fh_type = ovl_can_decode_fh(path->dentry->d_sb);
|
2018-01-19 17:26:53 +08:00
|
|
|
if ((ofs->config.nfs_export ||
|
2017-11-07 19:55:04 +08:00
|
|
|
(ofs->config.index && ofs->config.upperdir)) && !fh_type) {
|
2017-06-21 20:28:36 +08:00
|
|
|
ofs->config.index = false;
|
2018-01-19 17:26:53 +08:00
|
|
|
ofs->config.nfs_export = false;
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_warn("fs on '%s' does not support file handles, falling back to index=off,nfs_export=off.\n",
|
2018-01-19 17:26:53 +08:00
|
|
|
name);
|
2017-06-21 20:28:36 +08:00
|
|
|
}
|
ovl: restrict lower null uuid for "xino=auto"
Commit a888db310195 ("ovl: fix regression with re-formatted lower
squashfs") attempted to fix a regression with existing setups that
use a practice that we are trying to discourage.
The discourage part was described this way in the commit message:
"To avoid the reported regression while still allowing the new features
with single lower squashfs, do not allow decoding origin with lower null
uuid unless user opted-in to one of the new features that require
following the lower inode of non-dir upper (index, xino, metacopy)."
The three mentioned features are disabled by default in Kconfig, so
it was assumed that if they are enabled, the user opted-in for them.
Apparently, distros started to configure CONFIG_OVERLAY_FS_XINO_AUTO=y
some time ago, so users upgrading their kernels can still be affected
by said regression even though they never opted-in for any new feature.
To fix this, treat "xino=on" as "user opted-in", but not "xino=auto".
Since we are changing the behavior of "xino=auto" to no longer follow
to lower origin with null uuid, take this one step further and disable
xino in that corner case. To be consistent, disable xino also in cases
of lower fs without file handle support and upper fs without xattr
support.
Update documentation w.r.t the new "xino=auto" behavior and fix the out
dated bits of documentation regarding "xino" and regarding offline
modifications to lower layers.
Link: https://lore.kernel.org/linux-unionfs/b36a429d7c563730c28d763d4d57a6fc30508a4f.1615216996.git.kevin@kevinlocke.name/
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2021-03-10 00:26:54 +08:00
|
|
|
/*
|
|
|
|
* Decoding origin file handle is required for persistent st_ino.
|
|
|
|
* Without persistent st_ino, xino=auto falls back to xino=off.
|
|
|
|
*/
|
|
|
|
if (ofs->config.xino == OVL_XINO_AUTO &&
|
|
|
|
ofs->config.upperdir && !fh_type) {
|
|
|
|
ofs->config.xino = OVL_XINO_OFF;
|
|
|
|
pr_warn("fs on '%s' does not support file handles, falling back to xino=off.\n",
|
|
|
|
name);
|
|
|
|
}
|
2017-06-21 20:28:36 +08:00
|
|
|
|
2017-11-07 19:55:04 +08:00
|
|
|
/* Check if lower fs has 32bit inode numbers */
|
|
|
|
if (fh_type != FILEID_INO32_GEN)
|
2019-11-17 00:14:41 +08:00
|
|
|
ofs->xino_mode = -1;
|
2017-11-07 19:55:04 +08:00
|
|
|
|
2014-12-13 07:59:49 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
/* Workdir should not be subdir of upperdir and vice versa */
|
|
|
|
static bool ovl_workdir_ok(struct dentry *workdir, struct dentry *upperdir)
|
|
|
|
{
|
|
|
|
bool ok = false;
|
|
|
|
|
|
|
|
if (workdir != upperdir) {
|
|
|
|
ok = (lock_rename(workdir, upperdir) == NULL);
|
|
|
|
unlock_rename(workdir, upperdir);
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2014-12-13 07:59:52 +08:00
|
|
|
static unsigned int ovl_split_lowerdirs(char *str)
|
|
|
|
{
|
|
|
|
unsigned int ctr = 1;
|
|
|
|
char *s, *d;
|
|
|
|
|
|
|
|
for (s = d = str;; s++, d++) {
|
|
|
|
if (*s == '\\') {
|
|
|
|
s++;
|
|
|
|
} else if (*s == ':') {
|
|
|
|
*d = '\0';
|
|
|
|
ctr++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*d = *s;
|
|
|
|
if (!*s)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ctr;
|
|
|
|
}
|
|
|
|
|
2016-08-22 23:52:55 +08:00
|
|
|
static int __maybe_unused
|
|
|
|
ovl_posix_acl_xattr_get(const struct xattr_handler *handler,
|
|
|
|
struct dentry *dentry, struct inode *inode,
|
|
|
|
const char *name, void *buffer, size_t size)
|
|
|
|
{
|
2017-07-20 17:08:21 +08:00
|
|
|
return ovl_xattr_get(dentry, inode, handler->name, buffer, size);
|
2016-08-22 23:52:55 +08:00
|
|
|
}
|
|
|
|
|
2016-08-22 22:36:49 +08:00
|
|
|
static int __maybe_unused
|
|
|
|
ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
|
2021-01-21 21:19:27 +08:00
|
|
|
struct user_namespace *mnt_userns,
|
2016-08-22 22:36:49 +08:00
|
|
|
struct dentry *dentry, struct inode *inode,
|
|
|
|
const char *name, const void *value,
|
|
|
|
size_t size, int flags)
|
2016-07-29 18:05:24 +08:00
|
|
|
{
|
|
|
|
struct dentry *workdir = ovl_workdir(dentry);
|
2017-07-05 04:03:16 +08:00
|
|
|
struct inode *realinode = ovl_inode_real(inode);
|
2016-07-29 18:05:24 +08:00
|
|
|
struct posix_acl *acl = NULL;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* Check that everything is OK before copy-up */
|
|
|
|
if (value) {
|
2022-08-29 20:38:44 +08:00
|
|
|
/* The above comment can be understood in two ways:
|
|
|
|
*
|
|
|
|
* 1. We just want to check whether the basic POSIX ACL format
|
|
|
|
* is ok. For example, if the header is correct and the size
|
|
|
|
* is sane.
|
|
|
|
* 2. We want to know whether the ACL_{GROUP,USER} entries can
|
|
|
|
* be mapped according to the underlying filesystem.
|
|
|
|
*
|
|
|
|
* Currently, we only check 1. If we wanted to check 2. we
|
|
|
|
* would need to pass the mnt_userns and the fs_userns of the
|
|
|
|
* underlying filesystem. But frankly, I think checking 1. is
|
|
|
|
* enough to start the copy-up.
|
|
|
|
*/
|
|
|
|
acl = vfs_set_acl_prepare(&init_user_ns, &init_user_ns, value, size);
|
2016-07-29 18:05:24 +08:00
|
|
|
if (IS_ERR(acl))
|
|
|
|
return PTR_ERR(acl);
|
|
|
|
}
|
|
|
|
err = -EOPNOTSUPP;
|
|
|
|
if (!IS_POSIXACL(d_inode(workdir)))
|
|
|
|
goto out_acl_release;
|
|
|
|
if (!realinode->i_op->set_acl)
|
|
|
|
goto out_acl_release;
|
|
|
|
if (handler->flags == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) {
|
|
|
|
err = acl ? -EACCES : 0;
|
|
|
|
goto out_acl_release;
|
|
|
|
}
|
|
|
|
err = -EPERM;
|
2021-01-21 21:19:25 +08:00
|
|
|
if (!inode_owner_or_capable(&init_user_ns, inode))
|
2016-07-29 18:05:24 +08:00
|
|
|
goto out_acl_release;
|
|
|
|
|
|
|
|
posix_acl_release(acl);
|
|
|
|
|
2016-10-31 21:42:14 +08:00
|
|
|
/*
|
|
|
|
* Check if sgid bit needs to be cleared (actual setacl operation will
|
|
|
|
* be done with mounter's capabilities and so that won't do it for us).
|
|
|
|
*/
|
|
|
|
if (unlikely(inode->i_mode & S_ISGID) &&
|
|
|
|
handler->flags == ACL_TYPE_ACCESS &&
|
|
|
|
!in_group_p(inode->i_gid) &&
|
2021-01-21 21:19:23 +08:00
|
|
|
!capable_wrt_inode_uidgid(&init_user_ns, inode, CAP_FSETID)) {
|
2016-10-31 21:42:14 +08:00
|
|
|
struct iattr iattr = { .ia_valid = ATTR_KILL_SGID };
|
|
|
|
|
2021-01-21 21:19:43 +08:00
|
|
|
err = ovl_setattr(&init_user_ns, dentry, &iattr);
|
2016-10-31 21:42:14 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2017-07-20 17:08:21 +08:00
|
|
|
err = ovl_xattr_set(dentry, inode, handler->name, value, size, flags);
|
2016-09-01 17:12:00 +08:00
|
|
|
return err;
|
2016-07-29 18:05:24 +08:00
|
|
|
|
|
|
|
out_acl_release:
|
|
|
|
posix_acl_release(acl);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2016-08-22 23:52:55 +08:00
|
|
|
static int ovl_own_xattr_get(const struct xattr_handler *handler,
|
|
|
|
struct dentry *dentry, struct inode *inode,
|
|
|
|
const char *name, void *buffer, size_t size)
|
|
|
|
{
|
2016-11-16 17:22:39 +08:00
|
|
|
return -EOPNOTSUPP;
|
2016-08-22 23:52:55 +08:00
|
|
|
}
|
|
|
|
|
2016-07-29 18:05:24 +08:00
|
|
|
static int ovl_own_xattr_set(const struct xattr_handler *handler,
|
2021-01-21 21:19:27 +08:00
|
|
|
struct user_namespace *mnt_userns,
|
2016-07-29 18:05:24 +08:00
|
|
|
struct dentry *dentry, struct inode *inode,
|
|
|
|
const char *name, const void *value,
|
|
|
|
size_t size, int flags)
|
|
|
|
{
|
2016-11-16 17:22:39 +08:00
|
|
|
return -EOPNOTSUPP;
|
2016-07-29 18:05:24 +08:00
|
|
|
}
|
|
|
|
|
2016-08-22 23:52:55 +08:00
|
|
|
static int ovl_other_xattr_get(const struct xattr_handler *handler,
|
|
|
|
struct dentry *dentry, struct inode *inode,
|
|
|
|
const char *name, void *buffer, size_t size)
|
|
|
|
{
|
2017-07-20 17:08:21 +08:00
|
|
|
return ovl_xattr_get(dentry, inode, name, buffer, size);
|
2016-08-22 23:52:55 +08:00
|
|
|
}
|
|
|
|
|
2016-08-22 23:22:11 +08:00
|
|
|
static int ovl_other_xattr_set(const struct xattr_handler *handler,
|
2021-01-21 21:19:27 +08:00
|
|
|
struct user_namespace *mnt_userns,
|
2016-08-22 23:22:11 +08:00
|
|
|
struct dentry *dentry, struct inode *inode,
|
|
|
|
const char *name, const void *value,
|
|
|
|
size_t size, int flags)
|
|
|
|
{
|
2017-07-20 17:08:21 +08:00
|
|
|
return ovl_xattr_set(dentry, inode, name, value, size, flags);
|
2016-08-22 23:22:11 +08:00
|
|
|
}
|
|
|
|
|
2016-08-22 22:36:49 +08:00
|
|
|
static const struct xattr_handler __maybe_unused
|
|
|
|
ovl_posix_acl_access_xattr_handler = {
|
2016-07-29 18:05:24 +08:00
|
|
|
.name = XATTR_NAME_POSIX_ACL_ACCESS,
|
|
|
|
.flags = ACL_TYPE_ACCESS,
|
2016-08-22 23:52:55 +08:00
|
|
|
.get = ovl_posix_acl_xattr_get,
|
2016-07-29 18:05:24 +08:00
|
|
|
.set = ovl_posix_acl_xattr_set,
|
|
|
|
};
|
|
|
|
|
2016-08-22 22:36:49 +08:00
|
|
|
static const struct xattr_handler __maybe_unused
|
|
|
|
ovl_posix_acl_default_xattr_handler = {
|
2016-07-29 18:05:24 +08:00
|
|
|
.name = XATTR_NAME_POSIX_ACL_DEFAULT,
|
|
|
|
.flags = ACL_TYPE_DEFAULT,
|
2016-08-22 23:52:55 +08:00
|
|
|
.get = ovl_posix_acl_xattr_get,
|
2016-07-29 18:05:24 +08:00
|
|
|
.set = ovl_posix_acl_xattr_set,
|
|
|
|
};
|
|
|
|
|
2020-12-14 22:26:14 +08:00
|
|
|
static const struct xattr_handler ovl_own_trusted_xattr_handler = {
|
|
|
|
.prefix = OVL_XATTR_TRUSTED_PREFIX,
|
|
|
|
.get = ovl_own_xattr_get,
|
|
|
|
.set = ovl_own_xattr_set,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct xattr_handler ovl_own_user_xattr_handler = {
|
|
|
|
.prefix = OVL_XATTR_USER_PREFIX,
|
2016-08-22 23:52:55 +08:00
|
|
|
.get = ovl_own_xattr_get,
|
2016-07-29 18:05:24 +08:00
|
|
|
.set = ovl_own_xattr_set,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct xattr_handler ovl_other_xattr_handler = {
|
|
|
|
.prefix = "", /* catch all */
|
2016-08-22 23:52:55 +08:00
|
|
|
.get = ovl_other_xattr_get,
|
2016-07-29 18:05:24 +08:00
|
|
|
.set = ovl_other_xattr_set,
|
|
|
|
};
|
|
|
|
|
2020-12-14 22:26:14 +08:00
|
|
|
static const struct xattr_handler *ovl_trusted_xattr_handlers[] = {
|
|
|
|
#ifdef CONFIG_FS_POSIX_ACL
|
|
|
|
&ovl_posix_acl_access_xattr_handler,
|
|
|
|
&ovl_posix_acl_default_xattr_handler,
|
|
|
|
#endif
|
|
|
|
&ovl_own_trusted_xattr_handler,
|
|
|
|
&ovl_other_xattr_handler,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct xattr_handler *ovl_user_xattr_handlers[] = {
|
2016-08-22 22:36:49 +08:00
|
|
|
#ifdef CONFIG_FS_POSIX_ACL
|
2016-07-29 18:05:24 +08:00
|
|
|
&ovl_posix_acl_access_xattr_handler,
|
|
|
|
&ovl_posix_acl_default_xattr_handler,
|
2016-08-22 22:36:49 +08:00
|
|
|
#endif
|
2020-12-14 22:26:14 +08:00
|
|
|
&ovl_own_user_xattr_handler,
|
2016-07-29 18:05:24 +08:00
|
|
|
&ovl_other_xattr_handler,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
static int ovl_setup_trap(struct super_block *sb, struct dentry *dir,
|
|
|
|
struct inode **ptrap, const char *name)
|
|
|
|
{
|
|
|
|
struct inode *trap;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
trap = ovl_get_trap_inode(sb, dir);
|
2019-06-17 20:39:29 +08:00
|
|
|
err = PTR_ERR_OR_ZERO(trap);
|
|
|
|
if (err) {
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
if (err == -ELOOP)
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("conflicting %s path\n", name);
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ptrap = trap;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-12 20:24:34 +08:00
|
|
|
/*
|
|
|
|
* Determine how we treat concurrent use of upperdir/workdir based on the
|
|
|
|
* index feature. This is papering over mount leaks of container runtimes,
|
|
|
|
* for example, an old overlay mount is leaked and now its upperdir is
|
|
|
|
* attempted to be used as a lower layer in a new overlay mount.
|
|
|
|
*/
|
|
|
|
static int ovl_report_in_use(struct ovl_fs *ofs, const char *name)
|
|
|
|
{
|
|
|
|
if (ofs->config.index) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("%s is in-use as upperdir/workdir of another mount, mount with '-o index=off' to override exclusive upperdir protection.\n",
|
2019-07-12 20:24:34 +08:00
|
|
|
name);
|
|
|
|
return -EBUSY;
|
|
|
|
} else {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_warn("%s is in-use as upperdir/workdir of another mount, accessing files from both mounts will result in undefined behavior.\n",
|
2019-07-12 20:24:34 +08:00
|
|
|
name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
static int ovl_get_upper(struct super_block *sb, struct ovl_fs *ofs,
|
2020-06-04 16:48:19 +08:00
|
|
|
struct ovl_layer *upper_layer, struct path *upperpath)
|
2017-11-09 17:23:28 +08:00
|
|
|
{
|
2017-11-10 16:39:15 +08:00
|
|
|
struct vfsmount *upper_mnt;
|
2017-11-09 17:23:28 +08:00
|
|
|
int err;
|
|
|
|
|
2017-11-10 16:39:16 +08:00
|
|
|
err = ovl_mount_dir(ofs->config.upperdir, upperpath);
|
2017-11-09 17:23:28 +08:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2021-04-08 19:30:20 +08:00
|
|
|
/* Upperdir path should not be r/o */
|
|
|
|
if (__mnt_is_readonly(upperpath->mnt)) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("upper fs is r/o, try multi-lower layers mount\n");
|
2017-11-09 17:23:28 +08:00
|
|
|
err = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-11-10 16:39:16 +08:00
|
|
|
err = ovl_check_namelen(upperpath, ofs, ofs->config.upperdir);
|
2017-11-09 17:23:28 +08:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2020-06-04 16:48:19 +08:00
|
|
|
err = ovl_setup_trap(sb, upperpath->dentry, &upper_layer->trap,
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
"upperdir");
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2017-11-10 16:39:15 +08:00
|
|
|
upper_mnt = clone_private_mount(upperpath);
|
|
|
|
err = PTR_ERR(upper_mnt);
|
|
|
|
if (IS_ERR(upper_mnt)) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("failed to clone upperpath\n");
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't inherit atime flags */
|
|
|
|
upper_mnt->mnt_flags &= ~(MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME);
|
2020-06-04 16:48:19 +08:00
|
|
|
upper_layer->mnt = upper_mnt;
|
|
|
|
upper_layer->idx = 0;
|
|
|
|
upper_layer->fsid = 0;
|
2018-09-10 17:43:29 +08:00
|
|
|
|
2020-04-23 19:06:55 +08:00
|
|
|
/*
|
|
|
|
* Inherit SB_NOSEC flag from upperdir.
|
|
|
|
*
|
|
|
|
* This optimization changes behavior when a security related attribute
|
|
|
|
* (suid/sgid/security.*) is changed on an underlying layer. This is
|
|
|
|
* okay because we don't yet have guarantees in that case, but it will
|
|
|
|
* need careful treatment once we want to honour changes to underlying
|
|
|
|
* filesystems.
|
|
|
|
*/
|
|
|
|
if (upper_mnt->mnt_sb->s_flags & SB_NOSEC)
|
|
|
|
sb->s_flags |= SB_NOSEC;
|
|
|
|
|
2020-06-04 16:48:19 +08:00
|
|
|
if (ovl_inuse_trylock(ovl_upper_mnt(ofs)->mnt_root)) {
|
2018-09-10 17:43:29 +08:00
|
|
|
ofs->upperdir_locked = true;
|
|
|
|
} else {
|
2019-07-12 20:24:34 +08:00
|
|
|
err = ovl_report_in_use(ofs, "upperdir");
|
|
|
|
if (err)
|
|
|
|
goto out;
|
2018-09-10 17:43:29 +08:00
|
|
|
}
|
|
|
|
|
2017-11-09 17:23:28 +08:00
|
|
|
err = 0;
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-02-20 15:00:19 +08:00
|
|
|
/*
|
|
|
|
* Returns 1 if RENAME_WHITEOUT is supported, 0 if not supported and
|
|
|
|
* negative values if error is encountered.
|
|
|
|
*/
|
2022-04-04 18:51:43 +08:00
|
|
|
static int ovl_check_rename_whiteout(struct ovl_fs *ofs)
|
2020-02-20 15:00:19 +08:00
|
|
|
{
|
2022-04-04 18:51:43 +08:00
|
|
|
struct dentry *workdir = ofs->workdir;
|
2020-02-20 15:00:19 +08:00
|
|
|
struct inode *dir = d_inode(workdir);
|
|
|
|
struct dentry *temp;
|
|
|
|
struct dentry *dest;
|
|
|
|
struct dentry *whiteout;
|
|
|
|
struct name_snapshot name;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
inode_lock_nested(dir, I_MUTEX_PARENT);
|
|
|
|
|
2022-04-04 18:51:43 +08:00
|
|
|
temp = ovl_create_temp(ofs, workdir, OVL_CATTR(S_IFREG | 0));
|
2020-02-20 15:00:19 +08:00
|
|
|
err = PTR_ERR(temp);
|
|
|
|
if (IS_ERR(temp))
|
|
|
|
goto out_unlock;
|
|
|
|
|
2022-04-04 18:51:43 +08:00
|
|
|
dest = ovl_lookup_temp(ofs, workdir);
|
2020-02-20 15:00:19 +08:00
|
|
|
err = PTR_ERR(dest);
|
|
|
|
if (IS_ERR(dest)) {
|
|
|
|
dput(temp);
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Name is inline and stable - using snapshot as a copy helper */
|
|
|
|
take_dentry_name_snapshot(&name, temp);
|
2022-04-04 18:51:43 +08:00
|
|
|
err = ovl_do_rename(ofs, dir, temp, dir, dest, RENAME_WHITEOUT);
|
2020-02-20 15:00:19 +08:00
|
|
|
if (err) {
|
|
|
|
if (err == -EINVAL)
|
|
|
|
err = 0;
|
|
|
|
goto cleanup_temp;
|
|
|
|
}
|
|
|
|
|
2022-04-04 18:51:49 +08:00
|
|
|
whiteout = ovl_lookup_upper(ofs, name.name.name, workdir, name.name.len);
|
2020-02-20 15:00:19 +08:00
|
|
|
err = PTR_ERR(whiteout);
|
|
|
|
if (IS_ERR(whiteout))
|
|
|
|
goto cleanup_temp;
|
|
|
|
|
|
|
|
err = ovl_is_whiteout(whiteout);
|
|
|
|
|
|
|
|
/* Best effort cleanup of whiteout and temp file */
|
|
|
|
if (err)
|
2022-04-04 18:51:43 +08:00
|
|
|
ovl_cleanup(ofs, dir, whiteout);
|
2020-02-20 15:00:19 +08:00
|
|
|
dput(whiteout);
|
|
|
|
|
|
|
|
cleanup_temp:
|
2022-04-04 18:51:43 +08:00
|
|
|
ovl_cleanup(ofs, dir, temp);
|
2020-02-20 15:00:19 +08:00
|
|
|
release_dentry_name_snapshot(&name);
|
|
|
|
dput(temp);
|
|
|
|
dput(dest);
|
|
|
|
|
|
|
|
out_unlock:
|
|
|
|
inode_unlock(dir);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-04-04 18:51:43 +08:00
|
|
|
static struct dentry *ovl_lookup_or_create(struct ovl_fs *ofs,
|
|
|
|
struct dentry *parent,
|
2020-09-01 02:15:29 +08:00
|
|
|
const char *name, umode_t mode)
|
|
|
|
{
|
|
|
|
size_t len = strlen(name);
|
|
|
|
struct dentry *child;
|
|
|
|
|
|
|
|
inode_lock_nested(parent->d_inode, I_MUTEX_PARENT);
|
2022-04-04 18:51:49 +08:00
|
|
|
child = ovl_lookup_upper(ofs, name, parent, len);
|
2020-09-01 02:15:29 +08:00
|
|
|
if (!IS_ERR(child) && !child->d_inode)
|
2022-04-04 18:51:43 +08:00
|
|
|
child = ovl_create_real(ofs, parent->d_inode, child,
|
2020-09-01 02:15:29 +08:00
|
|
|
OVL_CATTR(mode));
|
|
|
|
inode_unlock(parent->d_inode);
|
|
|
|
dput(parent);
|
|
|
|
|
|
|
|
return child;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Creates $workdir/work/incompat/volatile/dirty file if it is not already
|
|
|
|
* present.
|
|
|
|
*/
|
|
|
|
static int ovl_create_volatile_dirty(struct ovl_fs *ofs)
|
|
|
|
{
|
|
|
|
unsigned int ctr;
|
|
|
|
struct dentry *d = dget(ofs->workbasedir);
|
|
|
|
static const char *const volatile_path[] = {
|
|
|
|
OVL_WORKDIR_NAME, "incompat", "volatile", "dirty"
|
|
|
|
};
|
|
|
|
const char *const *name = volatile_path;
|
|
|
|
|
|
|
|
for (ctr = ARRAY_SIZE(volatile_path); ctr; ctr--, name++) {
|
2022-04-04 18:51:43 +08:00
|
|
|
d = ovl_lookup_or_create(ofs, d, *name, ctr > 1 ? S_IFDIR : S_IFREG);
|
2020-09-01 02:15:29 +08:00
|
|
|
if (IS_ERR(d))
|
|
|
|
return PTR_ERR(d);
|
|
|
|
}
|
|
|
|
dput(d);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
|
2022-08-05 01:11:15 +08:00
|
|
|
const struct path *workpath)
|
2017-11-09 17:23:28 +08:00
|
|
|
{
|
2020-06-04 16:48:19 +08:00
|
|
|
struct vfsmount *mnt = ovl_upper_mnt(ofs);
|
2022-09-24 13:00:00 +08:00
|
|
|
struct dentry *workdir;
|
|
|
|
struct file *tmpfile;
|
2020-02-20 15:03:08 +08:00
|
|
|
bool rename_whiteout;
|
|
|
|
bool d_type;
|
2017-11-07 19:55:04 +08:00
|
|
|
int fh_type;
|
2017-11-09 17:23:28 +08:00
|
|
|
int err;
|
|
|
|
|
2018-01-04 00:54:41 +08:00
|
|
|
err = mnt_want_write(mnt);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2020-08-31 04:28:03 +08:00
|
|
|
workdir = ovl_workdir_create(ofs, OVL_WORKDIR_NAME, false);
|
|
|
|
err = PTR_ERR(workdir);
|
|
|
|
if (IS_ERR_OR_NULL(workdir))
|
2018-01-04 00:54:41 +08:00
|
|
|
goto out;
|
2017-11-09 17:23:28 +08:00
|
|
|
|
2020-08-31 04:28:03 +08:00
|
|
|
ofs->workdir = workdir;
|
|
|
|
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
err = ovl_setup_trap(sb, ofs->workdir, &ofs->workdir_trap, "workdir");
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2017-11-09 17:23:28 +08:00
|
|
|
/*
|
|
|
|
* Upper should support d_type, else whiteouts are visible. Given
|
|
|
|
* workdir and upper are on same fs, we can do iterate_dir() on
|
|
|
|
* workdir. This check requires successful creation of workdir in
|
|
|
|
* previous step.
|
|
|
|
*/
|
|
|
|
err = ovl_check_d_type_supported(workpath);
|
|
|
|
if (err < 0)
|
2018-01-04 00:54:41 +08:00
|
|
|
goto out;
|
2017-11-09 17:23:28 +08:00
|
|
|
|
2020-02-20 15:03:08 +08:00
|
|
|
d_type = err;
|
|
|
|
if (!d_type)
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_warn("upper fs needs to support d_type.\n");
|
2017-11-09 17:23:28 +08:00
|
|
|
|
|
|
|
/* Check if upper/work fs supports O_TMPFILE */
|
2022-09-24 13:00:00 +08:00
|
|
|
tmpfile = ovl_do_tmpfile(ofs, ofs->workdir, S_IFREG | 0);
|
|
|
|
ofs->tmpfile = !IS_ERR(tmpfile);
|
2017-11-10 16:39:16 +08:00
|
|
|
if (ofs->tmpfile)
|
2022-09-24 13:00:00 +08:00
|
|
|
fput(tmpfile);
|
2017-11-09 17:23:28 +08:00
|
|
|
else
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_warn("upper fs does not support tmpfile.\n");
|
2017-11-09 17:23:28 +08:00
|
|
|
|
2020-02-20 15:00:19 +08:00
|
|
|
|
|
|
|
/* Check if upper/work fs supports RENAME_WHITEOUT */
|
2022-04-04 18:51:43 +08:00
|
|
|
err = ovl_check_rename_whiteout(ofs);
|
2020-02-20 15:00:19 +08:00
|
|
|
if (err < 0)
|
|
|
|
goto out;
|
|
|
|
|
2020-02-20 15:03:08 +08:00
|
|
|
rename_whiteout = err;
|
|
|
|
if (!rename_whiteout)
|
2020-02-20 15:00:19 +08:00
|
|
|
pr_warn("upper fs does not support RENAME_WHITEOUT.\n");
|
|
|
|
|
2017-11-09 17:23:28 +08:00
|
|
|
/*
|
2020-12-14 22:26:14 +08:00
|
|
|
* Check if upper/work fs supports (trusted|user).overlay.* xattr
|
2017-11-09 17:23:28 +08:00
|
|
|
*/
|
2022-04-04 18:51:42 +08:00
|
|
|
err = ovl_setxattr(ofs, ofs->workdir, OVL_XATTR_OPAQUE, "0", 1);
|
2017-11-09 17:23:28 +08:00
|
|
|
if (err) {
|
2022-07-27 22:31:30 +08:00
|
|
|
pr_warn("failed to set xattr on upper\n");
|
2017-11-10 16:39:16 +08:00
|
|
|
ofs->noxattr = true;
|
ovl: restrict lower null uuid for "xino=auto"
Commit a888db310195 ("ovl: fix regression with re-formatted lower
squashfs") attempted to fix a regression with existing setups that
use a practice that we are trying to discourage.
The discourage part was described this way in the commit message:
"To avoid the reported regression while still allowing the new features
with single lower squashfs, do not allow decoding origin with lower null
uuid unless user opted-in to one of the new features that require
following the lower inode of non-dir upper (index, xino, metacopy)."
The three mentioned features are disabled by default in Kconfig, so
it was assumed that if they are enabled, the user opted-in for them.
Apparently, distros started to configure CONFIG_OVERLAY_FS_XINO_AUTO=y
some time ago, so users upgrading their kernels can still be affected
by said regression even though they never opted-in for any new feature.
To fix this, treat "xino=on" as "user opted-in", but not "xino=auto".
Since we are changing the behavior of "xino=auto" to no longer follow
to lower origin with null uuid, take this one step further and disable
xino in that corner case. To be consistent, disable xino also in cases
of lower fs without file handle support and upper fs without xattr
support.
Update documentation w.r.t the new "xino=auto" behavior and fix the out
dated bits of documentation regarding "xino" and regarding offline
modifications to lower layers.
Link: https://lore.kernel.org/linux-unionfs/b36a429d7c563730c28d763d4d57a6fc30508a4f.1615216996.git.kevin@kevinlocke.name/
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2021-03-10 00:26:54 +08:00
|
|
|
if (ofs->config.index || ofs->config.metacopy) {
|
|
|
|
ofs->config.index = false;
|
|
|
|
ofs->config.metacopy = false;
|
2022-07-27 22:31:30 +08:00
|
|
|
pr_warn("...falling back to index=off,metacopy=off.\n");
|
ovl: restrict lower null uuid for "xino=auto"
Commit a888db310195 ("ovl: fix regression with re-formatted lower
squashfs") attempted to fix a regression with existing setups that
use a practice that we are trying to discourage.
The discourage part was described this way in the commit message:
"To avoid the reported regression while still allowing the new features
with single lower squashfs, do not allow decoding origin with lower null
uuid unless user opted-in to one of the new features that require
following the lower inode of non-dir upper (index, xino, metacopy)."
The three mentioned features are disabled by default in Kconfig, so
it was assumed that if they are enabled, the user opted-in for them.
Apparently, distros started to configure CONFIG_OVERLAY_FS_XINO_AUTO=y
some time ago, so users upgrading their kernels can still be affected
by said regression even though they never opted-in for any new feature.
To fix this, treat "xino=on" as "user opted-in", but not "xino=auto".
Since we are changing the behavior of "xino=auto" to no longer follow
to lower origin with null uuid, take this one step further and disable
xino in that corner case. To be consistent, disable xino also in cases
of lower fs without file handle support and upper fs without xattr
support.
Update documentation w.r.t the new "xino=auto" behavior and fix the out
dated bits of documentation regarding "xino" and regarding offline
modifications to lower layers.
Link: https://lore.kernel.org/linux-unionfs/b36a429d7c563730c28d763d4d57a6fc30508a4f.1615216996.git.kevin@kevinlocke.name/
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2021-03-10 00:26:54 +08:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* xattr support is required for persistent st_ino.
|
|
|
|
* Without persistent st_ino, xino=auto falls back to xino=off.
|
|
|
|
*/
|
|
|
|
if (ofs->config.xino == OVL_XINO_AUTO) {
|
|
|
|
ofs->config.xino = OVL_XINO_OFF;
|
2022-07-27 22:31:30 +08:00
|
|
|
pr_warn("...falling back to xino=off.\n");
|
ovl: restrict lower null uuid for "xino=auto"
Commit a888db310195 ("ovl: fix regression with re-formatted lower
squashfs") attempted to fix a regression with existing setups that
use a practice that we are trying to discourage.
The discourage part was described this way in the commit message:
"To avoid the reported regression while still allowing the new features
with single lower squashfs, do not allow decoding origin with lower null
uuid unless user opted-in to one of the new features that require
following the lower inode of non-dir upper (index, xino, metacopy)."
The three mentioned features are disabled by default in Kconfig, so
it was assumed that if they are enabled, the user opted-in for them.
Apparently, distros started to configure CONFIG_OVERLAY_FS_XINO_AUTO=y
some time ago, so users upgrading their kernels can still be affected
by said regression even though they never opted-in for any new feature.
To fix this, treat "xino=on" as "user opted-in", but not "xino=auto".
Since we are changing the behavior of "xino=auto" to no longer follow
to lower origin with null uuid, take this one step further and disable
xino in that corner case. To be consistent, disable xino also in cases
of lower fs without file handle support and upper fs without xattr
support.
Update documentation w.r.t the new "xino=auto" behavior and fix the out
dated bits of documentation regarding "xino" and regarding offline
modifications to lower layers.
Link: https://lore.kernel.org/linux-unionfs/b36a429d7c563730c28d763d4d57a6fc30508a4f.1615216996.git.kevin@kevinlocke.name/
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2021-03-10 00:26:54 +08:00
|
|
|
}
|
2022-07-27 22:31:30 +08:00
|
|
|
if (err == -EPERM && !ofs->config.userxattr)
|
|
|
|
pr_info("try mounting with 'userxattr' option\n");
|
2018-01-04 00:54:41 +08:00
|
|
|
err = 0;
|
2017-11-09 17:23:28 +08:00
|
|
|
} else {
|
2022-04-04 18:51:42 +08:00
|
|
|
ovl_removexattr(ofs, ofs->workdir, OVL_XATTR_OPAQUE);
|
2017-11-09 17:23:28 +08:00
|
|
|
}
|
|
|
|
|
2020-02-20 15:03:08 +08:00
|
|
|
/*
|
|
|
|
* We allowed sub-optimal upper fs configuration and don't want to break
|
|
|
|
* users over kernel upgrade, but we never allowed remote upper fs, so
|
|
|
|
* we can enforce strict requirements for remote upper fs.
|
|
|
|
*/
|
|
|
|
if (ovl_dentry_remote(ofs->workdir) &&
|
|
|
|
(!d_type || !rename_whiteout || ofs->noxattr)) {
|
|
|
|
pr_err("upper fs missing required features.\n");
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-09-01 02:15:29 +08:00
|
|
|
/*
|
|
|
|
* For volatile mount, create a incompat/volatile/dirty file to keep
|
|
|
|
* track of it.
|
|
|
|
*/
|
|
|
|
if (ofs->config.ovl_volatile) {
|
|
|
|
err = ovl_create_volatile_dirty(ofs);
|
|
|
|
if (err < 0) {
|
|
|
|
pr_err("Failed to create volatile/dirty file.\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-09 17:23:28 +08:00
|
|
|
/* Check if upper/work fs supports file handles */
|
2017-11-07 19:55:04 +08:00
|
|
|
fh_type = ovl_can_decode_fh(ofs->workdir->d_sb);
|
|
|
|
if (ofs->config.index && !fh_type) {
|
2017-11-10 16:39:16 +08:00
|
|
|
ofs->config.index = false;
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_warn("upper fs does not support file handles, falling back to index=off.\n");
|
2017-11-09 17:23:28 +08:00
|
|
|
}
|
|
|
|
|
2017-11-07 19:55:04 +08:00
|
|
|
/* Check if upper fs has 32bit inode numbers */
|
|
|
|
if (fh_type != FILEID_INO32_GEN)
|
2019-11-17 00:14:41 +08:00
|
|
|
ofs->xino_mode = -1;
|
2017-11-07 19:55:04 +08:00
|
|
|
|
2018-01-19 17:26:53 +08:00
|
|
|
/* NFS export of r/w mount depends on index */
|
|
|
|
if (ofs->config.nfs_export && !ofs->config.index) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_warn("NFS export requires \"index=on\", falling back to nfs_export=off.\n");
|
2018-01-19 17:26:53 +08:00
|
|
|
ofs->config.nfs_export = false;
|
|
|
|
}
|
2018-01-04 00:54:41 +08:00
|
|
|
out:
|
|
|
|
mnt_drop_write(mnt);
|
|
|
|
return err;
|
2017-11-09 17:23:28 +08:00
|
|
|
}
|
|
|
|
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
static int ovl_get_workdir(struct super_block *sb, struct ovl_fs *ofs,
|
2022-08-05 01:11:15 +08:00
|
|
|
const struct path *upperpath)
|
2017-11-10 16:39:15 +08:00
|
|
|
{
|
|
|
|
int err;
|
2017-11-10 16:39:15 +08:00
|
|
|
struct path workpath = { };
|
2017-11-10 16:39:15 +08:00
|
|
|
|
2017-11-10 16:39:16 +08:00
|
|
|
err = ovl_mount_dir(ofs->config.workdir, &workpath);
|
2017-11-10 16:39:15 +08:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
err = -EINVAL;
|
2017-11-10 16:39:15 +08:00
|
|
|
if (upperpath->mnt != workpath.mnt) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("workdir and upperdir must reside under the same mount\n");
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out;
|
|
|
|
}
|
2017-11-10 16:39:15 +08:00
|
|
|
if (!ovl_workdir_ok(workpath.dentry, upperpath->dentry)) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("workdir and upperdir must be separate subtrees\n");
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2018-09-10 17:43:29 +08:00
|
|
|
ofs->workbasedir = dget(workpath.dentry);
|
|
|
|
|
|
|
|
if (ovl_inuse_trylock(ofs->workbasedir)) {
|
2017-11-10 16:39:16 +08:00
|
|
|
ofs->workdir_locked = true;
|
2017-11-10 16:39:15 +08:00
|
|
|
} else {
|
2019-07-12 20:24:34 +08:00
|
|
|
err = ovl_report_in_use(ofs, "workdir");
|
|
|
|
if (err)
|
|
|
|
goto out;
|
2017-11-10 16:39:15 +08:00
|
|
|
}
|
|
|
|
|
2019-07-12 20:24:34 +08:00
|
|
|
err = ovl_setup_trap(sb, ofs->workbasedir, &ofs->workbasedir_trap,
|
|
|
|
"workdir");
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
err = ovl_make_workdir(sb, ofs, &workpath);
|
2017-11-10 16:39:15 +08:00
|
|
|
|
2017-11-10 16:39:15 +08:00
|
|
|
out:
|
2017-11-10 16:39:15 +08:00
|
|
|
path_put(&workpath);
|
|
|
|
|
2017-11-10 16:39:15 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs,
|
2022-08-05 01:11:15 +08:00
|
|
|
struct ovl_entry *oe, const struct path *upperpath)
|
2017-11-09 17:23:28 +08:00
|
|
|
{
|
2020-06-04 16:48:19 +08:00
|
|
|
struct vfsmount *mnt = ovl_upper_mnt(ofs);
|
2020-08-31 04:28:03 +08:00
|
|
|
struct dentry *indexdir;
|
2017-11-09 17:23:28 +08:00
|
|
|
int err;
|
|
|
|
|
2018-01-04 00:54:41 +08:00
|
|
|
err = mnt_want_write(mnt);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2017-11-09 17:23:28 +08:00
|
|
|
/* Verify lower root is upper root origin */
|
2020-09-02 16:58:49 +08:00
|
|
|
err = ovl_verify_origin(ofs, upperpath->dentry,
|
|
|
|
oe->lowerstack[0].dentry, true);
|
2017-11-09 17:23:28 +08:00
|
|
|
if (err) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("failed to verify upper root origin\n");
|
2017-11-09 17:23:28 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-07-13 22:19:43 +08:00
|
|
|
/* index dir will act also as workdir */
|
|
|
|
iput(ofs->workdir_trap);
|
|
|
|
ofs->workdir_trap = NULL;
|
|
|
|
dput(ofs->workdir);
|
|
|
|
ofs->workdir = NULL;
|
2020-08-31 04:28:03 +08:00
|
|
|
indexdir = ovl_workdir_create(ofs, OVL_INDEXDIR_NAME, true);
|
|
|
|
if (IS_ERR(indexdir)) {
|
|
|
|
err = PTR_ERR(indexdir);
|
|
|
|
} else if (indexdir) {
|
|
|
|
ofs->indexdir = indexdir;
|
|
|
|
ofs->workdir = dget(indexdir);
|
ovl: fix oops in ovl_indexdir_cleanup() with nfs_export=on
Mounting with nfs_export=on, xfstests overlay/031 triggers a kernel panic
since v5.8-rc1 overlayfs updates.
overlayfs: orphan index entry (index/00fb1..., ftype=4000, nlink=2)
BUG: kernel NULL pointer dereference, address: 0000000000000030
RIP: 0010:ovl_cleanup_and_whiteout+0x28/0x220 [overlay]
Bisect point at commit c21c839b8448 ("ovl: whiteout inode sharing")
Minimal reproducer:
--------------------------------------------------
rm -rf l u w m
mkdir -p l u w m
mkdir -p l/testdir
touch l/testdir/testfile
mount -t overlay -o lowerdir=l,upperdir=u,workdir=w,nfs_export=on overlay m
echo 1 > m/testdir/testfile
umount m
rm -rf u/testdir
mount -t overlay -o lowerdir=l,upperdir=u,workdir=w,nfs_export=on overlay m
umount m
--------------------------------------------------
When mount with nfs_export=on, and fail to verify an orphan index, we're
cleaning this index from indexdir by calling ovl_cleanup_and_whiteout().
This dereferences ofs->workdir, that was earlier set to NULL.
The design was that ovl->workdir will point at ovl->indexdir, but we are
assigning ofs->indexdir to ofs->workdir only after ovl_indexdir_cleanup().
There is no reason not to do it sooner, because once we get success from
ofs->indexdir = ovl_workdir_create(... there is no turning back.
Reported-and-tested-by: Murphy Zhou <jencce.kernel@gmail.com>
Fixes: c21c839b8448 ("ovl: whiteout inode sharing")
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2020-06-21 14:37:59 +08:00
|
|
|
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
err = ovl_setup_trap(sb, ofs->indexdir, &ofs->indexdir_trap,
|
|
|
|
"indexdir");
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2018-01-11 16:47:03 +08:00
|
|
|
/*
|
|
|
|
* Verify upper root is exclusively associated with index dir.
|
2020-12-14 22:26:14 +08:00
|
|
|
* Older kernels stored upper fh in ".overlay.origin"
|
2018-01-11 16:47:03 +08:00
|
|
|
* xattr. If that xattr exists, verify that it is a match to
|
|
|
|
* upper dir file handle. In any case, verify or set xattr
|
2020-12-14 22:26:14 +08:00
|
|
|
* ".overlay.upper" to indicate that index may have
|
2018-01-11 16:47:03 +08:00
|
|
|
* directory entries.
|
|
|
|
*/
|
2020-09-02 16:58:49 +08:00
|
|
|
if (ovl_check_origin_xattr(ofs, ofs->indexdir)) {
|
|
|
|
err = ovl_verify_set_fh(ofs, ofs->indexdir,
|
|
|
|
OVL_XATTR_ORIGIN,
|
2018-01-11 16:47:03 +08:00
|
|
|
upperpath->dentry, true, false);
|
|
|
|
if (err)
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("failed to verify index dir 'origin' xattr\n");
|
2018-01-11 16:47:03 +08:00
|
|
|
}
|
2020-09-02 16:58:49 +08:00
|
|
|
err = ovl_verify_upper(ofs, ofs->indexdir, upperpath->dentry,
|
|
|
|
true);
|
2017-11-09 17:23:28 +08:00
|
|
|
if (err)
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("failed to verify index dir 'upper' xattr\n");
|
2017-11-09 17:23:28 +08:00
|
|
|
|
|
|
|
/* Cleanup bad/stale/orphan index entries */
|
|
|
|
if (!err)
|
2017-12-13 04:40:46 +08:00
|
|
|
err = ovl_indexdir_cleanup(ofs);
|
2017-11-09 17:23:28 +08:00
|
|
|
}
|
2017-11-10 16:39:16 +08:00
|
|
|
if (err || !ofs->indexdir)
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_warn("try deleting index dir or mounting with '-o index=off' to disable inodes index.\n");
|
2017-11-09 17:23:28 +08:00
|
|
|
|
|
|
|
out:
|
2018-01-04 00:54:41 +08:00
|
|
|
mnt_drop_write(mnt);
|
2017-11-09 17:23:28 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-09-03 14:12:09 +08:00
|
|
|
static bool ovl_lower_uuid_ok(struct ovl_fs *ofs, const uuid_t *uuid)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
2020-06-04 16:48:19 +08:00
|
|
|
if (!ofs->config.nfs_export && !ovl_upper_mnt(ofs))
|
2018-09-03 14:12:09 +08:00
|
|
|
return true;
|
|
|
|
|
2020-07-08 21:16:13 +08:00
|
|
|
/*
|
|
|
|
* We allow using single lower with null uuid for index and nfs_export
|
|
|
|
* for example to support those features with single lower squashfs.
|
|
|
|
* To avoid regressions in setups of overlay with re-formatted lower
|
|
|
|
* squashfs, do not allow decoding origin with lower null uuid unless
|
|
|
|
* user opted-in to one of the new features that require following the
|
|
|
|
* lower inode of non-dir upper.
|
|
|
|
*/
|
2021-05-28 01:45:46 +08:00
|
|
|
if (ovl_allow_offline_changes(ofs) && uuid_is_null(uuid))
|
2020-07-08 21:16:13 +08:00
|
|
|
return false;
|
|
|
|
|
2019-11-17 00:52:20 +08:00
|
|
|
for (i = 0; i < ofs->numfs; i++) {
|
2018-09-03 14:12:09 +08:00
|
|
|
/*
|
|
|
|
* We use uuid to associate an overlay lower file handle with a
|
|
|
|
* lower layer, so we can accept lower fs with null uuid as long
|
|
|
|
* as all lower layers with null uuid are on the same fs.
|
2019-11-15 04:28:41 +08:00
|
|
|
* if we detect multiple lower fs with the same uuid, we
|
|
|
|
* disable lower file handle decoding on all of them.
|
2018-09-03 14:12:09 +08:00
|
|
|
*/
|
2019-11-17 00:52:20 +08:00
|
|
|
if (ofs->fs[i].is_lower &&
|
|
|
|
uuid_equal(&ofs->fs[i].sb->s_uuid, uuid)) {
|
2020-01-15 03:59:22 +08:00
|
|
|
ofs->fs[i].bad_uuid = true;
|
2018-09-03 14:12:09 +08:00
|
|
|
return false;
|
2019-11-15 04:28:41 +08:00
|
|
|
}
|
2018-09-03 14:12:09 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-03-29 01:22:41 +08:00
|
|
|
/* Get a unique fsid for the layer */
|
2018-09-03 14:12:09 +08:00
|
|
|
static int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path)
|
2018-03-29 01:22:41 +08:00
|
|
|
{
|
2018-09-03 14:12:09 +08:00
|
|
|
struct super_block *sb = path->mnt->mnt_sb;
|
2018-03-29 01:22:41 +08:00
|
|
|
unsigned int i;
|
|
|
|
dev_t dev;
|
|
|
|
int err;
|
2019-11-15 04:28:41 +08:00
|
|
|
bool bad_uuid = false;
|
ovl: restrict lower null uuid for "xino=auto"
Commit a888db310195 ("ovl: fix regression with re-formatted lower
squashfs") attempted to fix a regression with existing setups that
use a practice that we are trying to discourage.
The discourage part was described this way in the commit message:
"To avoid the reported regression while still allowing the new features
with single lower squashfs, do not allow decoding origin with lower null
uuid unless user opted-in to one of the new features that require
following the lower inode of non-dir upper (index, xino, metacopy)."
The three mentioned features are disabled by default in Kconfig, so
it was assumed that if they are enabled, the user opted-in for them.
Apparently, distros started to configure CONFIG_OVERLAY_FS_XINO_AUTO=y
some time ago, so users upgrading their kernels can still be affected
by said regression even though they never opted-in for any new feature.
To fix this, treat "xino=on" as "user opted-in", but not "xino=auto".
Since we are changing the behavior of "xino=auto" to no longer follow
to lower origin with null uuid, take this one step further and disable
xino in that corner case. To be consistent, disable xino also in cases
of lower fs without file handle support and upper fs without xattr
support.
Update documentation w.r.t the new "xino=auto" behavior and fix the out
dated bits of documentation regarding "xino" and regarding offline
modifications to lower layers.
Link: https://lore.kernel.org/linux-unionfs/b36a429d7c563730c28d763d4d57a6fc30508a4f.1615216996.git.kevin@kevinlocke.name/
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2021-03-10 00:26:54 +08:00
|
|
|
bool warn = false;
|
2018-03-29 01:22:41 +08:00
|
|
|
|
2020-01-15 03:59:22 +08:00
|
|
|
for (i = 0; i < ofs->numfs; i++) {
|
|
|
|
if (ofs->fs[i].sb == sb)
|
|
|
|
return i;
|
2018-03-29 01:22:41 +08:00
|
|
|
}
|
|
|
|
|
2018-09-03 14:12:09 +08:00
|
|
|
if (!ovl_lower_uuid_ok(ofs, &sb->s_uuid)) {
|
2019-11-15 04:28:41 +08:00
|
|
|
bad_uuid = true;
|
ovl: restrict lower null uuid for "xino=auto"
Commit a888db310195 ("ovl: fix regression with re-formatted lower
squashfs") attempted to fix a regression with existing setups that
use a practice that we are trying to discourage.
The discourage part was described this way in the commit message:
"To avoid the reported regression while still allowing the new features
with single lower squashfs, do not allow decoding origin with lower null
uuid unless user opted-in to one of the new features that require
following the lower inode of non-dir upper (index, xino, metacopy)."
The three mentioned features are disabled by default in Kconfig, so
it was assumed that if they are enabled, the user opted-in for them.
Apparently, distros started to configure CONFIG_OVERLAY_FS_XINO_AUTO=y
some time ago, so users upgrading their kernels can still be affected
by said regression even though they never opted-in for any new feature.
To fix this, treat "xino=on" as "user opted-in", but not "xino=auto".
Since we are changing the behavior of "xino=auto" to no longer follow
to lower origin with null uuid, take this one step further and disable
xino in that corner case. To be consistent, disable xino also in cases
of lower fs without file handle support and upper fs without xattr
support.
Update documentation w.r.t the new "xino=auto" behavior and fix the out
dated bits of documentation regarding "xino" and regarding offline
modifications to lower layers.
Link: https://lore.kernel.org/linux-unionfs/b36a429d7c563730c28d763d4d57a6fc30508a4f.1615216996.git.kevin@kevinlocke.name/
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2021-03-10 00:26:54 +08:00
|
|
|
if (ofs->config.xino == OVL_XINO_AUTO) {
|
|
|
|
ofs->config.xino = OVL_XINO_OFF;
|
|
|
|
warn = true;
|
|
|
|
}
|
2019-11-15 04:28:41 +08:00
|
|
|
if (ofs->config.index || ofs->config.nfs_export) {
|
|
|
|
ofs->config.index = false;
|
|
|
|
ofs->config.nfs_export = false;
|
ovl: restrict lower null uuid for "xino=auto"
Commit a888db310195 ("ovl: fix regression with re-formatted lower
squashfs") attempted to fix a regression with existing setups that
use a practice that we are trying to discourage.
The discourage part was described this way in the commit message:
"To avoid the reported regression while still allowing the new features
with single lower squashfs, do not allow decoding origin with lower null
uuid unless user opted-in to one of the new features that require
following the lower inode of non-dir upper (index, xino, metacopy)."
The three mentioned features are disabled by default in Kconfig, so
it was assumed that if they are enabled, the user opted-in for them.
Apparently, distros started to configure CONFIG_OVERLAY_FS_XINO_AUTO=y
some time ago, so users upgrading their kernels can still be affected
by said regression even though they never opted-in for any new feature.
To fix this, treat "xino=on" as "user opted-in", but not "xino=auto".
Since we are changing the behavior of "xino=auto" to no longer follow
to lower origin with null uuid, take this one step further and disable
xino in that corner case. To be consistent, disable xino also in cases
of lower fs without file handle support and upper fs without xattr
support.
Update documentation w.r.t the new "xino=auto" behavior and fix the out
dated bits of documentation regarding "xino" and regarding offline
modifications to lower layers.
Link: https://lore.kernel.org/linux-unionfs/b36a429d7c563730c28d763d4d57a6fc30508a4f.1615216996.git.kevin@kevinlocke.name/
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2021-03-10 00:26:54 +08:00
|
|
|
warn = true;
|
|
|
|
}
|
|
|
|
if (warn) {
|
|
|
|
pr_warn("%s uuid detected in lower fs '%pd2', falling back to xino=%s,index=off,nfs_export=off.\n",
|
2019-11-15 04:28:41 +08:00
|
|
|
uuid_is_null(&sb->s_uuid) ? "null" :
|
|
|
|
"conflicting",
|
ovl: restrict lower null uuid for "xino=auto"
Commit a888db310195 ("ovl: fix regression with re-formatted lower
squashfs") attempted to fix a regression with existing setups that
use a practice that we are trying to discourage.
The discourage part was described this way in the commit message:
"To avoid the reported regression while still allowing the new features
with single lower squashfs, do not allow decoding origin with lower null
uuid unless user opted-in to one of the new features that require
following the lower inode of non-dir upper (index, xino, metacopy)."
The three mentioned features are disabled by default in Kconfig, so
it was assumed that if they are enabled, the user opted-in for them.
Apparently, distros started to configure CONFIG_OVERLAY_FS_XINO_AUTO=y
some time ago, so users upgrading their kernels can still be affected
by said regression even though they never opted-in for any new feature.
To fix this, treat "xino=on" as "user opted-in", but not "xino=auto".
Since we are changing the behavior of "xino=auto" to no longer follow
to lower origin with null uuid, take this one step further and disable
xino in that corner case. To be consistent, disable xino also in cases
of lower fs without file handle support and upper fs without xattr
support.
Update documentation w.r.t the new "xino=auto" behavior and fix the out
dated bits of documentation regarding "xino" and regarding offline
modifications to lower layers.
Link: https://lore.kernel.org/linux-unionfs/b36a429d7c563730c28d763d4d57a6fc30508a4f.1615216996.git.kevin@kevinlocke.name/
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2021-03-10 00:26:54 +08:00
|
|
|
path->dentry, ovl_xino_str[ofs->config.xino]);
|
2019-11-15 04:28:41 +08:00
|
|
|
}
|
2018-09-03 14:12:09 +08:00
|
|
|
}
|
|
|
|
|
2018-03-29 01:22:41 +08:00
|
|
|
err = get_anon_bdev(&dev);
|
|
|
|
if (err) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("failed to get anonymous bdev for lowerpath\n");
|
2018-03-29 01:22:41 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-01-15 03:59:22 +08:00
|
|
|
ofs->fs[ofs->numfs].sb = sb;
|
|
|
|
ofs->fs[ofs->numfs].pseudo_dev = dev;
|
|
|
|
ofs->fs[ofs->numfs].bad_uuid = bad_uuid;
|
2018-03-29 01:22:41 +08:00
|
|
|
|
2020-01-15 03:59:22 +08:00
|
|
|
return ofs->numfs++;
|
2018-03-29 01:22:41 +08:00
|
|
|
}
|
|
|
|
|
2019-11-15 20:12:40 +08:00
|
|
|
static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
|
2020-06-04 16:48:19 +08:00
|
|
|
struct path *stack, unsigned int numlower,
|
|
|
|
struct ovl_layer *layers)
|
2017-11-10 16:39:15 +08:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
err = -ENOMEM;
|
2020-01-15 03:59:22 +08:00
|
|
|
ofs->fs = kcalloc(numlower + 1, sizeof(struct ovl_sb), GFP_KERNEL);
|
|
|
|
if (ofs->fs == NULL)
|
2018-03-29 01:22:41 +08:00
|
|
|
goto out;
|
|
|
|
|
2020-01-15 03:59:22 +08:00
|
|
|
/* idx/fsid 0 are reserved for upper fs even with lower only overlay */
|
|
|
|
ofs->numfs++;
|
|
|
|
|
|
|
|
/*
|
2020-01-15 04:17:25 +08:00
|
|
|
* All lower layers that share the same fs as upper layer, use the same
|
|
|
|
* pseudo_dev as upper layer. Allocate fs[0].pseudo_dev even for lower
|
|
|
|
* only overlay to simplify ovl_fs_free().
|
2019-11-17 00:52:20 +08:00
|
|
|
* is_lower will be set if upper fs is shared with a lower layer.
|
2020-01-15 03:59:22 +08:00
|
|
|
*/
|
2020-01-15 04:17:25 +08:00
|
|
|
err = get_anon_bdev(&ofs->fs[0].pseudo_dev);
|
|
|
|
if (err) {
|
|
|
|
pr_err("failed to get anonymous bdev for upper fs\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-06-04 16:48:19 +08:00
|
|
|
if (ovl_upper_mnt(ofs)) {
|
|
|
|
ofs->fs[0].sb = ovl_upper_mnt(ofs)->mnt_sb;
|
2019-11-17 00:52:20 +08:00
|
|
|
ofs->fs[0].is_lower = false;
|
2020-01-15 03:59:22 +08:00
|
|
|
}
|
|
|
|
|
2017-11-10 16:39:15 +08:00
|
|
|
for (i = 0; i < numlower; i++) {
|
|
|
|
struct vfsmount *mnt;
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
struct inode *trap;
|
2018-03-29 01:22:41 +08:00
|
|
|
int fsid;
|
2017-11-10 16:39:15 +08:00
|
|
|
|
2018-09-03 14:12:09 +08:00
|
|
|
err = fsid = ovl_get_fsid(ofs, &stack[i]);
|
2018-03-29 01:22:41 +08:00
|
|
|
if (err < 0)
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out;
|
|
|
|
|
2020-06-16 16:30:43 +08:00
|
|
|
/*
|
|
|
|
* Check if lower root conflicts with this overlay layers before
|
|
|
|
* checking if it is in-use as upperdir/workdir of "another"
|
|
|
|
* mount, because we do not bother to check in ovl_is_inuse() if
|
|
|
|
* the upperdir/workdir is in fact in-use by our
|
|
|
|
* upperdir/workdir.
|
|
|
|
*/
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
err = ovl_setup_trap(sb, stack[i].dentry, &trap, "lowerdir");
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2019-07-12 20:24:34 +08:00
|
|
|
if (ovl_is_inuse(stack[i].dentry)) {
|
|
|
|
err = ovl_report_in_use(ofs, "lowerdir");
|
2020-06-16 16:30:43 +08:00
|
|
|
if (err) {
|
|
|
|
iput(trap);
|
2019-07-12 20:24:34 +08:00
|
|
|
goto out;
|
2020-06-16 16:30:43 +08:00
|
|
|
}
|
2019-07-12 20:24:34 +08:00
|
|
|
}
|
|
|
|
|
2017-11-10 16:39:15 +08:00
|
|
|
mnt = clone_private_mount(&stack[i]);
|
|
|
|
err = PTR_ERR(mnt);
|
|
|
|
if (IS_ERR(mnt)) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("failed to clone lowerpath\n");
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
iput(trap);
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out;
|
|
|
|
}
|
2018-03-29 01:22:41 +08:00
|
|
|
|
2017-11-10 16:39:15 +08:00
|
|
|
/*
|
|
|
|
* Make lower layers R/O. That way fchmod/fchown on lower file
|
|
|
|
* will fail instead of modifying lower fs.
|
|
|
|
*/
|
|
|
|
mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME;
|
|
|
|
|
2020-01-24 16:46:45 +08:00
|
|
|
layers[ofs->numlayer].trap = trap;
|
|
|
|
layers[ofs->numlayer].mnt = mnt;
|
|
|
|
layers[ofs->numlayer].idx = ofs->numlayer;
|
|
|
|
layers[ofs->numlayer].fsid = fsid;
|
|
|
|
layers[ofs->numlayer].fs = &ofs->fs[fsid];
|
2019-11-15 20:12:40 +08:00
|
|
|
ofs->numlayer++;
|
2019-11-17 00:52:20 +08:00
|
|
|
ofs->fs[fsid].is_lower = true;
|
2017-11-10 16:39:15 +08:00
|
|
|
}
|
2017-11-07 19:55:04 +08:00
|
|
|
|
2018-03-29 14:08:18 +08:00
|
|
|
/*
|
|
|
|
* When all layers on same fs, overlay can use real inode numbers.
|
2020-02-21 22:34:45 +08:00
|
|
|
* With mount option "xino=<on|auto>", mounter declares that there are
|
|
|
|
* enough free high bits in underlying fs to hold the unique fsid.
|
2018-03-29 14:08:18 +08:00
|
|
|
* If overlayfs does encounter underlying inodes using the high xino
|
|
|
|
* bits reserved for fsid, it emits a warning and uses the original
|
2020-02-21 22:34:44 +08:00
|
|
|
* inode number or a non persistent inode number allocated from a
|
|
|
|
* dedicated range.
|
2018-03-29 14:08:18 +08:00
|
|
|
*/
|
2020-06-04 16:48:19 +08:00
|
|
|
if (ofs->numfs - !ovl_upper_mnt(ofs) == 1) {
|
2019-11-17 00:14:41 +08:00
|
|
|
if (ofs->config.xino == OVL_XINO_ON)
|
|
|
|
pr_info("\"xino=on\" is useless with all layers on same fs, ignore.\n");
|
|
|
|
ofs->xino_mode = 0;
|
2020-02-21 22:34:42 +08:00
|
|
|
} else if (ofs->config.xino == OVL_XINO_OFF) {
|
|
|
|
ofs->xino_mode = -1;
|
2020-02-21 22:34:45 +08:00
|
|
|
} else if (ofs->xino_mode < 0) {
|
2018-03-29 14:08:18 +08:00
|
|
|
/*
|
2020-01-15 03:59:22 +08:00
|
|
|
* This is a roundup of number of bits needed for encoding
|
2020-02-21 22:34:44 +08:00
|
|
|
* fsid, where fsid 0 is reserved for upper fs (even with
|
|
|
|
* lower only overlay) +1 extra bit is reserved for the non
|
|
|
|
* persistent inode number range that is used for resolving
|
|
|
|
* xino lower bits overflow.
|
2018-03-29 14:08:18 +08:00
|
|
|
*/
|
2020-02-21 22:34:44 +08:00
|
|
|
BUILD_BUG_ON(ilog2(OVL_MAX_STACK) > 30);
|
|
|
|
ofs->xino_mode = ilog2(ofs->numfs - 1) + 2;
|
2018-03-29 14:08:18 +08:00
|
|
|
}
|
|
|
|
|
2019-11-17 00:14:41 +08:00
|
|
|
if (ofs->xino_mode > 0) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_info("\"xino\" feature enabled using %d upper inode bits.\n",
|
2019-11-17 00:14:41 +08:00
|
|
|
ofs->xino_mode);
|
2018-03-29 14:08:18 +08:00
|
|
|
}
|
2017-11-07 19:55:04 +08:00
|
|
|
|
2017-11-10 16:39:15 +08:00
|
|
|
err = 0;
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2017-11-10 16:39:15 +08:00
|
|
|
static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb,
|
2020-06-04 16:48:19 +08:00
|
|
|
const char *lower, unsigned int numlower,
|
|
|
|
struct ovl_fs *ofs, struct ovl_layer *layers)
|
2017-11-09 17:23:28 +08:00
|
|
|
{
|
|
|
|
int err;
|
2017-11-10 16:39:15 +08:00
|
|
|
struct path *stack = NULL;
|
2020-06-04 16:48:19 +08:00
|
|
|
unsigned int i;
|
2017-11-10 16:39:15 +08:00
|
|
|
struct ovl_entry *oe;
|
2017-11-09 17:23:28 +08:00
|
|
|
|
2020-06-04 16:48:19 +08:00
|
|
|
if (!ofs->config.upperdir && numlower == 1) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("at least 2 lowerdir are needed while upperdir nonexistent\n");
|
2020-06-04 16:48:19 +08:00
|
|
|
return ERR_PTR(-EINVAL);
|
2017-11-09 17:23:28 +08:00
|
|
|
}
|
|
|
|
|
2020-06-04 16:48:19 +08:00
|
|
|
stack = kcalloc(numlower, sizeof(struct path), GFP_KERNEL);
|
2017-11-09 17:23:28 +08:00
|
|
|
if (!stack)
|
2020-06-04 16:48:19 +08:00
|
|
|
return ERR_PTR(-ENOMEM);
|
2017-11-09 17:23:28 +08:00
|
|
|
|
|
|
|
err = -EINVAL;
|
2020-06-04 16:48:19 +08:00
|
|
|
for (i = 0; i < numlower; i++) {
|
|
|
|
err = ovl_lower_dir(lower, &stack[i], ofs, &sb->s_stack_depth);
|
2017-11-09 17:23:28 +08:00
|
|
|
if (err)
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out_err;
|
2017-11-09 17:23:28 +08:00
|
|
|
|
|
|
|
lower = strchr(lower, '\0') + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
sb->s_stack_depth++;
|
|
|
|
if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("maximum fs stacking depth exceeded\n");
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out_err;
|
2017-11-09 17:23:28 +08:00
|
|
|
}
|
|
|
|
|
2020-06-04 16:48:19 +08:00
|
|
|
err = ovl_get_layers(sb, ofs, stack, numlower, layers);
|
2017-11-10 16:39:15 +08:00
|
|
|
if (err)
|
|
|
|
goto out_err;
|
|
|
|
|
|
|
|
err = -ENOMEM;
|
|
|
|
oe = ovl_alloc_entry(numlower);
|
|
|
|
if (!oe)
|
|
|
|
goto out_err;
|
|
|
|
|
|
|
|
for (i = 0; i < numlower; i++) {
|
|
|
|
oe->lowerstack[i].dentry = dget(stack[i].dentry);
|
2019-11-15 20:12:40 +08:00
|
|
|
oe->lowerstack[i].layer = &ofs->layers[i+1];
|
2017-11-10 16:39:15 +08:00
|
|
|
}
|
2017-11-09 17:23:28 +08:00
|
|
|
|
|
|
|
out:
|
|
|
|
for (i = 0; i < numlower; i++)
|
|
|
|
path_put(&stack[i]);
|
|
|
|
kfree(stack);
|
2017-11-10 16:39:15 +08:00
|
|
|
|
|
|
|
return oe;
|
|
|
|
|
|
|
|
out_err:
|
|
|
|
oe = ERR_PTR(err);
|
2017-11-09 17:23:28 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
/*
|
|
|
|
* Check if this layer root is a descendant of:
|
|
|
|
* - another layer of this overlayfs instance
|
|
|
|
* - upper/work dir of any overlayfs instance
|
|
|
|
*/
|
2019-07-12 20:24:34 +08:00
|
|
|
static int ovl_check_layer(struct super_block *sb, struct ovl_fs *ofs,
|
2021-04-12 18:00:37 +08:00
|
|
|
struct dentry *dentry, const char *name,
|
|
|
|
bool is_lower)
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
{
|
2019-06-18 21:06:16 +08:00
|
|
|
struct dentry *next = dentry, *parent;
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
int err = 0;
|
|
|
|
|
2019-06-18 21:06:16 +08:00
|
|
|
if (!dentry)
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
return 0;
|
|
|
|
|
2019-06-18 21:06:16 +08:00
|
|
|
parent = dget_parent(next);
|
|
|
|
|
|
|
|
/* Walk back ancestors to root (inclusive) looking for traps */
|
|
|
|
while (!err && parent != next) {
|
2021-04-12 18:00:37 +08:00
|
|
|
if (is_lower && ovl_lookup_trap_inode(sb, parent)) {
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
err = -ELOOP;
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("overlapping %s path\n", name);
|
2019-07-12 20:24:34 +08:00
|
|
|
} else if (ovl_is_inuse(parent)) {
|
|
|
|
err = ovl_report_in_use(ofs, name);
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
}
|
|
|
|
next = parent;
|
2019-06-18 21:06:16 +08:00
|
|
|
parent = dget_parent(next);
|
|
|
|
dput(next);
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
}
|
|
|
|
|
2019-06-18 21:06:16 +08:00
|
|
|
dput(parent);
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if any of the layers or work dirs overlap.
|
|
|
|
*/
|
|
|
|
static int ovl_check_overlapping_layers(struct super_block *sb,
|
|
|
|
struct ovl_fs *ofs)
|
|
|
|
{
|
|
|
|
int i, err;
|
|
|
|
|
2020-06-04 16:48:19 +08:00
|
|
|
if (ovl_upper_mnt(ofs)) {
|
|
|
|
err = ovl_check_layer(sb, ofs, ovl_upper_mnt(ofs)->mnt_root,
|
2021-04-12 18:00:37 +08:00
|
|
|
"upperdir", false);
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Checking workbasedir avoids hitting ovl_is_inuse(parent) of
|
|
|
|
* this instance and covers overlapping work and index dirs,
|
|
|
|
* unless work or index dir have been moved since created inside
|
|
|
|
* workbasedir. In that case, we already have their traps in
|
|
|
|
* inode cache and we will catch that case on lookup.
|
|
|
|
*/
|
2021-04-12 18:00:37 +08:00
|
|
|
err = ovl_check_layer(sb, ofs, ofs->workbasedir, "workdir",
|
|
|
|
false);
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-11-15 20:12:40 +08:00
|
|
|
for (i = 1; i < ofs->numlayer; i++) {
|
2019-07-12 20:24:34 +08:00
|
|
|
err = ovl_check_layer(sb, ofs,
|
2019-11-15 20:12:40 +08:00
|
|
|
ofs->layers[i].mnt->mnt_root,
|
2021-04-12 18:00:37 +08:00
|
|
|
"lowerdir", true);
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-19 23:49:17 +08:00
|
|
|
static struct dentry *ovl_get_root(struct super_block *sb,
|
|
|
|
struct dentry *upperdentry,
|
|
|
|
struct ovl_entry *oe)
|
|
|
|
{
|
|
|
|
struct dentry *root;
|
2019-11-19 21:31:46 +08:00
|
|
|
struct ovl_path *lowerpath = &oe->lowerstack[0];
|
|
|
|
unsigned long ino = d_inode(lowerpath->dentry)->i_ino;
|
|
|
|
int fsid = lowerpath->layer->fsid;
|
|
|
|
struct ovl_inode_params oip = {
|
|
|
|
.upperdentry = upperdentry,
|
|
|
|
.lowerpath = lowerpath,
|
|
|
|
};
|
2019-11-19 23:49:17 +08:00
|
|
|
|
|
|
|
root = d_make_root(ovl_new_inode(sb, S_IFDIR, 0));
|
|
|
|
if (!root)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
root->d_fsdata = oe;
|
|
|
|
|
|
|
|
if (upperdentry) {
|
2019-11-19 21:31:46 +08:00
|
|
|
/* Root inode uses upper st_ino/i_ino */
|
|
|
|
ino = d_inode(upperdentry)->i_ino;
|
|
|
|
fsid = 0;
|
2019-11-19 23:49:17 +08:00
|
|
|
ovl_dentry_set_upper_alias(root);
|
2020-09-02 16:58:49 +08:00
|
|
|
if (ovl_is_impuredir(sb, upperdentry))
|
2019-11-19 23:49:17 +08:00
|
|
|
ovl_set_flag(OVL_IMPURE, d_inode(root));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Root is always merge -> can have whiteouts */
|
|
|
|
ovl_set_flag(OVL_WHITEOUTS, d_inode(root));
|
|
|
|
ovl_dentry_set_flag(OVL_E_CONNECTED, root);
|
|
|
|
ovl_set_upperdata(d_inode(root));
|
2019-11-19 21:31:46 +08:00
|
|
|
ovl_inode_init(d_inode(root), &oip, ino, fsid);
|
2020-03-17 22:04:22 +08:00
|
|
|
ovl_dentry_update_reval(root, upperdentry, DCACHE_OP_WEAK_REVALIDATE);
|
2019-11-19 23:49:17 +08:00
|
|
|
|
|
|
|
return root;
|
|
|
|
}
|
|
|
|
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
static int ovl_fill_super(struct super_block *sb, void *data, int silent)
|
|
|
|
{
|
2017-03-30 05:02:19 +08:00
|
|
|
struct path upperpath = { };
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
struct dentry *root_dentry;
|
2017-11-10 16:39:15 +08:00
|
|
|
struct ovl_entry *oe;
|
2017-11-10 16:39:16 +08:00
|
|
|
struct ovl_fs *ofs;
|
2020-06-04 16:48:19 +08:00
|
|
|
struct ovl_layer *layers;
|
2017-01-11 02:30:21 +08:00
|
|
|
struct cred *cred;
|
2020-06-04 16:48:19 +08:00
|
|
|
char *splitlower = NULL;
|
|
|
|
unsigned int numlower;
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
int err;
|
|
|
|
|
2021-01-28 17:22:48 +08:00
|
|
|
err = -EIO;
|
|
|
|
if (WARN_ON(sb->s_user_ns != current_user_ns()))
|
|
|
|
goto out;
|
|
|
|
|
2020-03-17 22:04:22 +08:00
|
|
|
sb->s_d_op = &ovl_dentry_operations;
|
|
|
|
|
2014-10-24 06:14:38 +08:00
|
|
|
err = -ENOMEM;
|
2017-11-10 16:39:16 +08:00
|
|
|
ofs = kzalloc(sizeof(struct ovl_fs), GFP_KERNEL);
|
|
|
|
if (!ofs)
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
goto out;
|
|
|
|
|
2021-03-01 14:19:30 +08:00
|
|
|
err = -ENOMEM;
|
2017-11-10 16:39:16 +08:00
|
|
|
ofs->creator_cred = cred = prepare_creds();
|
2017-11-10 16:39:15 +08:00
|
|
|
if (!cred)
|
|
|
|
goto out_err;
|
|
|
|
|
2020-04-24 10:55:17 +08:00
|
|
|
/* Is there a reason anyone would want not to share whiteouts? */
|
|
|
|
ofs->share_whiteout = true;
|
|
|
|
|
2017-11-10 16:39:16 +08:00
|
|
|
ofs->config.index = ovl_index_def;
|
ovl: introduce new "uuid=off" option for inodes index feature
This replaces uuid with null in overlayfs file handles and thus relaxes
uuid checks for overlay index feature. It is only possible in case there is
only one filesystem for all the work/upper/lower directories and bare file
handles from this backing filesystem are unique. In other case when we have
multiple filesystems lets just fallback to "uuid=on" which is and
equivalent of how it worked before with all uuid checks.
This is needed when overlayfs is/was mounted in a container with index
enabled (e.g.: to be able to resolve inotify watch file handles on it to
paths in CRIU), and this container is copied and started alongside with the
original one. This way the "copy" container can't have the same uuid on the
superblock and mounting the overlayfs from it later would fail.
That is an example of the problem on top of loop+ext4:
dd if=/dev/zero of=loopbackfile.img bs=100M count=10
losetup -fP loopbackfile.img
losetup -a
#/dev/loop0: [64768]:35 (/loop-test/loopbackfile.img)
mkfs.ext4 loopbackfile.img
mkdir loop-mp
mount -o loop /dev/loop0 loop-mp
mkdir loop-mp/{lower,upper,work,merged}
mount -t overlay overlay -oindex=on,lowerdir=loop-mp/lower,\
upperdir=loop-mp/upper,workdir=loop-mp/work loop-mp/merged
umount loop-mp/merged
umount loop-mp
e2fsck -f /dev/loop0
tune2fs -U random /dev/loop0
mount -o loop /dev/loop0 loop-mp
mount -t overlay overlay -oindex=on,lowerdir=loop-mp/lower,\
upperdir=loop-mp/upper,workdir=loop-mp/work loop-mp/merged
#mount: /loop-test/loop-mp/merged:
#mount(2) system call failed: Stale file handle.
If you just change the uuid of the backing filesystem, overlay is not
mounting any more. In Virtuozzo we copy container disks (ploops) when
create the copy of container and we require fs uuid to be unique for a new
container.
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2020-10-13 22:59:54 +08:00
|
|
|
ofs->config.uuid = true;
|
2018-01-19 17:26:53 +08:00
|
|
|
ofs->config.nfs_export = ovl_nfs_export_def;
|
2018-03-29 14:08:18 +08:00
|
|
|
ofs->config.xino = ovl_xino_def();
|
2018-05-11 23:49:27 +08:00
|
|
|
ofs->config.metacopy = ovl_metacopy_def;
|
2017-11-10 16:39:16 +08:00
|
|
|
err = ovl_parse_opt((char *) data, &ofs->config);
|
2014-10-24 06:14:38 +08:00
|
|
|
if (err)
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out_err;
|
2014-10-24 06:14:38 +08:00
|
|
|
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
err = -EINVAL;
|
2017-11-10 16:39:16 +08:00
|
|
|
if (!ofs->config.lowerdir) {
|
2015-06-30 01:18:56 +08:00
|
|
|
if (!silent)
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("missing 'lowerdir'\n");
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out_err;
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
}
|
|
|
|
|
2020-06-04 16:48:19 +08:00
|
|
|
err = -ENOMEM;
|
|
|
|
splitlower = kstrdup(ofs->config.lowerdir, GFP_KERNEL);
|
|
|
|
if (!splitlower)
|
|
|
|
goto out_err;
|
|
|
|
|
2021-03-01 14:19:30 +08:00
|
|
|
err = -EINVAL;
|
2020-06-04 16:48:19 +08:00
|
|
|
numlower = ovl_split_lowerdirs(splitlower);
|
|
|
|
if (numlower > OVL_MAX_STACK) {
|
|
|
|
pr_err("too many lower directories, limit is %d\n",
|
|
|
|
OVL_MAX_STACK);
|
|
|
|
goto out_err;
|
|
|
|
}
|
|
|
|
|
2021-03-01 14:19:30 +08:00
|
|
|
err = -ENOMEM;
|
2020-06-04 16:48:19 +08:00
|
|
|
layers = kcalloc(numlower + 1, sizeof(struct ovl_layer), GFP_KERNEL);
|
|
|
|
if (!layers)
|
|
|
|
goto out_err;
|
|
|
|
|
|
|
|
ofs->layers = layers;
|
|
|
|
/* Layer 0 is reserved for upper even if there's no upper */
|
|
|
|
ofs->numlayer = 1;
|
|
|
|
|
2014-12-13 07:59:51 +08:00
|
|
|
sb->s_stack_depth = 0;
|
2015-12-11 23:30:49 +08:00
|
|
|
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
2020-02-21 22:34:43 +08:00
|
|
|
atomic_long_set(&ofs->last_ino, 1);
|
2022-07-29 09:57:26 +08:00
|
|
|
/* Assume underlying fs uses 32bit inodes unless proven otherwise */
|
2020-02-21 22:34:42 +08:00
|
|
|
if (ofs->config.xino != OVL_XINO_OFF) {
|
2019-11-17 00:14:41 +08:00
|
|
|
ofs->xino_mode = BITS_PER_LONG - 32;
|
2020-02-21 22:34:42 +08:00
|
|
|
if (!ofs->xino_mode) {
|
|
|
|
pr_warn("xino not supported on 32bit kernel, falling back to xino=off.\n");
|
|
|
|
ofs->config.xino = OVL_XINO_OFF;
|
|
|
|
}
|
|
|
|
}
|
2018-03-29 14:08:18 +08:00
|
|
|
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
/* alloc/destroy_inode needed for setting up traps in inode cache */
|
|
|
|
sb->s_op = &ovl_super_operations;
|
|
|
|
|
2017-11-10 16:39:16 +08:00
|
|
|
if (ofs->config.upperdir) {
|
ovl: implement volatile-specific fsync error behaviour
Overlayfs's volatile option allows the user to bypass all forced sync calls
to the upperdir filesystem. This comes at the cost of safety. We can never
ensure that the user's data is intact, but we can make a best effort to
expose whether or not the data is likely to be in a bad state.
The best way to handle this in the time being is that if an overlayfs's
upperdir experiences an error after a volatile mount occurs, that error
will be returned on fsync, fdatasync, sync, and syncfs. This is
contradictory to the traditional behaviour of VFS which fails the call
once, and only raises an error if a subsequent fsync error has occurred,
and been raised by the filesystem.
One awkward aspect of the patch is that we have to manually set the
superblock's errseq_t after the sync_fs callback as opposed to just
returning an error from syncfs. This is because the call chain looks
something like this:
sys_syncfs ->
sync_filesystem ->
__sync_filesystem ->
/* The return value is ignored here
sb->s_op->sync_fs(sb)
_sync_blockdev
/* Where the VFS fetches the error to raise to userspace */
errseq_check_and_advance
Because of this we call errseq_set every time the sync_fs callback occurs.
Due to the nature of this seen / unseen dichotomy, if the upperdir is an
inconsistent state at the initial mount time, overlayfs will refuse to
mount, as overlayfs cannot get a snapshot of the upperdir's errseq that
will increment on error until the user calls syncfs.
Signed-off-by: Sargun Dhillon <sargun@sargun.me>
Suggested-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Fixes: c86243b090bc ("ovl: provide a mount option "volatile"")
Cc: stable@vger.kernel.org
Reviewed-by: Vivek Goyal <vgoyal@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2021-01-08 08:10:43 +08:00
|
|
|
struct super_block *upper_sb;
|
|
|
|
|
2021-03-01 14:19:30 +08:00
|
|
|
err = -EINVAL;
|
2017-11-10 16:39:16 +08:00
|
|
|
if (!ofs->config.workdir) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_err("missing 'workdir'\n");
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out_err;
|
2014-12-13 07:59:51 +08:00
|
|
|
}
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
|
2020-06-04 16:48:19 +08:00
|
|
|
err = ovl_get_upper(sb, ofs, &layers[0], &upperpath);
|
2014-12-13 07:59:51 +08:00
|
|
|
if (err)
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out_err;
|
2017-06-21 20:28:33 +08:00
|
|
|
|
ovl: implement volatile-specific fsync error behaviour
Overlayfs's volatile option allows the user to bypass all forced sync calls
to the upperdir filesystem. This comes at the cost of safety. We can never
ensure that the user's data is intact, but we can make a best effort to
expose whether or not the data is likely to be in a bad state.
The best way to handle this in the time being is that if an overlayfs's
upperdir experiences an error after a volatile mount occurs, that error
will be returned on fsync, fdatasync, sync, and syncfs. This is
contradictory to the traditional behaviour of VFS which fails the call
once, and only raises an error if a subsequent fsync error has occurred,
and been raised by the filesystem.
One awkward aspect of the patch is that we have to manually set the
superblock's errseq_t after the sync_fs callback as opposed to just
returning an error from syncfs. This is because the call chain looks
something like this:
sys_syncfs ->
sync_filesystem ->
__sync_filesystem ->
/* The return value is ignored here
sb->s_op->sync_fs(sb)
_sync_blockdev
/* Where the VFS fetches the error to raise to userspace */
errseq_check_and_advance
Because of this we call errseq_set every time the sync_fs callback occurs.
Due to the nature of this seen / unseen dichotomy, if the upperdir is an
inconsistent state at the initial mount time, overlayfs will refuse to
mount, as overlayfs cannot get a snapshot of the upperdir's errseq that
will increment on error until the user calls syncfs.
Signed-off-by: Sargun Dhillon <sargun@sargun.me>
Suggested-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Fixes: c86243b090bc ("ovl: provide a mount option "volatile"")
Cc: stable@vger.kernel.org
Reviewed-by: Vivek Goyal <vgoyal@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2021-01-08 08:10:43 +08:00
|
|
|
upper_sb = ovl_upper_mnt(ofs)->mnt_sb;
|
|
|
|
if (!ovl_should_sync(ofs)) {
|
|
|
|
ofs->errseq = errseq_sample(&upper_sb->s_wb_err);
|
|
|
|
if (errseq_check(&upper_sb->s_wb_err, ofs->errseq)) {
|
|
|
|
err = -EIO;
|
|
|
|
pr_err("Cannot mount volatile when upperdir has an unseen error. Sync upperdir fs to clear state.\n");
|
|
|
|
goto out_err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
err = ovl_get_workdir(sb, ofs, &upperpath);
|
2017-11-09 17:23:28 +08:00
|
|
|
if (err)
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out_err;
|
2017-11-10 16:39:15 +08:00
|
|
|
|
2017-11-10 16:39:16 +08:00
|
|
|
if (!ofs->workdir)
|
2017-11-28 05:05:09 +08:00
|
|
|
sb->s_flags |= SB_RDONLY;
|
2017-11-10 16:39:15 +08:00
|
|
|
|
ovl: implement volatile-specific fsync error behaviour
Overlayfs's volatile option allows the user to bypass all forced sync calls
to the upperdir filesystem. This comes at the cost of safety. We can never
ensure that the user's data is intact, but we can make a best effort to
expose whether or not the data is likely to be in a bad state.
The best way to handle this in the time being is that if an overlayfs's
upperdir experiences an error after a volatile mount occurs, that error
will be returned on fsync, fdatasync, sync, and syncfs. This is
contradictory to the traditional behaviour of VFS which fails the call
once, and only raises an error if a subsequent fsync error has occurred,
and been raised by the filesystem.
One awkward aspect of the patch is that we have to manually set the
superblock's errseq_t after the sync_fs callback as opposed to just
returning an error from syncfs. This is because the call chain looks
something like this:
sys_syncfs ->
sync_filesystem ->
__sync_filesystem ->
/* The return value is ignored here
sb->s_op->sync_fs(sb)
_sync_blockdev
/* Where the VFS fetches the error to raise to userspace */
errseq_check_and_advance
Because of this we call errseq_set every time the sync_fs callback occurs.
Due to the nature of this seen / unseen dichotomy, if the upperdir is an
inconsistent state at the initial mount time, overlayfs will refuse to
mount, as overlayfs cannot get a snapshot of the upperdir's errseq that
will increment on error until the user calls syncfs.
Signed-off-by: Sargun Dhillon <sargun@sargun.me>
Suggested-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Fixes: c86243b090bc ("ovl: provide a mount option "volatile"")
Cc: stable@vger.kernel.org
Reviewed-by: Vivek Goyal <vgoyal@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2021-01-08 08:10:43 +08:00
|
|
|
sb->s_stack_depth = upper_sb->s_stack_depth;
|
|
|
|
sb->s_time_gran = upper_sb->s_time_gran;
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
}
|
2020-06-04 16:48:19 +08:00
|
|
|
oe = ovl_get_lowerstack(sb, splitlower, numlower, ofs, layers);
|
2017-11-10 16:39:15 +08:00
|
|
|
err = PTR_ERR(oe);
|
|
|
|
if (IS_ERR(oe))
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out_err;
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
|
2015-01-15 13:20:57 +08:00
|
|
|
/* If the upper fs is nonexistent, we mark overlayfs r/o too */
|
2020-06-04 16:48:19 +08:00
|
|
|
if (!ovl_upper_mnt(ofs))
|
2017-11-28 05:05:09 +08:00
|
|
|
sb->s_flags |= SB_RDONLY;
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
|
ovl: introduce new "uuid=off" option for inodes index feature
This replaces uuid with null in overlayfs file handles and thus relaxes
uuid checks for overlay index feature. It is only possible in case there is
only one filesystem for all the work/upper/lower directories and bare file
handles from this backing filesystem are unique. In other case when we have
multiple filesystems lets just fallback to "uuid=on" which is and
equivalent of how it worked before with all uuid checks.
This is needed when overlayfs is/was mounted in a container with index
enabled (e.g.: to be able to resolve inotify watch file handles on it to
paths in CRIU), and this container is copied and started alongside with the
original one. This way the "copy" container can't have the same uuid on the
superblock and mounting the overlayfs from it later would fail.
That is an example of the problem on top of loop+ext4:
dd if=/dev/zero of=loopbackfile.img bs=100M count=10
losetup -fP loopbackfile.img
losetup -a
#/dev/loop0: [64768]:35 (/loop-test/loopbackfile.img)
mkfs.ext4 loopbackfile.img
mkdir loop-mp
mount -o loop /dev/loop0 loop-mp
mkdir loop-mp/{lower,upper,work,merged}
mount -t overlay overlay -oindex=on,lowerdir=loop-mp/lower,\
upperdir=loop-mp/upper,workdir=loop-mp/work loop-mp/merged
umount loop-mp/merged
umount loop-mp
e2fsck -f /dev/loop0
tune2fs -U random /dev/loop0
mount -o loop /dev/loop0 loop-mp
mount -t overlay overlay -oindex=on,lowerdir=loop-mp/lower,\
upperdir=loop-mp/upper,workdir=loop-mp/work loop-mp/merged
#mount: /loop-test/loop-mp/merged:
#mount(2) system call failed: Stale file handle.
If you just change the uuid of the backing filesystem, overlay is not
mounting any more. In Virtuozzo we copy container disks (ploops) when
create the copy of container and we require fs uuid to be unique for a new
container.
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2020-10-13 22:59:54 +08:00
|
|
|
if (!ofs->config.uuid && ofs->numfs > 1) {
|
|
|
|
pr_warn("The uuid=off requires a single fs for lower and upper, falling back to uuid=on.\n");
|
|
|
|
ofs->config.uuid = true;
|
|
|
|
}
|
|
|
|
|
2020-07-13 22:19:43 +08:00
|
|
|
if (!ovl_force_readonly(ofs) && ofs->config.index) {
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
err = ovl_get_indexdir(sb, ofs, oe, &upperpath);
|
2017-06-21 20:28:38 +08:00
|
|
|
if (err)
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out_free_oe;
|
2017-11-10 16:39:15 +08:00
|
|
|
|
2017-09-19 17:14:18 +08:00
|
|
|
/* Force r/o mount with no index dir */
|
ovl: fix oops in ovl_indexdir_cleanup() with nfs_export=on
Mounting with nfs_export=on, xfstests overlay/031 triggers a kernel panic
since v5.8-rc1 overlayfs updates.
overlayfs: orphan index entry (index/00fb1..., ftype=4000, nlink=2)
BUG: kernel NULL pointer dereference, address: 0000000000000030
RIP: 0010:ovl_cleanup_and_whiteout+0x28/0x220 [overlay]
Bisect point at commit c21c839b8448 ("ovl: whiteout inode sharing")
Minimal reproducer:
--------------------------------------------------
rm -rf l u w m
mkdir -p l u w m
mkdir -p l/testdir
touch l/testdir/testfile
mount -t overlay -o lowerdir=l,upperdir=u,workdir=w,nfs_export=on overlay m
echo 1 > m/testdir/testfile
umount m
rm -rf u/testdir
mount -t overlay -o lowerdir=l,upperdir=u,workdir=w,nfs_export=on overlay m
umount m
--------------------------------------------------
When mount with nfs_export=on, and fail to verify an orphan index, we're
cleaning this index from indexdir by calling ovl_cleanup_and_whiteout().
This dereferences ofs->workdir, that was earlier set to NULL.
The design was that ovl->workdir will point at ovl->indexdir, but we are
assigning ofs->indexdir to ofs->workdir only after ovl_indexdir_cleanup().
There is no reason not to do it sooner, because once we get success from
ofs->indexdir = ovl_workdir_create(... there is no turning back.
Reported-and-tested-by: Murphy Zhou <jencce.kernel@gmail.com>
Fixes: c21c839b8448 ("ovl: whiteout inode sharing")
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2020-06-21 14:37:59 +08:00
|
|
|
if (!ofs->indexdir)
|
2017-11-28 05:05:09 +08:00
|
|
|
sb->s_flags |= SB_RDONLY;
|
2017-06-21 20:28:36 +08:00
|
|
|
}
|
|
|
|
|
ovl: detect overlapping layers
Overlapping overlay layers are not supported and can cause unexpected
behavior, but overlayfs does not currently check or warn about these
configurations.
User is not supposed to specify the same directory for upper and
lower dirs or for different lower layers and user is not supposed to
specify directories that are descendants of each other for overlay
layers, but that is exactly what this zysbot repro did:
https://syzkaller.appspot.com/x/repro.syz?x=12c7a94f400000
Moving layer root directories into other layers while overlayfs
is mounted could also result in unexpected behavior.
This commit places "traps" in the overlay inode hash table.
Those traps are dummy overlay inodes that are hashed by the layers
root inodes.
On mount, the hash table trap entries are used to verify that overlay
layers are not overlapping. While at it, we also verify that overlay
layers are not overlapping with directories "in-use" by other overlay
instances as upperdir/workdir.
On lookup, the trap entries are used to verify that overlay layers
root inodes have not been moved into other layers after mount.
Some examples:
$ ./run --ov --samefs -s
...
( mkdir -p base/upper/0/u base/upper/0/w base/lower lower upper mnt
mount -o bind base/lower lower
mount -o bind base/upper upper
mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w)
$ umount mnt
$ mount -t overlay none mnt ...
-o lowerdir=base,upperdir=upper/0/u,workdir=upper/0/w
[ 94.434900] overlayfs: overlapping upperdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=upper/0/u,upperdir=upper/0/u,workdir=upper/0/w
[ 151.350132] overlayfs: conflicting lowerdir path
mount: none is already mounted or mnt busy
$ mount -t overlay none mnt ...
-o lowerdir=lower:lower/a,upperdir=upper/0/u,workdir=upper/0/w
[ 201.205045] overlayfs: overlapping lowerdir path
mount: mount overlay on mnt failed: Too many levels of symbolic links
$ mount -t overlay none mnt ...
-o lowerdir=lower,upperdir=upper/0/u,workdir=upper/0/w
$ mv base/upper/0/ base/lower/
$ find mnt/0
mnt/0
mnt/0/w
find: 'mnt/0/w/work': Too many levels of symbolic links
find: 'mnt/0/u': Too many levels of symbolic links
Reported-by: syzbot+9c69c282adc4edd2b540@syzkaller.appspotmail.com
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
2019-04-18 22:42:08 +08:00
|
|
|
err = ovl_check_overlapping_layers(sb, ofs);
|
|
|
|
if (err)
|
|
|
|
goto out_free_oe;
|
|
|
|
|
2017-09-19 17:14:18 +08:00
|
|
|
/* Show index=off in /proc/mounts for forced r/o mount */
|
2018-01-19 17:26:53 +08:00
|
|
|
if (!ofs->indexdir) {
|
2017-11-10 16:39:16 +08:00
|
|
|
ofs->config.index = false;
|
2020-06-04 16:48:19 +08:00
|
|
|
if (ovl_upper_mnt(ofs) && ofs->config.nfs_export) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_warn("NFS export requires an index dir, falling back to nfs_export=off.\n");
|
2018-01-19 17:26:53 +08:00
|
|
|
ofs->config.nfs_export = false;
|
|
|
|
}
|
|
|
|
}
|
2017-06-21 20:28:36 +08:00
|
|
|
|
2018-05-11 23:49:27 +08:00
|
|
|
if (ofs->config.metacopy && ofs->config.nfs_export) {
|
2019-12-16 19:12:32 +08:00
|
|
|
pr_warn("NFS export is not supported with metadata only copy up, falling back to nfs_export=off.\n");
|
2018-05-11 23:49:27 +08:00
|
|
|
ofs->config.nfs_export = false;
|
|
|
|
}
|
|
|
|
|
2017-10-02 16:31:42 +08:00
|
|
|
if (ofs->config.nfs_export)
|
|
|
|
sb->s_export_op = &ovl_export_operations;
|
|
|
|
|
2017-01-11 02:30:21 +08:00
|
|
|
/* Never override disk quota limits or use reserved space */
|
|
|
|
cap_lower(cred->cap_effective, CAP_SYS_RESOURCE);
|
|
|
|
|
2016-10-14 09:03:36 +08:00
|
|
|
sb->s_magic = OVERLAYFS_SUPER_MAGIC;
|
2020-12-14 22:26:14 +08:00
|
|
|
sb->s_xattr = ofs->config.userxattr ? ovl_user_xattr_handlers :
|
|
|
|
ovl_trusted_xattr_handlers;
|
2017-11-10 16:39:16 +08:00
|
|
|
sb->s_fs_info = ofs;
|
2022-07-13 17:47:44 +08:00
|
|
|
sb->s_flags |= SB_POSIXACL;
|
2020-04-09 16:29:47 +08:00
|
|
|
sb->s_iflags |= SB_I_SKIP_SYNC;
|
2016-10-14 09:03:36 +08:00
|
|
|
|
2017-11-10 16:39:15 +08:00
|
|
|
err = -ENOMEM;
|
2019-11-19 23:49:17 +08:00
|
|
|
root_dentry = ovl_get_root(sb, upperpath.dentry, oe);
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
if (!root_dentry)
|
2017-11-10 16:39:15 +08:00
|
|
|
goto out_free_oe;
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
|
|
|
|
mntput(upperpath.mnt);
|
2020-06-04 16:48:19 +08:00
|
|
|
kfree(splitlower);
|
2015-12-09 23:11:59 +08:00
|
|
|
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
sb->s_root = root_dentry;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2017-11-10 16:39:15 +08:00
|
|
|
out_free_oe:
|
|
|
|
ovl_entry_stack_free(oe);
|
2017-07-24 14:57:54 +08:00
|
|
|
kfree(oe);
|
2017-11-10 16:39:15 +08:00
|
|
|
out_err:
|
2020-06-04 16:48:19 +08:00
|
|
|
kfree(splitlower);
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
path_put(&upperpath);
|
2017-11-10 16:39:16 +08:00
|
|
|
ovl_free_fs(ofs);
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct dentry *ovl_mount(struct file_system_type *fs_type, int flags,
|
|
|
|
const char *dev_name, void *raw_data)
|
|
|
|
{
|
|
|
|
return mount_nodev(fs_type, flags, raw_data, ovl_fill_super);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct file_system_type ovl_fs_type = {
|
|
|
|
.owner = THIS_MODULE,
|
2014-11-20 23:39:59 +08:00
|
|
|
.name = "overlay",
|
2020-12-14 22:26:14 +08:00
|
|
|
.fs_flags = FS_USERNS_MOUNT,
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
.mount = ovl_mount,
|
|
|
|
.kill_sb = kill_anon_super,
|
|
|
|
};
|
2014-11-20 23:39:59 +08:00
|
|
|
MODULE_ALIAS_FS("overlay");
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
|
2017-06-12 14:54:40 +08:00
|
|
|
static void ovl_inode_init_once(void *foo)
|
|
|
|
{
|
|
|
|
struct ovl_inode *oi = foo;
|
|
|
|
|
|
|
|
inode_init_once(&oi->vfs_inode);
|
|
|
|
}
|
|
|
|
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
static int __init ovl_init(void)
|
|
|
|
{
|
2017-06-12 14:54:40 +08:00
|
|
|
int err;
|
|
|
|
|
|
|
|
ovl_inode_cachep = kmem_cache_create("ovl_inode",
|
|
|
|
sizeof(struct ovl_inode), 0,
|
|
|
|
(SLAB_RECLAIM_ACCOUNT|
|
|
|
|
SLAB_MEM_SPREAD|SLAB_ACCOUNT),
|
|
|
|
ovl_inode_init_once);
|
|
|
|
if (ovl_inode_cachep == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2019-11-20 17:45:26 +08:00
|
|
|
err = ovl_aio_request_cache_init();
|
|
|
|
if (!err) {
|
|
|
|
err = register_filesystem(&ovl_fs_type);
|
|
|
|
if (!err)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ovl_aio_request_cache_destroy();
|
|
|
|
}
|
|
|
|
kmem_cache_destroy(ovl_inode_cachep);
|
2017-06-12 14:54:40 +08:00
|
|
|
|
|
|
|
return err;
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit ovl_exit(void)
|
|
|
|
{
|
|
|
|
unregister_filesystem(&ovl_fs_type);
|
2017-06-12 14:54:40 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure all delayed rcu free inodes are flushed before we
|
|
|
|
* destroy cache.
|
|
|
|
*/
|
|
|
|
rcu_barrier();
|
|
|
|
kmem_cache_destroy(ovl_inode_cachep);
|
2019-11-20 17:45:26 +08:00
|
|
|
ovl_aio_request_cache_destroy();
|
overlay filesystem
Overlayfs allows one, usually read-write, directory tree to be
overlaid onto another, read-only directory tree. All modifications
go to the upper, writable layer.
This type of mechanism is most often used for live CDs but there's a
wide variety of other uses.
The implementation differs from other "union filesystem"
implementations in that after a file is opened all operations go
directly to the underlying, lower or upper, filesystems. This
simplifies the implementation and allows native performance in these
cases.
The dentry tree is duplicated from the underlying filesystems, this
enables fast cached lookups without adding special support into the
VFS. This uses slightly more memory than union mounts, but dentries
are relatively small.
Currently inodes are duplicated as well, but it is a possible
optimization to share inodes for non-directories.
Opening non directories results in the open forwarded to the
underlying filesystem. This makes the behavior very similar to union
mounts (with the same limitations vs. fchmod/fchown on O_RDONLY file
descriptors).
Usage:
mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper/upper,workdir=/upper/work /overlay
The following cotributions have been folded into this patch:
Neil Brown <neilb@suse.de>:
- minimal remount support
- use correct seek function for directories
- initialise is_real before use
- rename ovl_fill_cache to ovl_dir_read
Felix Fietkau <nbd@openwrt.org>:
- fix a deadlock in ovl_dir_read_merged
- fix a deadlock in ovl_remove_whiteouts
Erez Zadok <ezk@fsl.cs.sunysb.edu>
- fix cleanup after WARN_ON
Sedat Dilek <sedat.dilek@googlemail.com>
- fix up permission to confirm to new API
Robin Dong <hao.bigrat@gmail.com>
- fix possible leak in ovl_new_inode
- create new inode in ovl_link
Andy Whitcroft <apw@canonical.com>
- switch to __inode_permission()
- copy up i_uid/i_gid from the underlying inode
AV:
- ovl_copy_up_locked() - dput(ERR_PTR(...)) on two failure exits
- ovl_clear_empty() - one failure exit forgetting to do unlock_rename(),
lack of check for udir being the parent of upper, dropping and regaining
the lock on udir (which would require _another_ check for parent being
right).
- bogus d_drop() in copyup and rename [fix from your mail]
- copyup/remove and copyup/rename races [fix from your mail]
- ovl_dir_fsync() leaving ERR_PTR() in ->realfile
- ovl_entry_free() is pointless - it's just a kfree_rcu()
- fold ovl_do_lookup() into ovl_lookup()
- manually assigning ->d_op is wrong. Just use ->s_d_op.
[patches picked from Miklos]:
* copyup/remove and copyup/rename races
* bogus d_drop() in copyup and rename
Also thanks to the following people for testing and reporting bugs:
Jordi Pujol <jordipujolp@gmail.com>
Andy Whitcroft <apw@canonical.com>
Michal Suchanek <hramrach@centrum.cz>
Felix Fietkau <nbd@openwrt.org>
Erez Zadok <ezk@fsl.cs.sunysb.edu>
Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
2014-10-24 06:14:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
module_init(ovl_init);
|
|
|
|
module_exit(ovl_exit);
|