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); |
