diff options
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r-- | fs/cifs/inode.c | 149 |
1 files changed, 93 insertions, 56 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 6f0683c68952..4bc47e5b5f29 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) |
@@ -1663,26 +1698,16 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from) | |||
1663 | return rc; | 1698 | return rc; |
1664 | } | 1699 | } |
1665 | 1700 | ||
1666 | static int cifs_vmtruncate(struct inode *inode, loff_t offset) | 1701 | static void cifs_setsize(struct inode *inode, loff_t offset) |
1667 | { | 1702 | { |
1668 | loff_t oldsize; | 1703 | loff_t oldsize; |
1669 | int err; | ||
1670 | 1704 | ||
1671 | spin_lock(&inode->i_lock); | 1705 | spin_lock(&inode->i_lock); |
1672 | err = inode_newsize_ok(inode, offset); | ||
1673 | if (err) { | ||
1674 | spin_unlock(&inode->i_lock); | ||
1675 | goto out; | ||
1676 | } | ||
1677 | |||
1678 | oldsize = inode->i_size; | 1706 | oldsize = inode->i_size; |
1679 | i_size_write(inode, offset); | 1707 | i_size_write(inode, offset); |
1680 | spin_unlock(&inode->i_lock); | 1708 | spin_unlock(&inode->i_lock); |
1709 | |||
1681 | truncate_pagecache(inode, oldsize, offset); | 1710 | truncate_pagecache(inode, oldsize, offset); |
1682 | if (inode->i_op->truncate) | ||
1683 | inode->i_op->truncate(inode); | ||
1684 | out: | ||
1685 | return err; | ||
1686 | } | 1711 | } |
1687 | 1712 | ||
1688 | static int | 1713 | static int |
@@ -1755,7 +1780,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, | |||
1755 | 1780 | ||
1756 | if (rc == 0) { | 1781 | if (rc == 0) { |
1757 | cifsInode->server_eof = attrs->ia_size; | 1782 | cifsInode->server_eof = attrs->ia_size; |
1758 | rc = cifs_vmtruncate(inode, attrs->ia_size); | 1783 | cifs_setsize(inode, attrs->ia_size); |
1759 | cifs_truncate_page(inode->i_mapping, inode->i_size); | 1784 | cifs_truncate_page(inode->i_mapping, inode->i_size); |
1760 | } | 1785 | } |
1761 | 1786 | ||
@@ -1780,14 +1805,12 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
1780 | 1805 | ||
1781 | xid = GetXid(); | 1806 | xid = GetXid(); |
1782 | 1807 | ||
1783 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { | 1808 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) |
1784 | /* check if we have permission to change attrs */ | 1809 | attrs->ia_valid |= ATTR_FORCE; |
1785 | rc = inode_change_ok(inode, attrs); | 1810 | |
1786 | if (rc < 0) | 1811 | rc = inode_change_ok(inode, attrs); |
1787 | goto out; | 1812 | if (rc < 0) |
1788 | else | 1813 | goto out; |
1789 | rc = 0; | ||
1790 | } | ||
1791 | 1814 | ||
1792 | full_path = build_path_from_dentry(direntry); | 1815 | full_path = build_path_from_dentry(direntry); |
1793 | if (full_path == NULL) { | 1816 | if (full_path == NULL) { |
@@ -1873,18 +1896,24 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
1873 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1896 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
1874 | } | 1897 | } |
1875 | 1898 | ||
1876 | if (!rc) { | 1899 | if (rc) |
1877 | rc = inode_setattr(inode, attrs); | 1900 | goto out; |
1878 | 1901 | ||
1879 | /* force revalidate when any of these times are set since some | 1902 | if ((attrs->ia_valid & ATTR_SIZE) && |
1880 | of the fs types (eg ext3, fat) do not have fine enough | 1903 | attrs->ia_size != i_size_read(inode)) |
1881 | time granularity to match protocol, and we do not have a | 1904 | truncate_setsize(inode, attrs->ia_size); |
1882 | a way (yet) to query the server fs's time granularity (and | 1905 | |
1883 | whether it rounds times down). | 1906 | setattr_copy(inode, attrs); |
1884 | */ | 1907 | mark_inode_dirty(inode); |
1885 | if (!rc && (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))) | 1908 | |
1886 | cifsInode->time = 0; | 1909 | /* force revalidate when any of these times are set since some |
1887 | } | 1910 | of the fs types (eg ext3, fat) do not have fine enough |
1911 | time granularity to match protocol, and we do not have a | ||
1912 | a way (yet) to query the server fs's time granularity (and | ||
1913 | whether it rounds times down). | ||
1914 | */ | ||
1915 | if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)) | ||
1916 | cifsInode->time = 0; | ||
1888 | out: | 1917 | out: |
1889 | kfree(args); | 1918 | kfree(args); |
1890 | kfree(full_path); | 1919 | kfree(full_path); |
@@ -1909,14 +1938,13 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
1909 | cFYI(1, "setattr on file %s attrs->iavalid 0x%x", | 1938 | cFYI(1, "setattr on file %s attrs->iavalid 0x%x", |
1910 | direntry->d_name.name, attrs->ia_valid); | 1939 | direntry->d_name.name, attrs->ia_valid); |
1911 | 1940 | ||
1912 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { | 1941 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) |
1913 | /* check if we have permission to change attrs */ | 1942 | attrs->ia_valid |= ATTR_FORCE; |
1914 | rc = inode_change_ok(inode, attrs); | 1943 | |
1915 | if (rc < 0) { | 1944 | rc = inode_change_ok(inode, attrs); |
1916 | FreeXid(xid); | 1945 | if (rc < 0) { |
1917 | return rc; | 1946 | FreeXid(xid); |
1918 | } else | 1947 | return rc; |
1919 | rc = 0; | ||
1920 | } | 1948 | } |
1921 | 1949 | ||
1922 | full_path = build_path_from_dentry(direntry); | 1950 | full_path = build_path_from_dentry(direntry); |
@@ -2024,8 +2052,17 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
2024 | 2052 | ||
2025 | /* do not need local check to inode_check_ok since the server does | 2053 | /* do not need local check to inode_check_ok since the server does |
2026 | that */ | 2054 | that */ |
2027 | if (!rc) | 2055 | if (rc) |
2028 | rc = inode_setattr(inode, attrs); | 2056 | goto cifs_setattr_exit; |
2057 | |||
2058 | if ((attrs->ia_valid & ATTR_SIZE) && | ||
2059 | attrs->ia_size != i_size_read(inode)) | ||
2060 | truncate_setsize(inode, attrs->ia_size); | ||
2061 | |||
2062 | setattr_copy(inode, attrs); | ||
2063 | mark_inode_dirty(inode); | ||
2064 | return 0; | ||
2065 | |||
2029 | cifs_setattr_exit: | 2066 | cifs_setattr_exit: |
2030 | kfree(full_path); | 2067 | kfree(full_path); |
2031 | FreeXid(xid); | 2068 | FreeXid(xid); |