aboutsummaryrefslogtreecommitdiffstats
path: root/fs/overlayfs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/overlayfs/inode.c')
-rw-r--r--fs/overlayfs/inode.c58
1 files changed, 40 insertions, 18 deletions
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index fcd97b783fa1..3b1bd469accd 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -669,38 +669,59 @@ struct inode *ovl_lookup_inode(struct super_block *sb, struct dentry *real,
669 return inode; 669 return inode;
670} 670}
671 671
672/*
673 * Does overlay inode need to be hashed by lower inode?
674 */
675static bool ovl_hash_bylower(struct super_block *sb, struct dentry *upper,
676 struct dentry *lower, struct dentry *index)
677{
678 struct ovl_fs *ofs = sb->s_fs_info;
679
680 /* No, if pure upper */
681 if (!lower)
682 return false;
683
684 /* Yes, if already indexed */
685 if (index)
686 return true;
687
688 /* Yes, if won't be copied up */
689 if (!ofs->upper_mnt)
690 return true;
691
692 /* No, if lower hardlink is or will be broken on copy up */
693 if ((upper || !ovl_indexdir(sb)) &&
694 !d_is_dir(lower) && d_inode(lower)->i_nlink > 1)
695 return false;
696
697 /* No, if non-indexed upper with NFS export */
698 if (sb->s_export_op && upper)
699 return false;
700
701 /* Otherwise, hash by lower inode for fsnotify */
702 return true;
703}
704
672struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry, 705struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry,
673 struct dentry *lowerdentry, struct dentry *index, 706 struct dentry *lowerdentry, struct dentry *index,
674 unsigned int numlower) 707 unsigned int numlower)
675{ 708{
676 struct ovl_fs *ofs = sb->s_fs_info;
677 struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL; 709 struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL;
678 struct inode *inode; 710 struct inode *inode;
679 /* Already indexed or could be indexed on copy up? */ 711 bool bylower = ovl_hash_bylower(sb, upperdentry, lowerdentry, index);
680 bool indexed = (index || (ovl_indexdir(sb) && !upperdentry));
681 struct dentry *origin = indexed ? lowerdentry : NULL;
682 bool is_dir; 712 bool is_dir;
683 713
684 if (WARN_ON(upperdentry && indexed && !lowerdentry))
685 return ERR_PTR(-EIO);
686
687 if (!realinode) 714 if (!realinode)
688 realinode = d_inode(lowerdentry); 715 realinode = d_inode(lowerdentry);
689 716
690 /* 717 /*
691 * Copy up origin (lower) may exist for non-indexed non-dir upper, but 718 * Copy up origin (lower) may exist for non-indexed upper, but we must
692 * we must not use lower as hash key in that case. 719 * not use lower as hash key if this is a broken hardlink.
693 * Hash non-dir that is or could be indexed by origin inode.
694 * Hash dir that is or could be merged by origin inode.
695 * Hash pure upper and non-indexed non-dir by upper inode.
696 * Hash non-indexed dir by upper inode for NFS export.
697 */ 720 */
698 is_dir = S_ISDIR(realinode->i_mode); 721 is_dir = S_ISDIR(realinode->i_mode);
699 if (is_dir && (indexed || !sb->s_export_op || !ofs->upper_mnt)) 722 if (upperdentry || bylower) {
700 origin = lowerdentry; 723 struct inode *key = d_inode(bylower ? lowerdentry :
701 724 upperdentry);
702 if (upperdentry || origin) {
703 struct inode *key = d_inode(origin ?: upperdentry);
704 unsigned int nlink = is_dir ? 1 : realinode->i_nlink; 725 unsigned int nlink = is_dir ? 1 : realinode->i_nlink;
705 726
706 inode = iget5_locked(sb, (unsigned long) key, 727 inode = iget5_locked(sb, (unsigned long) key,
@@ -728,6 +749,7 @@ struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry,
728 nlink = ovl_get_nlink(lowerdentry, upperdentry, nlink); 749 nlink = ovl_get_nlink(lowerdentry, upperdentry, nlink);
729 set_nlink(inode, nlink); 750 set_nlink(inode, nlink);
730 } else { 751 } else {
752 /* Lower hardlink that will be broken on copy up */
731 inode = new_inode(sb); 753 inode = new_inode(sb);
732 if (!inode) 754 if (!inode)
733 goto out_nomem; 755 goto out_nomem;