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