diff options
author | Steve French <sfrench@us.ibm.com> | 2005-09-01 00:50:37 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2005-09-01 00:50:37 -0400 |
commit | bfa0d75a1eee59f0577e3c1697ff570b77581a35 (patch) | |
tree | c5399d95379f71903c4f3e82160bd7b4d36bb42d /fs/cifs | |
parent | 1c9551878c4629ca78dfe12ed23b9dc8d97770cc (diff) |
[CIFS] Add support for legacy servers part 5
Handle small negotiated read sizes (under 4K) and finish up
read and write support.
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/cifsproto.h | 3 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 99 | ||||
-rw-r--r-- | fs/cifs/file.c | 58 | ||||
-rw-r--r-- | fs/cifs/inode.c | 7 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 9 |
5 files changed, 39 insertions, 137 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 656b78ddf674..6943f7c6de08 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -226,9 +226,6 @@ extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, | |||
226 | extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, | 226 | extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, |
227 | const int smb_file_id); | 227 | const int smb_file_id); |
228 | 228 | ||
229 | extern int SMBLegacyRead(const int xid, struct cifsTconInfo *tcon, | ||
230 | const int netfid, unsigned int count, | ||
231 | const __u64 lseek, unsigned int *nbytes, char **buf); | ||
232 | extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | 229 | extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, |
233 | const int netfid, unsigned int count, | 230 | const int netfid, unsigned int count, |
234 | const __u64 lseek, unsigned int *nbytes, char **buf); | 231 | const __u64 lseek, unsigned int *nbytes, char **buf); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 74733851cfad..b8830118f09a 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -923,81 +923,6 @@ openRetry: | |||
923 | return rc; | 923 | return rc; |
924 | } | 924 | } |
925 | 925 | ||
926 | int | ||
927 | SMBLegacyRead(const int xid, struct cifsTconInfo *tcon, | ||
928 | const int netfid, unsigned int count, | ||
929 | const __u64 lseek, unsigned int *nbytes, char **buf) | ||
930 | { | ||
931 | int rc = -EACCES; | ||
932 | READX_REQ *pSMB = NULL; | ||
933 | READ_RSP *pSMBr = NULL; | ||
934 | char *pReadData = NULL; | ||
935 | int bytes_returned; | ||
936 | |||
937 | cFYI(1,("Legacy read %d bytes fid %d",count,netfid)); | ||
938 | |||
939 | /* field is shorter in legacy read, only 16 bits */ | ||
940 | if(count > 2048) | ||
941 | count = 2048; /* BB FIXME make this configurable */ | ||
942 | |||
943 | if(lseek > 0xFFFFFFFF) | ||
944 | return -EIO; /* can not read that far into file on old server */ | ||
945 | |||
946 | *nbytes = 0; | ||
947 | rc = smb_init(SMB_COM_READ_ANDX, 10, tcon, (void **) &pSMB, | ||
948 | (void **) &pSMBr); | ||
949 | if (rc) | ||
950 | return rc; | ||
951 | |||
952 | /* tcon and ses pointer are checked in smb_init */ | ||
953 | if (tcon->ses->server == NULL) | ||
954 | return -ECONNABORTED; | ||
955 | |||
956 | pSMB->AndXCommand = 0xFF; /* none */ | ||
957 | pSMB->Fid = netfid; | ||
958 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); | ||
959 | pSMB->Remaining = 0; | ||
960 | pSMB->MaxCount = cpu_to_le16(count); | ||
961 | pSMB->Reserved = 0; /* Must Be Zero */ | ||
962 | pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ | ||
963 | |||
964 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
965 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
966 | cifs_stats_inc(&tcon->num_reads); | ||
967 | if (rc) { | ||
968 | cERROR(1, ("Send error in legacy read = %d", rc)); | ||
969 | } else { | ||
970 | int data_length = le16_to_cpu(pSMBr->DataLengthHigh); | ||
971 | data_length = data_length << 16; | ||
972 | data_length += le16_to_cpu(pSMBr->DataLength); | ||
973 | *nbytes = data_length; | ||
974 | |||
975 | /*check that DataLength would not go beyond end of SMB */ | ||
976 | if ((data_length > CIFSMaxBufSize) || (data_length > count)) { | ||
977 | cFYI(1,("bad length %d for count %d",data_length,count)); | ||
978 | rc = -EIO; | ||
979 | *nbytes = 0; | ||
980 | } else { | ||
981 | pReadData = (char *) (&pSMBr->hdr.Protocol) + | ||
982 | le16_to_cpu(pSMBr->DataOffset); | ||
983 | /* if(rc = copy_to_user(buf, pReadData, data_length)) { | ||
984 | cERROR(1,("Faulting on read rc = %d",rc)); | ||
985 | rc = -EFAULT; | ||
986 | }*/ /* can not use copy_to_user when using page cache*/ | ||
987 | if(*buf) | ||
988 | memcpy(*buf,pReadData,data_length); | ||
989 | } | ||
990 | } | ||
991 | if(*buf) | ||
992 | cifs_buf_release(pSMB); | ||
993 | else | ||
994 | *buf = (char *)pSMB; | ||
995 | |||
996 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
997 | since file handle passed in no longer valid */ | ||
998 | return rc; | ||
999 | } | ||
1000 | |||
1001 | /* If no buffer passed in, then caller wants to do the copy | 926 | /* If no buffer passed in, then caller wants to do the copy |
1002 | as in the case of readpages so the SMB buffer must be | 927 | as in the case of readpages so the SMB buffer must be |
1003 | freed by the caller */ | 928 | freed by the caller */ |
@@ -1012,11 +937,16 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
1012 | READ_RSP *pSMBr = NULL; | 937 | READ_RSP *pSMBr = NULL; |
1013 | char *pReadData = NULL; | 938 | char *pReadData = NULL; |
1014 | int bytes_returned; | 939 | int bytes_returned; |
940 | int wct; | ||
1015 | 941 | ||
1016 | cFYI(1,("Reading %d bytes on fid %d",count,netfid)); | 942 | cFYI(1,("Reading %d bytes on fid %d",count,netfid)); |
943 | if(tcon->ses->capabilities & CAP_LARGE_FILES) | ||
944 | wct = 12; | ||
945 | else | ||
946 | wct = 10; /* old style read */ | ||
1017 | 947 | ||
1018 | *nbytes = 0; | 948 | *nbytes = 0; |
1019 | rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB, | 949 | rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB, |
1020 | (void **) &pSMBr); | 950 | (void **) &pSMBr); |
1021 | if (rc) | 951 | if (rc) |
1022 | return rc; | 952 | return rc; |
@@ -1028,12 +958,23 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
1028 | pSMB->AndXCommand = 0xFF; /* none */ | 958 | pSMB->AndXCommand = 0xFF; /* none */ |
1029 | pSMB->Fid = netfid; | 959 | pSMB->Fid = netfid; |
1030 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); | 960 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); |
1031 | pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); | 961 | if(wct == 12) |
962 | pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); | ||
963 | else if((lseek >> 32) > 0) /* can not handle this big offset for old */ | ||
964 | return -EIO; | ||
965 | |||
1032 | pSMB->Remaining = 0; | 966 | pSMB->Remaining = 0; |
1033 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); | 967 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); |
1034 | pSMB->MaxCountHigh = cpu_to_le32(count >> 16); | 968 | pSMB->MaxCountHigh = cpu_to_le32(count >> 16); |
1035 | pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ | 969 | if(wct == 12) |
1036 | 970 | pSMB->ByteCount = 0; /* no need to do le conversion since 0 */ | |
971 | else { | ||
972 | /* old style read */ | ||
973 | struct smb_com_readx_req * pSMBW = | ||
974 | (struct smb_com_readx_req *)pSMB; | ||
975 | pSMBW->ByteCount = 0; | ||
976 | } | ||
977 | |||
1037 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 978 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1038 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 979 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1039 | cifs_stats_inc(&tcon->num_reads); | 980 | cifs_stats_inc(&tcon->num_reads); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index b6c303f6373f..5ecda554f913 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -1183,16 +1183,11 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1183 | char *smb_read_data; | 1183 | char *smb_read_data; |
1184 | char __user *current_offset; | 1184 | char __user *current_offset; |
1185 | struct smb_com_read_rsp *pSMBr; | 1185 | struct smb_com_read_rsp *pSMBr; |
1186 | int use_old_read = FALSE; | ||
1187 | 1186 | ||
1188 | xid = GetXid(); | 1187 | xid = GetXid(); |
1189 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | 1188 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); |
1190 | pTcon = cifs_sb->tcon; | 1189 | pTcon = cifs_sb->tcon; |
1191 | 1190 | ||
1192 | if(pTcon->ses) | ||
1193 | if((pTcon->ses->capabilities & CAP_LARGE_FILES) == 0) | ||
1194 | use_old_read = TRUE; | ||
1195 | |||
1196 | if (file->private_data == NULL) { | 1191 | if (file->private_data == NULL) { |
1197 | FreeXid(xid); | 1192 | FreeXid(xid); |
1198 | return -EBADF; | 1193 | return -EBADF; |
@@ -1217,22 +1212,10 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1217 | if (rc != 0) | 1212 | if (rc != 0) |
1218 | break; | 1213 | break; |
1219 | } | 1214 | } |
1220 | if(use_old_read) | 1215 | rc = CIFSSMBRead(xid, pTcon, |
1221 | rc = SMBLegacyRead(xid, pTcon, | ||
1222 | open_file->netfid, | ||
1223 | current_read_size, *poffset, | ||
1224 | &bytes_read, &smb_read_data); | ||
1225 | else { | ||
1226 | rc = CIFSSMBRead(xid, pTcon, | ||
1227 | open_file->netfid, | 1216 | open_file->netfid, |
1228 | current_read_size, *poffset, | 1217 | current_read_size, *poffset, |
1229 | &bytes_read, &smb_read_data); | 1218 | &bytes_read, &smb_read_data); |
1230 | if(rc == -EINVAL) { | ||
1231 | use_old_read = TRUE; | ||
1232 | rc = -EAGAIN; | ||
1233 | continue; | ||
1234 | } | ||
1235 | } | ||
1236 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | 1219 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; |
1237 | if (copy_to_user(current_offset, | 1220 | if (copy_to_user(current_offset, |
1238 | smb_read_data + 4 /* RFC1001 hdr */ | 1221 | smb_read_data + 4 /* RFC1001 hdr */ |
@@ -1276,7 +1259,6 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1276 | int xid; | 1259 | int xid; |
1277 | char *current_offset; | 1260 | char *current_offset; |
1278 | struct cifsFileInfo *open_file; | 1261 | struct cifsFileInfo *open_file; |
1279 | int use_old_read = FALSE; | ||
1280 | 1262 | ||
1281 | xid = GetXid(); | 1263 | xid = GetXid(); |
1282 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | 1264 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); |
@@ -1287,9 +1269,6 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1287 | return -EBADF; | 1269 | return -EBADF; |
1288 | } | 1270 | } |
1289 | open_file = (struct cifsFileInfo *)file->private_data; | 1271 | open_file = (struct cifsFileInfo *)file->private_data; |
1290 | if(pTcon->ses) | ||
1291 | if((pTcon->ses->capabilities & CAP_LARGE_FILES) == 0) | ||
1292 | use_old_read = TRUE; | ||
1293 | 1272 | ||
1294 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 1273 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) |
1295 | cFYI(1, ("attempting read on write only file instance")); | 1274 | cFYI(1, ("attempting read on write only file instance")); |
@@ -1308,24 +1287,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1308 | if (rc != 0) | 1287 | if (rc != 0) |
1309 | break; | 1288 | break; |
1310 | } | 1289 | } |
1311 | if(use_old_read) | 1290 | rc = CIFSSMBRead(xid, pTcon, |
1312 | rc = SMBLegacyRead(xid, pTcon, | ||
1313 | open_file->netfid, | ||
1314 | current_read_size, *poffset, | ||
1315 | &bytes_read, ¤t_offset); | ||
1316 | else { | ||
1317 | rc = CIFSSMBRead(xid, pTcon, | ||
1318 | open_file->netfid, | 1291 | open_file->netfid, |
1319 | current_read_size, *poffset, | 1292 | current_read_size, *poffset, |
1320 | &bytes_read, ¤t_offset); | 1293 | &bytes_read, ¤t_offset); |
1321 | /* check if server disavows support for | ||
1322 | 64 bit offsets */ | ||
1323 | if(rc == -EINVAL) { | ||
1324 | rc = -EAGAIN; | ||
1325 | use_old_read = TRUE; | ||
1326 | continue; | ||
1327 | } | ||
1328 | } | ||
1329 | } | 1294 | } |
1330 | if (rc || (bytes_read == 0)) { | 1295 | if (rc || (bytes_read == 0)) { |
1331 | if (total_read) { | 1296 | if (total_read) { |
@@ -1423,7 +1388,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1423 | struct smb_com_read_rsp *pSMBr; | 1388 | struct smb_com_read_rsp *pSMBr; |
1424 | struct pagevec lru_pvec; | 1389 | struct pagevec lru_pvec; |
1425 | struct cifsFileInfo *open_file; | 1390 | struct cifsFileInfo *open_file; |
1426 | int use_old_read = FALSE; | ||
1427 | 1391 | ||
1428 | xid = GetXid(); | 1392 | xid = GetXid(); |
1429 | if (file->private_data == NULL) { | 1393 | if (file->private_data == NULL) { |
@@ -1433,9 +1397,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1433 | open_file = (struct cifsFileInfo *)file->private_data; | 1397 | open_file = (struct cifsFileInfo *)file->private_data; |
1434 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | 1398 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); |
1435 | pTcon = cifs_sb->tcon; | 1399 | pTcon = cifs_sb->tcon; |
1436 | if(pTcon->ses) | 1400 | |
1437 | if((pTcon->ses->capabilities & CAP_LARGE_FILES) == 0) | ||
1438 | use_old_read = TRUE; | ||
1439 | pagevec_init(&lru_pvec, 0); | 1401 | pagevec_init(&lru_pvec, 0); |
1440 | 1402 | ||
1441 | for (i = 0; i < num_pages; ) { | 1403 | for (i = 0; i < num_pages; ) { |
@@ -1481,22 +1443,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1481 | break; | 1443 | break; |
1482 | } | 1444 | } |
1483 | 1445 | ||
1484 | if(use_old_read) | 1446 | rc = CIFSSMBRead(xid, pTcon, |
1485 | rc = SMBLegacyRead(xid, pTcon, | ||
1486 | open_file->netfid, | ||
1487 | read_size, offset, | ||
1488 | &bytes_read, &smb_read_data); | ||
1489 | else { | ||
1490 | rc = CIFSSMBRead(xid, pTcon, | ||
1491 | open_file->netfid, | 1447 | open_file->netfid, |
1492 | read_size, offset, | 1448 | read_size, offset, |
1493 | &bytes_read, &smb_read_data); | 1449 | &bytes_read, &smb_read_data); |
1494 | if(rc == -EINVAL) { | ||
1495 | use_old_read = TRUE; | ||
1496 | rc = -EAGAIN; | ||
1497 | continue; | ||
1498 | } | ||
1499 | } | ||
1500 | 1450 | ||
1501 | /* BB more RC checks ? */ | 1451 | /* BB more RC checks ? */ |
1502 | if (rc== -EAGAIN) { | 1452 | if (rc== -EAGAIN) { |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 0485c6d6ecd5..0fbe02ebc033 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -169,6 +169,10 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
169 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | 169 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) |
170 | inode->i_fop->lock = NULL; | 170 | inode->i_fop->lock = NULL; |
171 | 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; | ||
172 | } else if (S_ISDIR(inode->i_mode)) { | 176 | } else if (S_ISDIR(inode->i_mode)) { |
173 | cFYI(1, (" Directory inode")); | 177 | cFYI(1, (" Directory inode")); |
174 | inode->i_op = &cifs_dir_inode_ops; | 178 | inode->i_op = &cifs_dir_inode_ops; |
@@ -384,6 +388,9 @@ int cifs_get_inode_info(struct inode **pinode, | |||
384 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | 388 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) |
385 | inode->i_fop->lock = NULL; | 389 | inode->i_fop->lock = NULL; |
386 | 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; | ||
387 | } else if (S_ISDIR(inode->i_mode)) { | 394 | } else if (S_ISDIR(inode->i_mode)) { |
388 | cFYI(1, (" Directory inode ")); | 395 | cFYI(1, (" Directory inode ")); |
389 | inode->i_op = &cifs_dir_inode_ops; | 396 | inode->i_op = &cifs_dir_inode_ops; |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 9780f4ee7f12..a1e8dc901de4 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -200,7 +200,10 @@ static void fill_in_inode(struct inode *tmp_inode, | |||
200 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | 200 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) |
201 | tmp_inode->i_fop->lock = NULL; | 201 | tmp_inode->i_fop->lock = NULL; |
202 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | 202 | tmp_inode->i_data.a_ops = &cifs_addr_ops; |
203 | 203 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | |
204 | (cifs_sb->tcon->ses->server->maxBuf < | ||
205 | 4096 + MAX_CIFS_HDR_SIZE)) | ||
206 | tmp_inode->i_data.a_ops->readpages = NULL; | ||
204 | if(isNewInode) | 207 | if(isNewInode) |
205 | return; /* No sense invalidating pages for new inode | 208 | return; /* No sense invalidating pages for new inode |
206 | since have not started caching readahead file | 209 | since have not started caching readahead file |
@@ -306,6 +309,10 @@ static void unix_fill_in_inode(struct inode *tmp_inode, | |||
306 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | 309 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) |
307 | tmp_inode->i_fop->lock = NULL; | 310 | tmp_inode->i_fop->lock = NULL; |
308 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | 311 | tmp_inode->i_data.a_ops = &cifs_addr_ops; |
312 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | ||
313 | (cifs_sb->tcon->ses->server->maxBuf < | ||
314 | 4096 + MAX_CIFS_HDR_SIZE)) | ||
315 | tmp_inode->i_data.a_ops->readpages = NULL; | ||
309 | 316 | ||
310 | if(isNewInode) | 317 | if(isNewInode) |
311 | return; /* No sense invalidating pages for new inode since we | 318 | return; /* No sense invalidating pages for new inode since we |