diff options
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r-- | fs/cifs/inode.c | 98 |
1 files changed, 57 insertions, 41 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index f121a80fdd6f..9c869a6dcba1 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -143,6 +143,7 @@ static void cifs_unix_info_to_inode(struct inode *inode, | |||
143 | 143 | ||
144 | inode->i_nlink = le64_to_cpu(info->Nlinks); | 144 | inode->i_nlink = le64_to_cpu(info->Nlinks); |
145 | 145 | ||
146 | cifsInfo->server_eof = end_of_file; | ||
146 | spin_lock(&inode->i_lock); | 147 | spin_lock(&inode->i_lock); |
147 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { | 148 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { |
148 | /* | 149 | /* |
@@ -276,7 +277,8 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
276 | 277 | ||
277 | /* get new inode */ | 278 | /* get new inode */ |
278 | if (*pinode == NULL) { | 279 | if (*pinode == NULL) { |
279 | *pinode = cifs_new_inode(sb, &find_data.UniqueId); | 280 | __u64 unique_id = le64_to_cpu(find_data.UniqueId); |
281 | *pinode = cifs_new_inode(sb, &unique_id); | ||
280 | if (*pinode == NULL) { | 282 | if (*pinode == NULL) { |
281 | rc = -ENOMEM; | 283 | rc = -ENOMEM; |
282 | goto cgiiu_exit; | 284 | goto cgiiu_exit; |
@@ -605,12 +607,12 @@ int cifs_get_inode_info(struct inode **pinode, | |||
605 | inode->i_mode |= S_IFREG; | 607 | inode->i_mode |= S_IFREG; |
606 | } | 608 | } |
607 | 609 | ||
610 | cifsInfo->server_eof = le64_to_cpu(pfindData->EndOfFile); | ||
608 | spin_lock(&inode->i_lock); | 611 | spin_lock(&inode->i_lock); |
609 | if (is_size_safe_to_change(cifsInfo, | 612 | if (is_size_safe_to_change(cifsInfo, cifsInfo->server_eof)) { |
610 | le64_to_cpu(pfindData->EndOfFile))) { | ||
611 | /* can not safely shrink the file size here if the | 613 | /* can not safely shrink the file size here if the |
612 | client is writing to it due to potential races */ | 614 | client is writing to it due to potential races */ |
613 | i_size_write(inode, le64_to_cpu(pfindData->EndOfFile)); | 615 | i_size_write(inode, cifsInfo->server_eof); |
614 | 616 | ||
615 | /* 512 bytes (2**9) is the fake blocksize that must be | 617 | /* 512 bytes (2**9) is the fake blocksize that must be |
616 | used for this calculation */ | 618 | used for this calculation */ |
@@ -960,13 +962,21 @@ undo_setattr: | |||
960 | goto out_close; | 962 | goto out_close; |
961 | } | 963 | } |
962 | 964 | ||
965 | |||
966 | /* | ||
967 | * If dentry->d_inode is null (usually meaning the cached dentry | ||
968 | * is a negative dentry) then we would attempt a standard SMB delete, but | ||
969 | * if that fails we can not attempt the fall back mechanisms on EACESS | ||
970 | * but will return the EACESS to the caller. Note that the VFS does not call | ||
971 | * unlink on negative dentries currently. | ||
972 | */ | ||
963 | int cifs_unlink(struct inode *dir, struct dentry *dentry) | 973 | int cifs_unlink(struct inode *dir, struct dentry *dentry) |
964 | { | 974 | { |
965 | int rc = 0; | 975 | int rc = 0; |
966 | int xid; | 976 | int xid; |
967 | char *full_path = NULL; | 977 | char *full_path = NULL; |
968 | struct inode *inode = dentry->d_inode; | 978 | struct inode *inode = dentry->d_inode; |
969 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | 979 | struct cifsInodeInfo *cifs_inode; |
970 | struct super_block *sb = dir->i_sb; | 980 | struct super_block *sb = dir->i_sb; |
971 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 981 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
972 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 982 | struct cifsTconInfo *tcon = cifs_sb->tcon; |
@@ -1010,7 +1020,7 @@ psx_del_no_retry: | |||
1010 | rc = cifs_rename_pending_delete(full_path, dentry, xid); | 1020 | rc = cifs_rename_pending_delete(full_path, dentry, xid); |
1011 | if (rc == 0) | 1021 | if (rc == 0) |
1012 | drop_nlink(inode); | 1022 | drop_nlink(inode); |
1013 | } else if (rc == -EACCES && dosattr == 0) { | 1023 | } else if ((rc == -EACCES) && (dosattr == 0) && inode) { |
1014 | attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); | 1024 | attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); |
1015 | if (attrs == NULL) { | 1025 | if (attrs == NULL) { |
1016 | rc = -ENOMEM; | 1026 | rc = -ENOMEM; |
@@ -1018,7 +1028,8 @@ psx_del_no_retry: | |||
1018 | } | 1028 | } |
1019 | 1029 | ||
1020 | /* try to reset dos attributes */ | 1030 | /* try to reset dos attributes */ |
1021 | origattr = cifsInode->cifsAttrs; | 1031 | cifs_inode = CIFS_I(inode); |
1032 | origattr = cifs_inode->cifsAttrs; | ||
1022 | if (origattr == 0) | 1033 | if (origattr == 0) |
1023 | origattr |= ATTR_NORMAL; | 1034 | origattr |= ATTR_NORMAL; |
1024 | dosattr = origattr & ~ATTR_READONLY; | 1035 | dosattr = origattr & ~ATTR_READONLY; |
@@ -1039,13 +1050,13 @@ psx_del_no_retry: | |||
1039 | 1050 | ||
1040 | out_reval: | 1051 | out_reval: |
1041 | if (inode) { | 1052 | if (inode) { |
1042 | cifsInode = CIFS_I(inode); | 1053 | cifs_inode = CIFS_I(inode); |
1043 | cifsInode->time = 0; /* will force revalidate to get info | 1054 | cifs_inode->time = 0; /* will force revalidate to get info |
1044 | when needed */ | 1055 | when needed */ |
1045 | inode->i_ctime = current_fs_time(sb); | 1056 | inode->i_ctime = current_fs_time(sb); |
1046 | } | 1057 | } |
1047 | dir->i_ctime = dir->i_mtime = current_fs_time(sb); | 1058 | dir->i_ctime = dir->i_mtime = current_fs_time(sb); |
1048 | cifsInode = CIFS_I(dir); | 1059 | cifs_inode = CIFS_I(dir); |
1049 | CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ | 1060 | CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ |
1050 | 1061 | ||
1051 | kfree(full_path); | 1062 | kfree(full_path); |
@@ -1138,6 +1149,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
1138 | cFYI(1, ("posix mkdir returned 0x%x", rc)); | 1149 | cFYI(1, ("posix mkdir returned 0x%x", rc)); |
1139 | d_drop(direntry); | 1150 | d_drop(direntry); |
1140 | } else { | 1151 | } else { |
1152 | __u64 unique_id; | ||
1141 | if (pInfo->Type == cpu_to_le32(-1)) { | 1153 | if (pInfo->Type == cpu_to_le32(-1)) { |
1142 | /* no return info, go query for it */ | 1154 | /* no return info, go query for it */ |
1143 | kfree(pInfo); | 1155 | kfree(pInfo); |
@@ -1151,8 +1163,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
1151 | else | 1163 | else |
1152 | direntry->d_op = &cifs_dentry_ops; | 1164 | direntry->d_op = &cifs_dentry_ops; |
1153 | 1165 | ||
1154 | newinode = cifs_new_inode(inode->i_sb, | 1166 | unique_id = le64_to_cpu(pInfo->UniqueId); |
1155 | &pInfo->UniqueId); | 1167 | newinode = cifs_new_inode(inode->i_sb, &unique_id); |
1156 | if (newinode == NULL) { | 1168 | if (newinode == NULL) { |
1157 | kfree(pInfo); | 1169 | kfree(pInfo); |
1158 | goto mkdir_get_info; | 1170 | goto mkdir_get_info; |
@@ -1450,7 +1462,8 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, | |||
1450 | checking the UniqueId via FILE_INTERNAL_INFO */ | 1462 | checking the UniqueId via FILE_INTERNAL_INFO */ |
1451 | 1463 | ||
1452 | unlink_target: | 1464 | unlink_target: |
1453 | if ((rc == -EACCES) || (rc == -EEXIST)) { | 1465 | /* Try unlinking the target dentry if it's not negative */ |
1466 | if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) { | ||
1454 | tmprc = cifs_unlink(target_dir, target_dentry); | 1467 | tmprc = cifs_unlink(target_dir, target_dentry); |
1455 | if (tmprc) | 1468 | if (tmprc) |
1456 | goto cifs_rename_exit; | 1469 | goto cifs_rename_exit; |
@@ -1753,6 +1766,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, | |||
1753 | } | 1766 | } |
1754 | 1767 | ||
1755 | if (rc == 0) { | 1768 | if (rc == 0) { |
1769 | cifsInode->server_eof = attrs->ia_size; | ||
1756 | rc = cifs_vmtruncate(inode, attrs->ia_size); | 1770 | rc = cifs_vmtruncate(inode, attrs->ia_size); |
1757 | cifs_truncate_page(inode->i_mapping, inode->i_size); | 1771 | cifs_truncate_page(inode->i_mapping, inode->i_size); |
1758 | } | 1772 | } |
@@ -1792,20 +1806,21 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
1792 | goto out; | 1806 | goto out; |
1793 | } | 1807 | } |
1794 | 1808 | ||
1795 | if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { | 1809 | /* |
1796 | /* | 1810 | * Attempt to flush data before changing attributes. We need to do |
1797 | Flush data before changing file size or changing the last | 1811 | * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the |
1798 | write time of the file on the server. If the | 1812 | * ownership or mode then we may also need to do this. Here, we take |
1799 | flush returns error, store it to report later and continue. | 1813 | * the safe way out and just do the flush on all setattr requests. If |
1800 | BB: This should be smarter. Why bother flushing pages that | 1814 | * the flush returns error, store it to report later and continue. |
1801 | will be truncated anyway? Also, should we error out here if | 1815 | * |
1802 | the flush returns error? | 1816 | * BB: This should be smarter. Why bother flushing pages that |
1803 | */ | 1817 | * will be truncated anyway? Also, should we error out here if |
1804 | rc = filemap_write_and_wait(inode->i_mapping); | 1818 | * the flush returns error? |
1805 | if (rc != 0) { | 1819 | */ |
1806 | cifsInode->write_behind_rc = rc; | 1820 | rc = filemap_write_and_wait(inode->i_mapping); |
1807 | rc = 0; | 1821 | if (rc != 0) { |
1808 | } | 1822 | cifsInode->write_behind_rc = rc; |
1823 | rc = 0; | ||
1809 | } | 1824 | } |
1810 | 1825 | ||
1811 | if (attrs->ia_valid & ATTR_SIZE) { | 1826 | if (attrs->ia_valid & ATTR_SIZE) { |
@@ -1903,20 +1918,21 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
1903 | return -ENOMEM; | 1918 | return -ENOMEM; |
1904 | } | 1919 | } |
1905 | 1920 | ||
1906 | if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { | 1921 | /* |
1907 | /* | 1922 | * Attempt to flush data before changing attributes. We need to do |
1908 | Flush data before changing file size or changing the last | 1923 | * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the |
1909 | write time of the file on the server. If the | 1924 | * ownership or mode then we may also need to do this. Here, we take |
1910 | flush returns error, store it to report later and continue. | 1925 | * the safe way out and just do the flush on all setattr requests. If |
1911 | BB: This should be smarter. Why bother flushing pages that | 1926 | * the flush returns error, store it to report later and continue. |
1912 | will be truncated anyway? Also, should we error out here if | 1927 | * |
1913 | the flush returns error? | 1928 | * BB: This should be smarter. Why bother flushing pages that |
1914 | */ | 1929 | * will be truncated anyway? Also, should we error out here if |
1915 | rc = filemap_write_and_wait(inode->i_mapping); | 1930 | * the flush returns error? |
1916 | if (rc != 0) { | 1931 | */ |
1917 | cifsInode->write_behind_rc = rc; | 1932 | rc = filemap_write_and_wait(inode->i_mapping); |
1918 | rc = 0; | 1933 | if (rc != 0) { |
1919 | } | 1934 | cifsInode->write_behind_rc = rc; |
1935 | rc = 0; | ||
1920 | } | 1936 | } |
1921 | 1937 | ||
1922 | if (attrs->ia_valid & ATTR_SIZE) { | 1938 | if (attrs->ia_valid & ATTR_SIZE) { |