Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs updates from Miklos Szeredi: - Report constant st_ino values across copy-up even if underlying layers are on different filesystems, but using different st_dev values for each layer. Ideally we'd report the same st_dev across the overlay, and it's possible to do for filesystems that use only 32bits for st_ino by unifying the inum space. It would be nice if it wasn't a choice of 32 or 64, rather filesystems could report their current maximum (that could change on resize, so it wouldn't be set in stone). - miscellaneus fixes and a cleanup of ovl_fill_super(), that was long overdue. - created a path_put_init() helper that clears out the pointers after putting the ref. I think this could be useful elsewhere, so added it to <linux/path.h> * 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: (30 commits) ovl: remove unneeded arg from ovl_verify_origin() ovl: Put upperdentry if ovl_check_origin() fails ovl: rename ufs to ofs ovl: clean up getting lower layers ovl: clean up workdir creation ovl: clean up getting upper layer ovl: move ovl_get_workdir() and ovl_get_lower_layers() ovl: reduce the number of arguments for ovl_workdir_create() ovl: change order of setup in ovl_fill_super() ovl: factor out ovl_free_fs() helper ovl: grab reference to workbasedir early ovl: split out ovl_get_indexdir() from ovl_fill_super() ovl: split out ovl_get_lower_layers() from ovl_fill_super() ovl: split out ovl_get_workdir() from ovl_fill_super() ovl: split out ovl_get_upper() from ovl_fill_super() ovl: split out ovl_get_lowerstack() from ovl_fill_super() ovl: split out ovl_get_workpath() from ovl_fill_super() ovl: split out ovl_get_upperpath() from ovl_fill_super() ovl: use path_put_init() in error paths for ovl_fill_super() vfs: add path_put_init() ...
This commit is contained in:
@@ -26,6 +26,7 @@ struct ovl_cache_entry {
|
||||
struct list_head l_node;
|
||||
struct rb_node node;
|
||||
struct ovl_cache_entry *next_maybe_whiteout;
|
||||
bool is_upper;
|
||||
bool is_whiteout;
|
||||
char name[];
|
||||
};
|
||||
@@ -158,6 +159,7 @@ static struct ovl_cache_entry *ovl_cache_entry_new(struct ovl_readdir_data *rdd,
|
||||
/* Defer setting d_ino for upper entry to ovl_iterate() */
|
||||
if (ovl_calc_d_ino(rdd, p))
|
||||
p->ino = 0;
|
||||
p->is_upper = rdd->is_upper;
|
||||
p->is_whiteout = false;
|
||||
|
||||
if (d_type == DT_CHR) {
|
||||
@@ -316,21 +318,37 @@ static inline int ovl_dir_read(struct path *realpath,
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Can we iterate real dir directly?
|
||||
*
|
||||
* Non-merge dir may contain whiteouts from a time it was a merge upper, before
|
||||
* lower dir was removed under it and possibly before it was rotated from upper
|
||||
* to lower layer.
|
||||
*/
|
||||
static bool ovl_dir_is_real(struct dentry *dir)
|
||||
{
|
||||
return !ovl_test_flag(OVL_WHITEOUTS, d_inode(dir));
|
||||
}
|
||||
|
||||
static void ovl_dir_reset(struct file *file)
|
||||
{
|
||||
struct ovl_dir_file *od = file->private_data;
|
||||
struct ovl_dir_cache *cache = od->cache;
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
enum ovl_path_type type = ovl_path_type(dentry);
|
||||
bool is_real;
|
||||
|
||||
if (cache && ovl_dentry_version_get(dentry) != cache->version) {
|
||||
ovl_cache_put(od, dentry);
|
||||
od->cache = NULL;
|
||||
od->cursor = NULL;
|
||||
}
|
||||
WARN_ON(!od->is_real && !OVL_TYPE_MERGE(type));
|
||||
if (od->is_real && OVL_TYPE_MERGE(type))
|
||||
is_real = ovl_dir_is_real(dentry);
|
||||
if (od->is_real != is_real) {
|
||||
/* is_real can only become false when dir is copied up */
|
||||
if (WARN_ON(is_real))
|
||||
return;
|
||||
od->is_real = false;
|
||||
}
|
||||
}
|
||||
|
||||
static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list,
|
||||
@@ -816,7 +834,7 @@ static int ovl_dir_open(struct inode *inode, struct file *file)
|
||||
return PTR_ERR(realfile);
|
||||
}
|
||||
od->realfile = realfile;
|
||||
od->is_real = !OVL_TYPE_MERGE(type);
|
||||
od->is_real = ovl_dir_is_real(file->f_path.dentry);
|
||||
od->is_upper = OVL_TYPE_UPPER(type);
|
||||
file->private_data = od;
|
||||
|
||||
@@ -835,7 +853,7 @@ const struct file_operations ovl_dir_operations = {
|
||||
int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)
|
||||
{
|
||||
int err;
|
||||
struct ovl_cache_entry *p;
|
||||
struct ovl_cache_entry *p, *n;
|
||||
struct rb_root root = RB_ROOT;
|
||||
|
||||
err = ovl_dir_read_merged(dentry, list, &root);
|
||||
@@ -844,18 +862,29 @@ int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)
|
||||
|
||||
err = 0;
|
||||
|
||||
list_for_each_entry(p, list, l_node) {
|
||||
if (p->is_whiteout)
|
||||
continue;
|
||||
list_for_each_entry_safe(p, n, list, l_node) {
|
||||
/*
|
||||
* Select whiteouts in upperdir, they should
|
||||
* be cleared when deleting this directory.
|
||||
*/
|
||||
if (p->is_whiteout) {
|
||||
if (p->is_upper)
|
||||
continue;
|
||||
goto del_entry;
|
||||
}
|
||||
|
||||
if (p->name[0] == '.') {
|
||||
if (p->len == 1)
|
||||
continue;
|
||||
goto del_entry;
|
||||
if (p->len == 2 && p->name[1] == '.')
|
||||
continue;
|
||||
goto del_entry;
|
||||
}
|
||||
err = -ENOTEMPTY;
|
||||
break;
|
||||
|
||||
del_entry:
|
||||
list_del(&p->l_node);
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
return err;
|
||||
@@ -869,7 +898,7 @@ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list)
|
||||
list_for_each_entry(p, list, l_node) {
|
||||
struct dentry *dentry;
|
||||
|
||||
if (!p->is_whiteout)
|
||||
if (WARN_ON(!p->is_whiteout || !p->is_upper))
|
||||
continue;
|
||||
|
||||
dentry = lookup_one_len(p->name, upper, p->len);
|
||||
@@ -985,7 +1014,7 @@ void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
|
||||
}
|
||||
|
||||
int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
|
||||
struct path *lowerstack, unsigned int numlower)
|
||||
struct ovl_path *lower, unsigned int numlower)
|
||||
{
|
||||
int err;
|
||||
struct dentry *index = NULL;
|
||||
@@ -1020,7 +1049,7 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
|
||||
index = NULL;
|
||||
break;
|
||||
}
|
||||
err = ovl_verify_index(index, lowerstack, numlower);
|
||||
err = ovl_verify_index(index, lower, numlower);
|
||||
/* Cleanup stale and orphan index entries */
|
||||
if (err && (err == -ESTALE || err == -ENOENT))
|
||||
err = ovl_cleanup(dir, index);
|
||||
|
Reference in New Issue
Block a user