diff options
-rw-r--r-- | fs/cifs/CHANGES | 2 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 2 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 15 | ||||
-rw-r--r-- | fs/cifs/inode.c | 78 |
4 files changed, 66 insertions, 31 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 8b55e56cf1fe..47ae68b51847 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -2,6 +2,8 @@ Version 1.37 | |||
2 | ------------ | 2 | ------------ |
3 | Fix readdir caching when unlink removes file in current search buffer, | 3 | Fix readdir caching when unlink removes file in current search buffer, |
4 | and this is followed by a rewind search to just before the deleted entry. | 4 | and this is followed by a rewind search to just before the deleted entry. |
5 | Do not attempt to set ctime unless atime and/or mtime change requested | ||
6 | (most servers throw it away anyway). | ||
5 | 7 | ||
6 | Version 1.36 | 8 | Version 1.36 |
7 | ------------ | 9 | ------------ |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 43fb2aafa528..f738c8b19e3b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -256,7 +256,7 @@ cifs_alloc_inode(struct super_block *sb) | |||
256 | cifs_inode->clientCanCacheAll = FALSE; | 256 | cifs_inode->clientCanCacheAll = FALSE; |
257 | cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; | 257 | cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; |
258 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ | 258 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
259 | 259 | cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME; | |
260 | INIT_LIST_HEAD(&cifs_inode->openFileList); | 260 | INIT_LIST_HEAD(&cifs_inode->openFileList); |
261 | return &cifs_inode->vfs_inode; | 261 | return &cifs_inode->vfs_inode; |
262 | } | 262 | } |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 575b2281518d..f72a61df3c68 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -1072,7 +1072,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
1072 | if (bytes_sent > count) | 1072 | if (bytes_sent > count) |
1073 | bytes_sent = count; | 1073 | bytes_sent = count; |
1074 | pSMB->DataOffset = | 1074 | pSMB->DataOffset = |
1075 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); | 1075 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); |
1076 | if(buf) | 1076 | if(buf) |
1077 | memcpy(pSMB->Data,buf,bytes_sent); | 1077 | memcpy(pSMB->Data,buf,bytes_sent); |
1078 | else if(ubuf) { | 1078 | else if(ubuf) { |
@@ -1080,20 +1080,23 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
1080 | cifs_buf_release(pSMB); | 1080 | cifs_buf_release(pSMB); |
1081 | return -EFAULT; | 1081 | return -EFAULT; |
1082 | } | 1082 | } |
1083 | } else { | 1083 | } else if (count != 0) { |
1084 | /* No buffer */ | 1084 | /* No buffer */ |
1085 | cifs_buf_release(pSMB); | 1085 | cifs_buf_release(pSMB); |
1086 | return -EINVAL; | 1086 | return -EINVAL; |
1087 | } /* else setting file size with write of zero bytes */ | ||
1088 | if(wct == 14) | ||
1089 | byte_count = bytes_sent + 1; /* pad */ | ||
1090 | else /* wct == 12 */ { | ||
1091 | byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */ | ||
1087 | } | 1092 | } |
1088 | |||
1089 | byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */ | ||
1090 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); | 1093 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); |
1091 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); | 1094 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); |
1092 | pSMB->hdr.smb_buf_length += bytes_sent+1; | 1095 | pSMB->hdr.smb_buf_length += byte_count; |
1093 | 1096 | ||
1094 | if(wct == 14) | 1097 | if(wct == 14) |
1095 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1098 | pSMB->ByteCount = cpu_to_le16(byte_count); |
1096 | else { /* old style write has byte count 4 bytes earlier */ | 1099 | else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */ |
1097 | struct smb_com_writex_req * pSMBW = | 1100 | struct smb_com_writex_req * pSMBW = |
1098 | (struct smb_com_writex_req *)pSMB; | 1101 | (struct smb_com_writex_req *)pSMB; |
1099 | pSMBW->ByteCount = cpu_to_le16(byte_count); | 1102 | pSMBW->ByteCount = cpu_to_le16(byte_count); |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 6e82e1ae03b4..ca3af4eafcb2 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -1030,14 +1030,15 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1030 | /* now that we found one valid file | 1030 | /* now that we found one valid file |
1031 | handle no sense continuing to loop | 1031 | handle no sense continuing to loop |
1032 | trying others, so break here */ | 1032 | trying others, so break here */ |
1033 | /* if(rc == -EINVAL) { | 1033 | if(rc == -EINVAL) { |
1034 | int bytes_written; | 1034 | int bytes_written; |
1035 | rc = CIFSSMBWrite(xid, pTcon, | 1035 | rc = CIFSSMBWrite(xid, pTcon, |
1036 | nfid, 0, | 1036 | nfid, 0, |
1037 | attrs->ia_size, | 1037 | attrs->ia_size, |
1038 | &bytes_written, | 1038 | &bytes_written, NULL, |
1039 | NULL, NULL, long_op); | 1039 | NULL, 1 /* 45 sec */); |
1040 | } */ | 1040 | cFYI(1,("wrt seteof rc %d",rc)); |
1041 | } | ||
1041 | break; | 1042 | break; |
1042 | } | 1043 | } |
1043 | } | 1044 | } |
@@ -1055,14 +1056,30 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1055 | cifs_sb->local_nls, | 1056 | cifs_sb->local_nls, |
1056 | cifs_sb->mnt_cifs_flags & | 1057 | cifs_sb->mnt_cifs_flags & |
1057 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1058 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
1058 | cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc)); | 1059 | cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc)); |
1059 | /* if(rc == -EINVAL) | 1060 | if(rc == -EINVAL) { |
1060 | old_style_set_eof_via_write(xid, pTcon, | 1061 | __u16 netfid; |
1061 | full_path, | 1062 | int oplock = FALSE; |
1062 | attrs->ia_size, | 1063 | |
1063 | cifs_sb->local_nls, | 1064 | rc = SMBLegacyOpen(xid, pTcon, full_path, |
1064 | cifs_sb->mnt_cifs_flags & | 1065 | FILE_OPEN, |
1065 | CIFS_MOUNT_MAP_SPECIAL_CHR);*/ | 1066 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, |
1067 | CREATE_NOT_DIR, &netfid, &oplock, | ||
1068 | NULL, cifs_sb->local_nls, | ||
1069 | cifs_sb->mnt_cifs_flags & | ||
1070 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1071 | if (rc==0) { | ||
1072 | int bytes_written; | ||
1073 | rc = CIFSSMBWrite(xid, pTcon, | ||
1074 | netfid, 0, | ||
1075 | attrs->ia_size, | ||
1076 | &bytes_written, NULL, | ||
1077 | NULL, 1 /* 45 sec */); | ||
1078 | cFYI(1,("wrt seteof rc %d",rc)); | ||
1079 | CIFSSMBClose(xid, pTcon, netfid); | ||
1080 | } | ||
1081 | |||
1082 | } | ||
1066 | } | 1083 | } |
1067 | 1084 | ||
1068 | /* Server is ok setting allocation size implicitly - no need | 1085 | /* Server is ok setting allocation size implicitly - no need |
@@ -1075,24 +1092,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1075 | rc = vmtruncate(direntry->d_inode, attrs->ia_size); | 1092 | rc = vmtruncate(direntry->d_inode, attrs->ia_size); |
1076 | cifs_truncate_page(direntry->d_inode->i_mapping, | 1093 | cifs_truncate_page(direntry->d_inode->i_mapping, |
1077 | direntry->d_inode->i_size); | 1094 | direntry->d_inode->i_size); |
1078 | } | 1095 | } else |
1096 | goto cifs_setattr_exit; | ||
1079 | } | 1097 | } |
1080 | if (attrs->ia_valid & ATTR_UID) { | 1098 | if (attrs->ia_valid & ATTR_UID) { |
1081 | cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid)); | 1099 | cFYI(1, ("UID changed to %d", attrs->ia_uid)); |
1082 | uid = attrs->ia_uid; | 1100 | uid = attrs->ia_uid; |
1083 | /* entry->uid = cpu_to_le16(attr->ia_uid); */ | ||
1084 | } | 1101 | } |
1085 | if (attrs->ia_valid & ATTR_GID) { | 1102 | if (attrs->ia_valid & ATTR_GID) { |
1086 | cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid)); | 1103 | cFYI(1, ("GID changed to %d", attrs->ia_gid)); |
1087 | gid = attrs->ia_gid; | 1104 | gid = attrs->ia_gid; |
1088 | /* entry->gid = cpu_to_le16(attr->ia_gid); */ | ||
1089 | } | 1105 | } |
1090 | 1106 | ||
1091 | time_buf.Attributes = 0; | 1107 | time_buf.Attributes = 0; |
1092 | if (attrs->ia_valid & ATTR_MODE) { | 1108 | if (attrs->ia_valid & ATTR_MODE) { |
1093 | cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode)); | 1109 | cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode)); |
1094 | mode = attrs->ia_mode; | 1110 | mode = attrs->ia_mode; |
1095 | /* entry->mode = cpu_to_le16(attr->ia_mode); */ | ||
1096 | } | 1111 | } |
1097 | 1112 | ||
1098 | if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) | 1113 | if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) |
@@ -1132,18 +1147,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1132 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | 1147 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); |
1133 | } else | 1148 | } else |
1134 | time_buf.LastWriteTime = 0; | 1149 | time_buf.LastWriteTime = 0; |
1135 | 1150 | /* Do not set ctime explicitly unless other time | |
1136 | if (attrs->ia_valid & ATTR_CTIME) { | 1151 | stamps are changed explicitly (i.e. by utime() |
1152 | since we would then have a mix of client and | ||
1153 | server times */ | ||
1154 | |||
1155 | if (set_time && (attrs->ia_valid & ATTR_CTIME)) { | ||
1137 | set_time = TRUE; | 1156 | set_time = TRUE; |
1138 | cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */ | 1157 | /* Although Samba throws this field away |
1158 | it may be useful to Windows - but we do | ||
1159 | not want to set ctime unless some other | ||
1160 | timestamp is changing */ | ||
1161 | cFYI(1, ("CIFS - CTIME changed ")); | ||
1139 | time_buf.ChangeTime = | 1162 | time_buf.ChangeTime = |
1140 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | 1163 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); |
1141 | } else | 1164 | } else |
1142 | time_buf.ChangeTime = 0; | 1165 | time_buf.ChangeTime = 0; |
1143 | 1166 | ||
1144 | if (set_time || time_buf.Attributes) { | 1167 | if (set_time || time_buf.Attributes) { |
1145 | /* BB what if setting one attribute fails (such as size) but | ||
1146 | time setting works? */ | ||
1147 | time_buf.CreationTime = 0; /* do not change */ | 1168 | time_buf.CreationTime = 0; /* do not change */ |
1148 | /* In the future we should experiment - try setting timestamps | 1169 | /* In the future we should experiment - try setting timestamps |
1149 | via Handle (SetFileInfo) instead of by path */ | 1170 | via Handle (SetFileInfo) instead of by path */ |
@@ -1182,12 +1203,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1182 | &time_buf, cifs_sb->local_nls); */ | 1203 | &time_buf, cifs_sb->local_nls); */ |
1183 | } | 1204 | } |
1184 | } | 1205 | } |
1206 | /* Even if error on time set, no sense failing the call if | ||
1207 | the server would set the time to a reasonable value anyway, | ||
1208 | and this check ensures that we are not being called from | ||
1209 | sys_utimes in which case we ought to fail the call back to | ||
1210 | the user when the server rejects the call */ | ||
1211 | if((rc) && (attrs->ia_valid && | ||
1212 | (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) | ||
1213 | rc = 0; | ||
1185 | } | 1214 | } |
1186 | 1215 | ||
1187 | /* do not need local check to inode_check_ok since the server does | 1216 | /* do not need local check to inode_check_ok since the server does |
1188 | that */ | 1217 | that */ |
1189 | if (!rc) | 1218 | if (!rc) |
1190 | rc = inode_setattr(direntry->d_inode, attrs); | 1219 | rc = inode_setattr(direntry->d_inode, attrs); |
1220 | cifs_setattr_exit: | ||
1191 | kfree(full_path); | 1221 | kfree(full_path); |
1192 | FreeXid(xid); | 1222 | FreeXid(xid); |
1193 | return rc; | 1223 | return rc; |