diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 401cb8c75520..c9cca33008d3 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -999,7 +999,7 @@ int ovl_set_nlink_lower(struct dentry *dentry) } unsigned int ovl_get_nlink(struct ovl_fs *ofs, struct dentry *lowerdentry, - struct dentry *upperdentry, + struct dentry *upperdentry, bool indexed, unsigned int fallback) { int nlink_diff; @@ -1007,7 +1007,15 @@ unsigned int ovl_get_nlink(struct ovl_fs *ofs, struct dentry *lowerdentry, char buf[13]; int err; - if (!lowerdentry || !upperdentry || d_inode(lowerdentry)->i_nlink == 1) + if (!lowerdentry || !upperdentry) + return fallback; + + /* + * A lower inode with one link is not indexed on copy up, unless all + * files are indexed for NFS export. If the caller found an index entry, + * then the xattr holds the union nlink, whatever the lower nlink is. + */ + if (!indexed && d_inode(lowerdentry)->i_nlink == 1) return fallback; err = ovl_getxattr_upper(ofs, upperdentry, OVL_XATTR_NLINK, @@ -1264,7 +1272,7 @@ struct inode *ovl_get_inode(struct super_block *sb, /* Recalculate nlink for non-dir due to indexing */ if (!is_dir) nlink = ovl_get_nlink(ofs, lowerdentry, upperdentry, - nlink); + oip->index, nlink); set_nlink(inode, nlink); ino = key->i_ino; } else { diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index cf7908a39f61..ad0fb3d055ed 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -712,7 +712,7 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index) if (err) goto fail; - if (ovl_get_nlink(ofs, origin.dentry, index, 0) == 0) + if (ovl_get_nlink(ofs, origin.dentry, index, true, 0) == 0) goto orphan; } diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index c89739e5338b..91cdd7e15696 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -808,7 +808,7 @@ static inline bool ovl_dir_is_real(struct inode *dir) int ovl_set_nlink_upper(struct dentry *dentry); int ovl_set_nlink_lower(struct dentry *dentry); unsigned int ovl_get_nlink(struct ovl_fs *ofs, struct dentry *lowerdentry, - struct dentry *upperdentry, + struct dentry *upperdentry, bool indexed, unsigned int fallback); int ovl_permission(struct mnt_idmap *idmap, struct inode *inode, int mask);