ovl: mark upper dir with type origin entries "impure"
When moving a merge dir or non-dir with copy up origin into a non-merge upper dir (a.k.a pure upper dir), we are marking the target parent dir "impure". ovl_iterate() iterates pure upper dirs directly, because there is no need to filter out whiteouts and merge dir content with lower dir. But for the case of an "impure" upper dir, ovl_iterate() will not be able to iterate the real upper dir directly, because it will need to lookup the origin inode and use it to fill d_ino. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
Родитель
3d27573ce3
Коммит
ee1d6d37b6
|
@ -149,6 +149,22 @@ static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry)
|
||||||
return ovl_set_opaque_xerr(dentry, upperdentry, -EIO);
|
return ovl_set_opaque_xerr(dentry, upperdentry, -EIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ovl_set_impure(struct dentry *dentry, struct dentry *upperdentry)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do not fail when upper doesn't support xattrs.
|
||||||
|
* Upper inodes won't have origin nor redirect xattr anyway.
|
||||||
|
*/
|
||||||
|
err = ovl_check_setxattr(dentry, upperdentry, OVL_XATTR_IMPURE,
|
||||||
|
"y", 1, 0);
|
||||||
|
if (!err)
|
||||||
|
ovl_dentry_set_impure(dentry);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Common operations required to be done after creation of file on upper */
|
/* Common operations required to be done after creation of file on upper */
|
||||||
static void ovl_instantiate(struct dentry *dentry, struct inode *inode,
|
static void ovl_instantiate(struct dentry *dentry, struct inode *inode,
|
||||||
struct dentry *newdentry, bool hardlink)
|
struct dentry *newdentry, bool hardlink)
|
||||||
|
@ -173,6 +189,11 @@ static bool ovl_type_merge(struct dentry *dentry)
|
||||||
return OVL_TYPE_MERGE(ovl_path_type(dentry));
|
return OVL_TYPE_MERGE(ovl_path_type(dentry));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ovl_type_origin(struct dentry *dentry)
|
||||||
|
{
|
||||||
|
return OVL_TYPE_ORIGIN(ovl_path_type(dentry));
|
||||||
|
}
|
||||||
|
|
||||||
static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
|
static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
|
||||||
struct cattr *attr, struct dentry *hardlink)
|
struct cattr *attr, struct dentry *hardlink)
|
||||||
{
|
{
|
||||||
|
@ -952,6 +973,30 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
|
||||||
old_upperdir = ovl_dentry_upper(old->d_parent);
|
old_upperdir = ovl_dentry_upper(old->d_parent);
|
||||||
new_upperdir = ovl_dentry_upper(new->d_parent);
|
new_upperdir = ovl_dentry_upper(new->d_parent);
|
||||||
|
|
||||||
|
if (!samedir) {
|
||||||
|
/*
|
||||||
|
* When moving a merge dir or non-dir with copy up origin into
|
||||||
|
* a non-merge upper dir (a.k.a pure upper dir), we are making
|
||||||
|
* the target parent dir "impure". ovl_iterate() iterates pure
|
||||||
|
* upper dirs directly, because there is no need to filter out
|
||||||
|
* whiteouts and merge dir content with lower dir. But for the
|
||||||
|
* case of an "impure" upper dir, ovl_iterate() cannot iterate
|
||||||
|
* the real directory directly, because it looks for the inode
|
||||||
|
* numbers to fill d_ino in the entries origin inode.
|
||||||
|
*/
|
||||||
|
if (ovl_type_origin(old) && !ovl_type_merge(new->d_parent)) {
|
||||||
|
err = ovl_set_impure(new->d_parent, new_upperdir);
|
||||||
|
if (err)
|
||||||
|
goto out_revert_creds;
|
||||||
|
}
|
||||||
|
if (!overwrite && ovl_type_origin(new) &&
|
||||||
|
!ovl_type_merge(old->d_parent)) {
|
||||||
|
err = ovl_set_impure(old->d_parent, old_upperdir);
|
||||||
|
if (err)
|
||||||
|
goto out_revert_creds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
trap = lock_rename(new_upperdir, old_upperdir);
|
trap = lock_rename(new_upperdir, old_upperdir);
|
||||||
|
|
||||||
olddentry = lookup_one_len(old->d_name.name, old_upperdir,
|
olddentry = lookup_one_len(old->d_name.name, old_upperdir,
|
||||||
|
|
|
@ -167,7 +167,7 @@ invalid:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ovl_is_opaquedir(struct dentry *dentry)
|
static bool ovl_check_dir_xattr(struct dentry *dentry, const char *name)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
char val;
|
char val;
|
||||||
|
@ -175,13 +175,23 @@ static bool ovl_is_opaquedir(struct dentry *dentry)
|
||||||
if (!d_is_dir(dentry))
|
if (!d_is_dir(dentry))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
res = vfs_getxattr(dentry, OVL_XATTR_OPAQUE, &val, 1);
|
res = vfs_getxattr(dentry, name, &val, 1);
|
||||||
if (res == 1 && val == 'y')
|
if (res == 1 && val == 'y')
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ovl_is_opaquedir(struct dentry *dentry)
|
||||||
|
{
|
||||||
|
return ovl_check_dir_xattr(dentry, OVL_XATTR_OPAQUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ovl_is_impuredir(struct dentry *dentry)
|
||||||
|
{
|
||||||
|
return ovl_check_dir_xattr(dentry, OVL_XATTR_IMPURE);
|
||||||
|
}
|
||||||
|
|
||||||
static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
|
static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
|
||||||
const char *name, unsigned int namelen,
|
const char *name, unsigned int namelen,
|
||||||
size_t prelen, const char *post,
|
size_t prelen, const char *post,
|
||||||
|
@ -351,6 +361,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
|
||||||
unsigned int ctr = 0;
|
unsigned int ctr = 0;
|
||||||
struct inode *inode = NULL;
|
struct inode *inode = NULL;
|
||||||
bool upperopaque = false;
|
bool upperopaque = false;
|
||||||
|
bool upperimpure = false;
|
||||||
char *upperredirect = NULL;
|
char *upperredirect = NULL;
|
||||||
struct dentry *this;
|
struct dentry *this;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
@ -395,6 +406,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
|
||||||
poe = roe;
|
poe = roe;
|
||||||
}
|
}
|
||||||
upperopaque = d.opaque;
|
upperopaque = d.opaque;
|
||||||
|
if (upperdentry && d.is_dir)
|
||||||
|
upperimpure = ovl_is_impuredir(upperdentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!d.stop && poe->numlower) {
|
if (!d.stop && poe->numlower) {
|
||||||
|
@ -463,6 +476,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
|
||||||
|
|
||||||
revert_creds(old_cred);
|
revert_creds(old_cred);
|
||||||
oe->opaque = upperopaque;
|
oe->opaque = upperopaque;
|
||||||
|
oe->impure = upperimpure;
|
||||||
oe->redirect = upperredirect;
|
oe->redirect = upperredirect;
|
||||||
oe->__upperdentry = upperdentry;
|
oe->__upperdentry = upperdentry;
|
||||||
memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr);
|
memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr);
|
||||||
|
|
|
@ -24,6 +24,7 @@ enum ovl_path_type {
|
||||||
#define OVL_XATTR_OPAQUE OVL_XATTR_PREFIX "opaque"
|
#define OVL_XATTR_OPAQUE OVL_XATTR_PREFIX "opaque"
|
||||||
#define OVL_XATTR_REDIRECT OVL_XATTR_PREFIX "redirect"
|
#define OVL_XATTR_REDIRECT OVL_XATTR_PREFIX "redirect"
|
||||||
#define OVL_XATTR_ORIGIN OVL_XATTR_PREFIX "origin"
|
#define OVL_XATTR_ORIGIN OVL_XATTR_PREFIX "origin"
|
||||||
|
#define OVL_XATTR_IMPURE OVL_XATTR_PREFIX "impure"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The tuple (fh,uuid) is a universal unique identifier for a copy up origin,
|
* The tuple (fh,uuid) is a universal unique identifier for a copy up origin,
|
||||||
|
@ -203,8 +204,10 @@ struct dentry *ovl_dentry_real(struct dentry *dentry);
|
||||||
struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry);
|
struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry);
|
||||||
void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache);
|
void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache);
|
||||||
bool ovl_dentry_is_opaque(struct dentry *dentry);
|
bool ovl_dentry_is_opaque(struct dentry *dentry);
|
||||||
|
bool ovl_dentry_is_impure(struct dentry *dentry);
|
||||||
bool ovl_dentry_is_whiteout(struct dentry *dentry);
|
bool ovl_dentry_is_whiteout(struct dentry *dentry);
|
||||||
void ovl_dentry_set_opaque(struct dentry *dentry);
|
void ovl_dentry_set_opaque(struct dentry *dentry);
|
||||||
|
void ovl_dentry_set_impure(struct dentry *dentry);
|
||||||
bool ovl_redirect_dir(struct super_block *sb);
|
bool ovl_redirect_dir(struct super_block *sb);
|
||||||
const char *ovl_dentry_get_redirect(struct dentry *dentry);
|
const char *ovl_dentry_get_redirect(struct dentry *dentry);
|
||||||
void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect);
|
void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect);
|
||||||
|
|
|
@ -43,6 +43,7 @@ struct ovl_entry {
|
||||||
u64 version;
|
u64 version;
|
||||||
const char *redirect;
|
const char *redirect;
|
||||||
bool opaque;
|
bool opaque;
|
||||||
|
bool impure;
|
||||||
bool copying;
|
bool copying;
|
||||||
};
|
};
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
|
|
|
@ -175,6 +175,13 @@ bool ovl_dentry_is_opaque(struct dentry *dentry)
|
||||||
return oe->opaque;
|
return oe->opaque;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ovl_dentry_is_impure(struct dentry *dentry)
|
||||||
|
{
|
||||||
|
struct ovl_entry *oe = dentry->d_fsdata;
|
||||||
|
|
||||||
|
return oe->impure;
|
||||||
|
}
|
||||||
|
|
||||||
bool ovl_dentry_is_whiteout(struct dentry *dentry)
|
bool ovl_dentry_is_whiteout(struct dentry *dentry)
|
||||||
{
|
{
|
||||||
return !dentry->d_inode && ovl_dentry_is_opaque(dentry);
|
return !dentry->d_inode && ovl_dentry_is_opaque(dentry);
|
||||||
|
@ -187,6 +194,13 @@ void ovl_dentry_set_opaque(struct dentry *dentry)
|
||||||
oe->opaque = true;
|
oe->opaque = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ovl_dentry_set_impure(struct dentry *dentry)
|
||||||
|
{
|
||||||
|
struct ovl_entry *oe = dentry->d_fsdata;
|
||||||
|
|
||||||
|
oe->impure = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ovl_redirect_dir(struct super_block *sb)
|
bool ovl_redirect_dir(struct super_block *sb)
|
||||||
{
|
{
|
||||||
struct ovl_fs *ofs = sb->s_fs_info;
|
struct ovl_fs *ofs = sb->s_fs_info;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче