diff options
Diffstat (limited to 'fs/cifs/inode.c')
| -rw-r--r-- | fs/cifs/inode.c | 150 |
1 files changed, 100 insertions, 50 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 8d336a900255..912d401600f6 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -166,7 +166,13 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
| 166 | inode->i_fop = &cifs_file_direct_ops; | 166 | inode->i_fop = &cifs_file_direct_ops; |
| 167 | else | 167 | else |
| 168 | inode->i_fop = &cifs_file_ops; | 168 | inode->i_fop = &cifs_file_ops; |
| 169 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
| 170 | inode->i_fop->lock = NULL; | ||
| 169 | inode->i_data.a_ops = &cifs_addr_ops; | 171 | inode->i_data.a_ops = &cifs_addr_ops; |
| 172 | /* check if server can support readpages */ | ||
| 173 | if(pTcon->ses->server->maxBuf < | ||
| 174 | 4096 + MAX_CIFS_HDR_SIZE) | ||
| 175 | inode->i_data.a_ops->readpages = NULL; | ||
| 170 | } else if (S_ISDIR(inode->i_mode)) { | 176 | } else if (S_ISDIR(inode->i_mode)) { |
| 171 | cFYI(1, (" Directory inode")); | 177 | cFYI(1, (" Directory inode")); |
| 172 | inode->i_op = &cifs_dir_inode_ops; | 178 | inode->i_op = &cifs_dir_inode_ops; |
| @@ -213,8 +219,18 @@ int cifs_get_inode_info(struct inode **pinode, | |||
| 213 | pfindData = (FILE_ALL_INFO *)buf; | 219 | pfindData = (FILE_ALL_INFO *)buf; |
| 214 | /* could do find first instead but this returns more info */ | 220 | /* could do find first instead but this returns more info */ |
| 215 | rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, | 221 | rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, |
| 216 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 222 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
| 217 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 223 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 224 | /* BB optimize code so we do not make the above call | ||
| 225 | when server claims no NT SMB support and the above call | ||
| 226 | failed at least once - set flag in tcon or mount */ | ||
| 227 | if((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { | ||
| 228 | rc = SMBQueryInformation(xid, pTcon, search_path, | ||
| 229 | pfindData, cifs_sb->local_nls, | ||
| 230 | cifs_sb->mnt_cifs_flags & | ||
| 231 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 232 | } | ||
| 233 | |||
| 218 | } | 234 | } |
| 219 | /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ | 235 | /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ |
| 220 | if (rc) { | 236 | if (rc) { |
| @@ -320,6 +336,16 @@ int cifs_get_inode_info(struct inode **pinode, | |||
| 320 | on dirs */ | 336 | on dirs */ |
| 321 | inode->i_mode = cifs_sb->mnt_dir_mode; | 337 | inode->i_mode = cifs_sb->mnt_dir_mode; |
| 322 | inode->i_mode |= S_IFDIR; | 338 | inode->i_mode |= S_IFDIR; |
| 339 | } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
| 340 | (cifsInfo->cifsAttrs & ATTR_SYSTEM) && | ||
| 341 | /* No need to le64 convert size of zero */ | ||
| 342 | (pfindData->EndOfFile == 0)) { | ||
| 343 | inode->i_mode = cifs_sb->mnt_file_mode; | ||
| 344 | inode->i_mode |= S_IFIFO; | ||
| 345 | /* BB Finish for SFU style symlinks and devies */ | ||
| 346 | /* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
| 347 | (cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */ | ||
| 348 | |||
| 323 | } else { | 349 | } else { |
| 324 | inode->i_mode |= S_IFREG; | 350 | inode->i_mode |= S_IFREG; |
| 325 | /* treat the dos attribute of read-only as read-only | 351 | /* treat the dos attribute of read-only as read-only |
| @@ -359,7 +385,12 @@ int cifs_get_inode_info(struct inode **pinode, | |||
| 359 | inode->i_fop = &cifs_file_direct_ops; | 385 | inode->i_fop = &cifs_file_direct_ops; |
| 360 | else | 386 | else |
| 361 | inode->i_fop = &cifs_file_ops; | 387 | inode->i_fop = &cifs_file_ops; |
| 388 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
| 389 | inode->i_fop->lock = NULL; | ||
| 362 | inode->i_data.a_ops = &cifs_addr_ops; | 390 | inode->i_data.a_ops = &cifs_addr_ops; |
| 391 | if(pTcon->ses->server->maxBuf < | ||
| 392 | 4096 + MAX_CIFS_HDR_SIZE) | ||
| 393 | inode->i_data.a_ops->readpages = NULL; | ||
| 363 | } else if (S_ISDIR(inode->i_mode)) { | 394 | } else if (S_ISDIR(inode->i_mode)) { |
| 364 | cFYI(1, (" Directory inode ")); | 395 | cFYI(1, (" Directory inode ")); |
| 365 | inode->i_op = &cifs_dir_inode_ops; | 396 | inode->i_op = &cifs_dir_inode_ops; |
| @@ -577,7 +608,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
| 577 | rc = cifs_get_inode_info(&newinode, full_path, NULL, | 608 | rc = cifs_get_inode_info(&newinode, full_path, NULL, |
| 578 | inode->i_sb,xid); | 609 | inode->i_sb,xid); |
| 579 | 610 | ||
| 580 | direntry->d_op = &cifs_dentry_ops; | 611 | if (pTcon->nocase) |
| 612 | direntry->d_op = &cifs_ci_dentry_ops; | ||
| 613 | else | ||
| 614 | direntry->d_op = &cifs_dentry_ops; | ||
| 581 | d_instantiate(direntry, newinode); | 615 | d_instantiate(direntry, newinode); |
| 582 | if (direntry->d_inode) | 616 | if (direntry->d_inode) |
| 583 | direntry->d_inode->i_nlink = 2; | 617 | direntry->d_inode->i_nlink = 2; |
| @@ -928,7 +962,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 928 | struct cifsTconInfo *pTcon; | 962 | struct cifsTconInfo *pTcon; |
| 929 | char *full_path = NULL; | 963 | char *full_path = NULL; |
| 930 | int rc = -EACCES; | 964 | int rc = -EACCES; |
| 931 | int found = FALSE; | ||
| 932 | struct cifsFileInfo *open_file = NULL; | 965 | struct cifsFileInfo *open_file = NULL; |
| 933 | FILE_BASIC_INFO time_buf; | 966 | FILE_BASIC_INFO time_buf; |
| 934 | int set_time = FALSE; | 967 | int set_time = FALSE; |
| @@ -936,7 +969,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 936 | __u64 uid = 0xFFFFFFFFFFFFFFFFULL; | 969 | __u64 uid = 0xFFFFFFFFFFFFFFFFULL; |
| 937 | __u64 gid = 0xFFFFFFFFFFFFFFFFULL; | 970 | __u64 gid = 0xFFFFFFFFFFFFFFFFULL; |
| 938 | struct cifsInodeInfo *cifsInode; | 971 | struct cifsInodeInfo *cifsInode; |
| 939 | struct list_head *tmp; | ||
| 940 | 972 | ||
| 941 | xid = GetXid(); | 973 | xid = GetXid(); |
| 942 | 974 | ||
| @@ -961,7 +993,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 961 | filemap_fdatawait(direntry->d_inode->i_mapping); | 993 | filemap_fdatawait(direntry->d_inode->i_mapping); |
| 962 | 994 | ||
| 963 | if (attrs->ia_valid & ATTR_SIZE) { | 995 | if (attrs->ia_valid & ATTR_SIZE) { |
| 964 | read_lock(&GlobalSMBSeslock); | ||
| 965 | /* To avoid spurious oplock breaks from server, in the case of | 996 | /* To avoid spurious oplock breaks from server, in the case of |
| 966 | inodes that we already have open, avoid doing path based | 997 | inodes that we already have open, avoid doing path based |
| 967 | setting of file size if we can do it by handle. | 998 | setting of file size if we can do it by handle. |
| @@ -969,40 +1000,23 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 969 | when the local oplock break takes longer to flush | 1000 | when the local oplock break takes longer to flush |
| 970 | writebehind data than the SMB timeout for the SetPathInfo | 1001 | writebehind data than the SMB timeout for the SetPathInfo |
| 971 | request would allow */ | 1002 | request would allow */ |
| 972 | list_for_each(tmp, &cifsInode->openFileList) { | 1003 | open_file = find_writable_file(cifsInode); |
| 973 | open_file = list_entry(tmp, struct cifsFileInfo, | 1004 | if (open_file) { |
| 974 | flist); | 1005 | __u16 nfid = open_file->netfid; |
| 975 | /* We check if file is open for writing first */ | 1006 | __u32 npid = open_file->pid; |
| 976 | if ((open_file->pfile) && | 1007 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, |
| 977 | ((open_file->pfile->f_flags & O_RDWR) || | 1008 | nfid, npid, FALSE); |
| 978 | (open_file->pfile->f_flags & O_WRONLY))) { | 1009 | atomic_dec(&open_file->wrtPending); |
| 979 | if (open_file->invalidHandle == FALSE) { | 1010 | cFYI(1,("SetFSize for attrs rc = %d", rc)); |
| 980 | /* we found a valid, writeable network | 1011 | if(rc == -EINVAL) { |
| 981 | file handle to use to try to set the | 1012 | int bytes_written; |
| 982 | file size */ | 1013 | rc = CIFSSMBWrite(xid, pTcon, |
| 983 | __u16 nfid = open_file->netfid; | 1014 | nfid, 0, attrs->ia_size, |
| 984 | __u32 npid = open_file->pid; | 1015 | &bytes_written, NULL, NULL, |
| 985 | read_unlock(&GlobalSMBSeslock); | 1016 | 1 /* 45 seconds */); |
| 986 | found = TRUE; | 1017 | cFYI(1,("Wrt seteof rc %d", rc)); |
| 987 | rc = CIFSSMBSetFileSize(xid, pTcon, | ||
| 988 | attrs->ia_size, nfid, npid, | ||
| 989 | FALSE); | ||
| 990 | cFYI(1, ("SetFileSize by handle " | ||
| 991 | "(setattrs) rc = %d", rc)); | ||
| 992 | /* Do not need reopen and retry on | ||
| 993 | EAGAIN since we will retry by | ||
| 994 | pathname below */ | ||
| 995 | |||
| 996 | /* now that we found one valid file | ||
| 997 | handle no sense continuing to loop | ||
| 998 | trying others, so break here */ | ||
| 999 | break; | ||
| 1000 | } | ||
| 1001 | } | 1018 | } |
| 1002 | } | 1019 | } |
| 1003 | if (found == FALSE) | ||
| 1004 | read_unlock(&GlobalSMBSeslock); | ||
| 1005 | |||
| 1006 | if (rc != 0) { | 1020 | if (rc != 0) { |
| 1007 | /* Set file size by pathname rather than by handle | 1021 | /* Set file size by pathname rather than by handle |
| 1008 | either because no valid, writeable file handle for | 1022 | either because no valid, writeable file handle for |
| @@ -1013,7 +1027,30 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1013 | cifs_sb->local_nls, | 1027 | cifs_sb->local_nls, |
| 1014 | cifs_sb->mnt_cifs_flags & | 1028 | cifs_sb->mnt_cifs_flags & |
| 1015 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1029 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 1016 | cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc)); | 1030 | cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc)); |
| 1031 | if(rc == -EINVAL) { | ||
| 1032 | __u16 netfid; | ||
| 1033 | int oplock = FALSE; | ||
| 1034 | |||
| 1035 | rc = SMBLegacyOpen(xid, pTcon, full_path, | ||
| 1036 | FILE_OPEN, | ||
| 1037 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||
| 1038 | CREATE_NOT_DIR, &netfid, &oplock, | ||
| 1039 | NULL, cifs_sb->local_nls, | ||
| 1040 | cifs_sb->mnt_cifs_flags & | ||
| 1041 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1042 | if (rc==0) { | ||
| 1043 | int bytes_written; | ||
| 1044 | rc = CIFSSMBWrite(xid, pTcon, | ||
| 1045 | netfid, 0, | ||
| 1046 | attrs->ia_size, | ||
| 1047 | &bytes_written, NULL, | ||
| 1048 | NULL, 1 /* 45 sec */); | ||
| 1049 | cFYI(1,("wrt seteof rc %d",rc)); | ||
| 1050 | CIFSSMBClose(xid, pTcon, netfid); | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | } | ||
| 1017 | } | 1054 | } |
| 1018 | 1055 | ||
| 1019 | /* Server is ok setting allocation size implicitly - no need | 1056 | /* Server is ok setting allocation size implicitly - no need |
| @@ -1026,24 +1063,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1026 | rc = vmtruncate(direntry->d_inode, attrs->ia_size); | 1063 | rc = vmtruncate(direntry->d_inode, attrs->ia_size); |
| 1027 | cifs_truncate_page(direntry->d_inode->i_mapping, | 1064 | cifs_truncate_page(direntry->d_inode->i_mapping, |
| 1028 | direntry->d_inode->i_size); | 1065 | direntry->d_inode->i_size); |
| 1029 | } | 1066 | } else |
| 1067 | goto cifs_setattr_exit; | ||
| 1030 | } | 1068 | } |
| 1031 | if (attrs->ia_valid & ATTR_UID) { | 1069 | if (attrs->ia_valid & ATTR_UID) { |
| 1032 | cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid)); | 1070 | cFYI(1, ("UID changed to %d", attrs->ia_uid)); |
| 1033 | uid = attrs->ia_uid; | 1071 | uid = attrs->ia_uid; |
| 1034 | /* entry->uid = cpu_to_le16(attr->ia_uid); */ | ||
| 1035 | } | 1072 | } |
| 1036 | if (attrs->ia_valid & ATTR_GID) { | 1073 | if (attrs->ia_valid & ATTR_GID) { |
| 1037 | cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid)); | 1074 | cFYI(1, ("GID changed to %d", attrs->ia_gid)); |
| 1038 | gid = attrs->ia_gid; | 1075 | gid = attrs->ia_gid; |
| 1039 | /* entry->gid = cpu_to_le16(attr->ia_gid); */ | ||
| 1040 | } | 1076 | } |
| 1041 | 1077 | ||
| 1042 | time_buf.Attributes = 0; | 1078 | time_buf.Attributes = 0; |
| 1043 | if (attrs->ia_valid & ATTR_MODE) { | 1079 | if (attrs->ia_valid & ATTR_MODE) { |
| 1044 | cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode)); | 1080 | cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode)); |
| 1045 | mode = attrs->ia_mode; | 1081 | mode = attrs->ia_mode; |
| 1046 | /* entry->mode = cpu_to_le16(attr->ia_mode); */ | ||
| 1047 | } | 1082 | } |
| 1048 | 1083 | ||
| 1049 | if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) | 1084 | if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) |
| @@ -1083,18 +1118,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1083 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | 1118 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); |
| 1084 | } else | 1119 | } else |
| 1085 | time_buf.LastWriteTime = 0; | 1120 | time_buf.LastWriteTime = 0; |
| 1086 | 1121 | /* Do not set ctime explicitly unless other time | |
| 1087 | if (attrs->ia_valid & ATTR_CTIME) { | 1122 | stamps are changed explicitly (i.e. by utime() |
| 1123 | since we would then have a mix of client and | ||
| 1124 | server times */ | ||
| 1125 | |||
| 1126 | if (set_time && (attrs->ia_valid & ATTR_CTIME)) { | ||
| 1088 | set_time = TRUE; | 1127 | set_time = TRUE; |
| 1089 | cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */ | 1128 | /* Although Samba throws this field away |
| 1129 | it may be useful to Windows - but we do | ||
| 1130 | not want to set ctime unless some other | ||
| 1131 | timestamp is changing */ | ||
| 1132 | cFYI(1, ("CIFS - CTIME changed ")); | ||
| 1090 | time_buf.ChangeTime = | 1133 | time_buf.ChangeTime = |
| 1091 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | 1134 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); |
| 1092 | } else | 1135 | } else |
| 1093 | time_buf.ChangeTime = 0; | 1136 | time_buf.ChangeTime = 0; |
| 1094 | 1137 | ||
| 1095 | if (set_time || time_buf.Attributes) { | 1138 | if (set_time || time_buf.Attributes) { |
| 1096 | /* BB what if setting one attribute fails (such as size) but | ||
| 1097 | time setting works? */ | ||
| 1098 | time_buf.CreationTime = 0; /* do not change */ | 1139 | time_buf.CreationTime = 0; /* do not change */ |
| 1099 | /* In the future we should experiment - try setting timestamps | 1140 | /* In the future we should experiment - try setting timestamps |
| 1100 | via Handle (SetFileInfo) instead of by path */ | 1141 | via Handle (SetFileInfo) instead of by path */ |
| @@ -1133,12 +1174,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1133 | &time_buf, cifs_sb->local_nls); */ | 1174 | &time_buf, cifs_sb->local_nls); */ |
| 1134 | } | 1175 | } |
| 1135 | } | 1176 | } |
| 1177 | /* Even if error on time set, no sense failing the call if | ||
| 1178 | the server would set the time to a reasonable value anyway, | ||
| 1179 | and this check ensures that we are not being called from | ||
| 1180 | sys_utimes in which case we ought to fail the call back to | ||
| 1181 | the user when the server rejects the call */ | ||
| 1182 | if((rc) && (attrs->ia_valid && | ||
| 1183 | (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) | ||
| 1184 | rc = 0; | ||
| 1136 | } | 1185 | } |
| 1137 | 1186 | ||
| 1138 | /* do not need local check to inode_check_ok since the server does | 1187 | /* do not need local check to inode_check_ok since the server does |
| 1139 | that */ | 1188 | that */ |
| 1140 | if (!rc) | 1189 | if (!rc) |
| 1141 | rc = inode_setattr(direntry->d_inode, attrs); | 1190 | rc = inode_setattr(direntry->d_inode, attrs); |
| 1191 | cifs_setattr_exit: | ||
| 1142 | kfree(full_path); | 1192 | kfree(full_path); |
| 1143 | FreeXid(xid); | 1193 | FreeXid(xid); |
| 1144 | return rc; | 1194 | return rc; |
