aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r--fs/cifs/inode.c43
1 files changed, 31 insertions, 12 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index a15b3a9bbff4..dc4c47ab9588 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -732,15 +732,9 @@ cifs_find_inode(struct inode *inode, void *opaque)
732 if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) 732 if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
733 return 0; 733 return 0;
734 734
735 /* 735 /* if it's not a directory or has no dentries, then flag it */
736 * uh oh -- it's a directory. We can't use it since hardlinked dirs are 736 if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry))
737 * verboten. Disable serverino and return it as if it were found, the
738 * caller can discard it, generate a uniqueid and retry the find
739 */
740 if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) {
741 fattr->cf_flags |= CIFS_FATTR_INO_COLLISION; 737 fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
742 cifs_autodisable_serverino(CIFS_SB(inode->i_sb));
743 }
744 738
745 return 1; 739 return 1;
746} 740}
@@ -754,6 +748,27 @@ cifs_init_inode(struct inode *inode, void *opaque)
754 return 0; 748 return 0;
755} 749}
756 750
751/*
752 * walk dentry list for an inode and report whether it has aliases that
753 * are hashed. We use this to determine if a directory inode can actually
754 * be used.
755 */
756static bool
757inode_has_hashed_dentries(struct inode *inode)
758{
759 struct dentry *dentry;
760
761 spin_lock(&dcache_lock);
762 list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
763 if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
764 spin_unlock(&dcache_lock);
765 return true;
766 }
767 }
768 spin_unlock(&dcache_lock);
769 return false;
770}
771
757/* Given fattrs, get a corresponding inode */ 772/* Given fattrs, get a corresponding inode */
758struct inode * 773struct inode *
759cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) 774cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
@@ -769,12 +784,16 @@ retry_iget5_locked:
769 784
770 inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr); 785 inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
771 if (inode) { 786 if (inode) {
772 /* was there a problematic inode number collision? */ 787 /* was there a potentially problematic inode collision? */
773 if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) { 788 if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
774 iput(inode);
775 fattr->cf_uniqueid = iunique(sb, ROOT_I);
776 fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION; 789 fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
777 goto retry_iget5_locked; 790
791 if (inode_has_hashed_dentries(inode)) {
792 cifs_autodisable_serverino(CIFS_SB(sb));
793 iput(inode);
794 fattr->cf_uniqueid = iunique(sb, ROOT_I);
795 goto retry_iget5_locked;
796 }
778 } 797 }
779 798
780 cifs_fattr_to_inode(inode, fattr); 799 cifs_fattr_to_inode(inode, fattr);