On Sun, Jun 28, 2015 at 05:38:35PM +0300, sa wrote: > On 04.06.2015 16:29, Miklos Szeredi wrote: > > >Two small patches implementing this follow. Comments and testing welcome. > > git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git overlayfs-next > >--- > > fs/overlayfs/super.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++----- > > 1 file changed, 74 insertions(+), 7 deletions(-) > > Thank you, it works in our environment mostly as expected, except > of the following: > files already existing in readonly NFS lowerdir can't be opened > for writing (but can be deleted). Newly created files are writable > as expected. The same lowerdir works with aufs without problem. > Is it a bug or am I missing something? Is the lower fs exported read-only on the NFS server? If so, can you please apply the following patch and specify 'default_permissions' mount option? Thanks, Miklos --- fs/overlayfs/inode.c | 23 +++++++++++++++++++++++ fs/overlayfs/overlayfs.h | 3 +++ fs/overlayfs/super.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -142,7 +142,10 @@ struct dentry *ovl_dentry_upper(struct d struct dentry *ovl_dentry_lower(struct dentry *dentry); struct dentry *ovl_dentry_real(struct dentry *dentry); struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper); +struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode, + bool is_upper); struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry); +bool ovl_is_default_permissions(struct inode *inode); void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache); struct dentry *ovl_workdir(struct dentry *dentry); int ovl_want_write(struct dentry *dentry); --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -30,6 +30,7 @@ struct ovl_config { char *lowerdir; char *upperdir; char *workdir; + bool default_permissions; }; /* private information held for overlayfs's superblock */ @@ -154,6 +155,18 @@ struct dentry *ovl_entry_real(struct ovl return realdentry; } +struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode, + bool is_upper) +{ + if (is_upper) { + struct ovl_fs *ofs = inode->i_sb->s_fs_info; + + return ofs->upper_mnt; + } else { + return oe->numlower ? oe->lowerstack[0].mnt : NULL; + } +} + struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry) { struct ovl_entry *oe = dentry->d_fsdata; @@ -161,6 +174,13 @@ struct ovl_dir_cache *ovl_dir_cache(stru return oe->cache; } +bool ovl_is_default_permissions(struct inode *inode) +{ + struct ovl_fs *ofs = inode->i_sb->s_fs_info; + + return ofs->config.default_permissions; +} + void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache) { struct ovl_entry *oe = dentry->d_fsdata; @@ -592,6 +612,8 @@ static int ovl_show_options(struct seq_f seq_printf(m, ",upperdir=%s", ufs->config.upperdir); seq_printf(m, ",workdir=%s", ufs->config.workdir); } + if (ufs->config.default_permissions) + seq_puts(m, ",default_permissions"); return 0; } @@ -616,6 +638,7 @@ enum { OPT_LOWERDIR, OPT_UPPERDIR, OPT_WORKDIR, + OPT_DEFAULT_PERMISSIONS, OPT_ERR, }; @@ -623,6 +646,7 @@ static const match_table_t ovl_tokens = {OPT_LOWERDIR, "lowerdir=%s"}, {OPT_UPPERDIR, "upperdir=%s"}, {OPT_WORKDIR, "workdir=%s"}, + {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, {OPT_ERR, NULL} }; @@ -683,6 +707,10 @@ static int ovl_parse_opt(char *opt, stru return -ENOMEM; break; + case OPT_DEFAULT_PERMISSIONS: + config->default_permissions = true; + break; + default: pr_err("overlayfs: unrecognized mount option \"%s\" or missing value\n", p); return -EINVAL; --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -98,6 +98,29 @@ int ovl_permission(struct inode *inode, realdentry = ovl_entry_real(oe, &is_upper); + if (ovl_is_default_permissions(inode)) { + struct kstat stat; + struct path realpath = { .dentry = realdentry }; + + if (mask & MAY_NOT_BLOCK) + return -ECHILD; + + realpath.mnt = ovl_entry_mnt_real(oe, inode, is_upper); + + err = vfs_getattr(&realpath, &stat); + if (err) + return err; + + if ((stat.mode ^ inode->i_mode) & S_IFMT) + return -ESTALE; + + inode->i_mode = stat.mode; + inode->i_uid = stat.uid; + inode->i_gid = stat.gid; + + return generic_permission(inode, mask); + } + /* Careful in RCU walk mode */ realinode = ACCESS_ONCE(realdentry->d_inode); if (!realinode) { -- To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html