diff options
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r-- | fs/cifs/inode.c | 63 |
1 files changed, 49 insertions, 14 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 6f0683c68952..dc4c47ab9588 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "cifsproto.h" | 29 | #include "cifsproto.h" |
30 | #include "cifs_debug.h" | 30 | #include "cifs_debug.h" |
31 | #include "cifs_fs_sb.h" | 31 | #include "cifs_fs_sb.h" |
32 | #include "fscache.h" | ||
32 | 33 | ||
33 | 34 | ||
34 | static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) | 35 | static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) |
@@ -288,7 +289,7 @@ int cifs_get_file_info_unix(struct file *filp) | |||
288 | struct inode *inode = filp->f_path.dentry->d_inode; | 289 | struct inode *inode = filp->f_path.dentry->d_inode; |
289 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 290 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
290 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 291 | struct cifsTconInfo *tcon = cifs_sb->tcon; |
291 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; | 292 | struct cifsFileInfo *cfile = filp->private_data; |
292 | 293 | ||
293 | xid = GetXid(); | 294 | xid = GetXid(); |
294 | rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data); | 295 | rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data); |
@@ -515,7 +516,7 @@ int cifs_get_file_info(struct file *filp) | |||
515 | struct inode *inode = filp->f_path.dentry->d_inode; | 516 | struct inode *inode = filp->f_path.dentry->d_inode; |
516 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 517 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
517 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 518 | struct cifsTconInfo *tcon = cifs_sb->tcon; |
518 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; | 519 | struct cifsFileInfo *cfile = filp->private_data; |
519 | 520 | ||
520 | xid = GetXid(); | 521 | xid = GetXid(); |
521 | rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); | 522 | rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); |
@@ -723,18 +724,17 @@ cifs_find_inode(struct inode *inode, void *opaque) | |||
723 | { | 724 | { |
724 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; | 725 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; |
725 | 726 | ||
727 | /* don't match inode with different uniqueid */ | ||
726 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) | 728 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) |
727 | return 0; | 729 | return 0; |
728 | 730 | ||
729 | /* | 731 | /* don't match inode of different type */ |
730 | * uh oh -- it's a directory. We can't use it since hardlinked dirs are | 732 | if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) |
731 | * verboten. Disable serverino and return it as if it were found, the | 733 | return 0; |
732 | * caller can discard it, generate a uniqueid and retry the find | 734 | |
733 | */ | 735 | /* if it's not a directory or has no dentries, then flag it */ |
734 | if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) { | 736 | if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) |
735 | fattr->cf_flags |= CIFS_FATTR_INO_COLLISION; | 737 | fattr->cf_flags |= CIFS_FATTR_INO_COLLISION; |
736 | cifs_autodisable_serverino(CIFS_SB(inode->i_sb)); | ||
737 | } | ||
738 | 738 | ||
739 | return 1; | 739 | return 1; |
740 | } | 740 | } |
@@ -748,6 +748,27 @@ cifs_init_inode(struct inode *inode, void *opaque) | |||
748 | return 0; | 748 | return 0; |
749 | } | 749 | } |
750 | 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 | */ | ||
756 | static bool | ||
757 | inode_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 | |||
751 | /* Given fattrs, get a corresponding inode */ | 772 | /* Given fattrs, get a corresponding inode */ |
752 | struct inode * | 773 | struct inode * |
753 | cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) | 774 | cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) |
@@ -763,12 +784,16 @@ retry_iget5_locked: | |||
763 | 784 | ||
764 | 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); |
765 | if (inode) { | 786 | if (inode) { |
766 | /* was there a problematic inode number collision? */ | 787 | /* was there a potentially problematic inode collision? */ |
767 | if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) { | 788 | if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) { |
768 | iput(inode); | ||
769 | fattr->cf_uniqueid = iunique(sb, ROOT_I); | ||
770 | fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION; | 789 | fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION; |
771 | 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 | } | ||
772 | } | 797 | } |
773 | 798 | ||
774 | cifs_fattr_to_inode(inode, fattr); | 799 | cifs_fattr_to_inode(inode, fattr); |
@@ -776,6 +801,10 @@ retry_iget5_locked: | |||
776 | inode->i_flags |= S_NOATIME | S_NOCMTIME; | 801 | inode->i_flags |= S_NOATIME | S_NOCMTIME; |
777 | if (inode->i_state & I_NEW) { | 802 | if (inode->i_state & I_NEW) { |
778 | inode->i_ino = hash; | 803 | inode->i_ino = hash; |
804 | #ifdef CONFIG_CIFS_FSCACHE | ||
805 | /* initialize per-inode cache cookie pointer */ | ||
806 | CIFS_I(inode)->fscache = NULL; | ||
807 | #endif | ||
779 | unlock_new_inode(inode); | 808 | unlock_new_inode(inode); |
780 | } | 809 | } |
781 | } | 810 | } |
@@ -807,6 +836,11 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) | |||
807 | if (!inode) | 836 | if (!inode) |
808 | return ERR_PTR(-ENOMEM); | 837 | return ERR_PTR(-ENOMEM); |
809 | 838 | ||
839 | #ifdef CONFIG_CIFS_FSCACHE | ||
840 | /* populate tcon->resource_id */ | ||
841 | cifs_sb->tcon->resource_id = CIFS_I(inode)->uniqueid; | ||
842 | #endif | ||
843 | |||
810 | if (rc && cifs_sb->tcon->ipc) { | 844 | if (rc && cifs_sb->tcon->ipc) { |
811 | cFYI(1, "ipc connection - fake read inode"); | 845 | cFYI(1, "ipc connection - fake read inode"); |
812 | inode->i_mode |= S_IFDIR; | 846 | inode->i_mode |= S_IFDIR; |
@@ -1568,6 +1602,7 @@ cifs_invalidate_mapping(struct inode *inode) | |||
1568 | cifs_i->write_behind_rc = rc; | 1602 | cifs_i->write_behind_rc = rc; |
1569 | } | 1603 | } |
1570 | invalidate_remote_inode(inode); | 1604 | invalidate_remote_inode(inode); |
1605 | cifs_fscache_reset_inode_cookie(inode); | ||
1571 | } | 1606 | } |
1572 | 1607 | ||
1573 | int cifs_revalidate_file(struct file *filp) | 1608 | int cifs_revalidate_file(struct file *filp) |