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.c63
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
34static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) 35static 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 */
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
751/* Given fattrs, get a corresponding inode */ 772/* Given fattrs, get a corresponding inode */
752struct inode * 773struct inode *
753cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) 774cifs_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
1573int cifs_revalidate_file(struct file *filp) 1608int cifs_revalidate_file(struct file *filp)