diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c index 8e37a07b9eff5cc74bc7aa6b6462bcac52170dc0..8c0172d9b92238aa7b855e38e864db7ea5776815 100644 --- a/fs/overlayfs/export.c +++ b/fs/overlayfs/export.c @@ -169,16 +169,16 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb, struct dentry *upper, struct ovl_path *lowerpath) { - struct inode *inode; + struct dentry *lower = lowerpath ? lowerpath->dentry : NULL; struct dentry *dentry; + struct inode *inode; struct ovl_entry *oe; - void *fsdata = &oe; - /* TODO: obtain non pure-upper */ - if (lowerpath) + /* TODO: obtain an indexed non-dir upper with origin */ + if (lower && (upper || d_is_dir(lower))) return ERR_PTR(-EIO); - inode = ovl_get_inode(sb, dget(upper), NULL, NULL, 0); + inode = ovl_get_inode(sb, dget(upper), lower, NULL, !!lower); if (IS_ERR(inode)) { dput(upper); return ERR_CAST(inode); @@ -189,12 +189,17 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb, dentry = d_alloc_anon(inode->i_sb); if (!dentry) goto nomem; - oe = ovl_alloc_entry(0); + oe = ovl_alloc_entry(lower ? 1 : 0); if (!oe) goto nomem; + if (lower) { + oe->lowerstack->dentry = dget(lower); + oe->lowerstack->layer = lowerpath->layer; + } dentry->d_fsdata = oe; - ovl_dentry_set_upper_alias(dentry); + if (upper) + ovl_dentry_set_upper_alias(dentry); } return d_instantiate_anon(dentry, inode); @@ -381,7 +386,14 @@ static struct dentry *ovl_get_dentry(struct super_block *sb, struct ovl_fs *ofs = sb->s_fs_info; struct ovl_layer upper_layer = { .mnt = ofs->upper_mnt }; - /* TODO: get non-upper dentry */ + /* + * Obtain a disconnected overlay dentry from a disconnected non-dir + * real lower dentry. + */ + if (!upper && !d_is_dir(lowerpath->dentry)) + return ovl_obtain_alias(sb, NULL, lowerpath); + + /* TODO: lookup connected dir from real lower dir */ if (!upper) return ERR_PTR(-EACCES); @@ -423,6 +435,25 @@ static struct dentry *ovl_upper_fh_to_d(struct super_block *sb, return dentry; } +static struct dentry *ovl_lower_fh_to_d(struct super_block *sb, + struct ovl_fh *fh) +{ + struct ovl_fs *ofs = sb->s_fs_info; + struct ovl_path origin = { }; + struct ovl_path *stack = &origin; + struct dentry *dentry = NULL; + int err; + + err = ovl_check_origin_fh(ofs, fh, NULL, &stack); + if (err) + return ERR_PTR(err); + + dentry = ovl_get_dentry(sb, NULL, &origin); + dput(origin.dentry); + + return dentry; +} + static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) { @@ -440,10 +471,10 @@ static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid, if (err) goto out_err; - /* TODO: decode non-upper */ flags = fh->flags; - if (flags & OVL_FH_FLAG_PATH_UPPER) - dentry = ovl_upper_fh_to_d(sb, fh); + dentry = (flags & OVL_FH_FLAG_PATH_UPPER) ? + ovl_upper_fh_to_d(sb, fh) : + ovl_lower_fh_to_d(sb, fh); err = PTR_ERR(dentry); if (IS_ERR(dentry) && err != -ESTALE) goto out_err; diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index a35c5eaa2c016c76767a3a0fbe7d812d563450d1..741a42d974a354982528389d7c21e43b4fa9434f 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -310,9 +310,8 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d, } -static int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, - struct dentry *upperdentry, - struct ovl_path **stackp) +int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, + struct dentry *upperdentry, struct ovl_path **stackp) { struct dentry *origin = NULL; int i; @@ -328,7 +327,7 @@ static int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, else if (IS_ERR(origin)) return PTR_ERR(origin); - if (!ovl_is_whiteout(upperdentry) && + if (upperdentry && !ovl_is_whiteout(upperdentry) && ((d_inode(origin)->i_mode ^ d_inode(upperdentry)->i_mode) & S_IFMT)) goto invalid; diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 401113a2e9c76d06af80fa8519374b99361c7d52..40ba11e412b16b9db78c0f76f12aa2c5ccd25142 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -266,6 +266,8 @@ static inline bool ovl_is_impuredir(struct dentry *dentry) /* namei.c */ int ovl_check_fh_len(struct ovl_fh *fh, int fh_len); struct dentry *ovl_decode_fh(struct ovl_fh *fh, struct vfsmount *mnt); +int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, + struct dentry *upperdentry, struct ovl_path **stackp); int ovl_verify_set_fh(struct dentry *dentry, const char *name, struct dentry *real, bool is_upper, bool set); int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index);