Commit bfa0d75a authored by Steve French's avatar Steve French

[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: default avatarSteve French <sfrench@us.ibm.com>
parent 1c955187
...@@ -226,9 +226,6 @@ extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, ...@@ -226,9 +226,6 @@ extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
const int smb_file_id); const int smb_file_id);
extern int SMBLegacyRead(const int xid, struct cifsTconInfo *tcon,
const int netfid, unsigned int count,
const __u64 lseek, unsigned int *nbytes, char **buf);
extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
const int netfid, unsigned int count, const int netfid, unsigned int count,
const __u64 lseek, unsigned int *nbytes, char **buf); const __u64 lseek, unsigned int *nbytes, char **buf);
......
...@@ -923,81 +923,6 @@ openRetry: ...@@ -923,81 +923,6 @@ openRetry:
return rc; return rc;
} }
int
SMBLegacyRead(const int xid, struct cifsTconInfo *tcon,
const int netfid, unsigned int count,
const __u64 lseek, unsigned int *nbytes, char **buf)
{
int rc = -EACCES;
READX_REQ *pSMB = NULL;
READ_RSP *pSMBr = NULL;
char *pReadData = NULL;
int bytes_returned;
cFYI(1,("Legacy read %d bytes fid %d",count,netfid));
/* field is shorter in legacy read, only 16 bits */
if(count > 2048)
count = 2048; /* BB FIXME make this configurable */
if(lseek > 0xFFFFFFFF)
return -EIO; /* can not read that far into file on old server */
*nbytes = 0;
rc = smb_init(SMB_COM_READ_ANDX, 10, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
return rc;
/* tcon and ses pointer are checked in smb_init */
if (tcon->ses->server == NULL)
return -ECONNABORTED;
pSMB->AndXCommand = 0xFF; /* none */
pSMB->Fid = netfid;
pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
pSMB->Remaining = 0;
pSMB->MaxCount = cpu_to_le16(count);
pSMB->Reserved = 0; /* Must Be Zero */
pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->num_reads);
if (rc) {
cERROR(1, ("Send error in legacy read = %d", rc));
} else {
int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
data_length = data_length << 16;
data_length += le16_to_cpu(pSMBr->DataLength);
*nbytes = data_length;
/*check that DataLength would not go beyond end of SMB */
if ((data_length > CIFSMaxBufSize) || (data_length > count)) {
cFYI(1,("bad length %d for count %d",data_length,count));
rc = -EIO;
*nbytes = 0;
} else {
pReadData = (char *) (&pSMBr->hdr.Protocol) +
le16_to_cpu(pSMBr->DataOffset);
/* if(rc = copy_to_user(buf, pReadData, data_length)) {
cERROR(1,("Faulting on read rc = %d",rc));
rc = -EFAULT;
}*/ /* can not use copy_to_user when using page cache*/
if(*buf)
memcpy(*buf,pReadData,data_length);
}
}
if(*buf)
cifs_buf_release(pSMB);
else
*buf = (char *)pSMB;
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
return rc;
}
/* If no buffer passed in, then caller wants to do the copy /* If no buffer passed in, then caller wants to do the copy
as in the case of readpages so the SMB buffer must be as in the case of readpages so the SMB buffer must be
freed by the caller */ freed by the caller */
...@@ -1012,11 +937,16 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, ...@@ -1012,11 +937,16 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
READ_RSP *pSMBr = NULL; READ_RSP *pSMBr = NULL;
char *pReadData = NULL; char *pReadData = NULL;
int bytes_returned; int bytes_returned;
int wct;
cFYI(1,("Reading %d bytes on fid %d",count,netfid)); cFYI(1,("Reading %d bytes on fid %d",count,netfid));
if(tcon->ses->capabilities & CAP_LARGE_FILES)
wct = 12;
else
wct = 10; /* old style read */
*nbytes = 0; *nbytes = 0;
rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB, rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB,
(void **) &pSMBr); (void **) &pSMBr);
if (rc) if (rc)
return rc; return rc;
...@@ -1028,11 +958,22 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, ...@@ -1028,11 +958,22 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
pSMB->AndXCommand = 0xFF; /* none */ pSMB->AndXCommand = 0xFF; /* none */
pSMB->Fid = netfid; pSMB->Fid = netfid;
pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
if(wct == 12)
pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
else if((lseek >> 32) > 0) /* can not handle this big offset for old */
return -EIO;
pSMB->Remaining = 0; pSMB->Remaining = 0;
pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
pSMB->MaxCountHigh = cpu_to_le32(count >> 16); pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ if(wct == 12)
pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
else {
/* old style read */
struct smb_com_readx_req * pSMBW =
(struct smb_com_readx_req *)pSMB;
pSMBW->ByteCount = 0;
}
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0); (struct smb_hdr *) pSMBr, &bytes_returned, 0);
......
...@@ -1183,16 +1183,11 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, ...@@ -1183,16 +1183,11 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
char *smb_read_data; char *smb_read_data;
char __user *current_offset; char __user *current_offset;
struct smb_com_read_rsp *pSMBr; struct smb_com_read_rsp *pSMBr;
int use_old_read = FALSE;
xid = GetXid(); xid = GetXid();
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
if(pTcon->ses)
if((pTcon->ses->capabilities & CAP_LARGE_FILES) == 0)
use_old_read = TRUE;
if (file->private_data == NULL) { if (file->private_data == NULL) {
FreeXid(xid); FreeXid(xid);
return -EBADF; return -EBADF;
...@@ -1217,22 +1212,10 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, ...@@ -1217,22 +1212,10 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
if (rc != 0) if (rc != 0)
break; break;
} }
if(use_old_read)
rc = SMBLegacyRead(xid, pTcon,
open_file->netfid,
current_read_size, *poffset,
&bytes_read, &smb_read_data);
else {
rc = CIFSSMBRead(xid, pTcon, rc = CIFSSMBRead(xid, pTcon,
open_file->netfid, open_file->netfid,
current_read_size, *poffset, current_read_size, *poffset,
&bytes_read, &smb_read_data); &bytes_read, &smb_read_data);
if(rc == -EINVAL) {
use_old_read = TRUE;
rc = -EAGAIN;
continue;
}
}
pSMBr = (struct smb_com_read_rsp *)smb_read_data; pSMBr = (struct smb_com_read_rsp *)smb_read_data;
if (copy_to_user(current_offset, if (copy_to_user(current_offset,
smb_read_data + 4 /* RFC1001 hdr */ 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,7 +1259,6 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
int xid; int xid;
char *current_offset; char *current_offset;
struct cifsFileInfo *open_file; struct cifsFileInfo *open_file;
int use_old_read = FALSE;
xid = GetXid(); xid = GetXid();
cifs_sb = CIFS_SB(file->f_dentry->d_sb); 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,9 +1269,6 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
return -EBADF; return -EBADF;
} }
open_file = (struct cifsFileInfo *)file->private_data; open_file = (struct cifsFileInfo *)file->private_data;
if(pTcon->ses)
if((pTcon->ses->capabilities & CAP_LARGE_FILES) == 0)
use_old_read = TRUE;
if ((file->f_flags & O_ACCMODE) == O_WRONLY) if ((file->f_flags & O_ACCMODE) == O_WRONLY)
cFYI(1, ("attempting read on write only file instance")); 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,24 +1287,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
if (rc != 0) if (rc != 0)
break; break;
} }
if(use_old_read)
rc = SMBLegacyRead(xid, pTcon,
open_file->netfid,
current_read_size, *poffset,
&bytes_read, &current_offset);
else {
rc = CIFSSMBRead(xid, pTcon, rc = CIFSSMBRead(xid, pTcon,
open_file->netfid, open_file->netfid,
current_read_size, *poffset, current_read_size, *poffset,
&bytes_read, &current_offset); &bytes_read, &current_offset);
/* check if server disavows support for
64 bit offsets */
if(rc == -EINVAL) {
rc = -EAGAIN;
use_old_read = TRUE;
continue;
}
}
} }
if (rc || (bytes_read == 0)) { if (rc || (bytes_read == 0)) {
if (total_read) { if (total_read) {
...@@ -1423,7 +1388,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1423,7 +1388,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
struct smb_com_read_rsp *pSMBr; struct smb_com_read_rsp *pSMBr;
struct pagevec lru_pvec; struct pagevec lru_pvec;
struct cifsFileInfo *open_file; struct cifsFileInfo *open_file;
int use_old_read = FALSE;
xid = GetXid(); xid = GetXid();
if (file->private_data == NULL) { if (file->private_data == NULL) {
...@@ -1433,9 +1397,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1433,9 +1397,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
open_file = (struct cifsFileInfo *)file->private_data; open_file = (struct cifsFileInfo *)file->private_data;
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
if(pTcon->ses)
if((pTcon->ses->capabilities & CAP_LARGE_FILES) == 0)
use_old_read = TRUE;
pagevec_init(&lru_pvec, 0); pagevec_init(&lru_pvec, 0);
for (i = 0; i < num_pages; ) { for (i = 0; i < num_pages; ) {
...@@ -1481,22 +1443,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1481,22 +1443,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
break; break;
} }
if(use_old_read)
rc = SMBLegacyRead(xid, pTcon,
open_file->netfid,
read_size, offset,
&bytes_read, &smb_read_data);
else {
rc = CIFSSMBRead(xid, pTcon, rc = CIFSSMBRead(xid, pTcon,
open_file->netfid, open_file->netfid,
read_size, offset, read_size, offset,
&bytes_read, &smb_read_data); &bytes_read, &smb_read_data);
if(rc == -EINVAL) {
use_old_read = TRUE;
rc = -EAGAIN;
continue;
}
}
/* BB more RC checks ? */ /* BB more RC checks ? */
if (rc== -EAGAIN) { if (rc== -EAGAIN) {
......
...@@ -169,6 +169,10 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -169,6 +169,10 @@ int cifs_get_inode_info_unix(struct inode **pinode,
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
inode->i_fop->lock = NULL; inode->i_fop->lock = NULL;
inode->i_data.a_ops = &cifs_addr_ops; inode->i_data.a_ops = &cifs_addr_ops;
/* check if server can support readpages */
if(pTcon->ses->server->maxBuf <
4096 + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops->readpages = NULL;
} else if (S_ISDIR(inode->i_mode)) { } else if (S_ISDIR(inode->i_mode)) {
cFYI(1, (" Directory inode")); cFYI(1, (" Directory inode"));
inode->i_op = &cifs_dir_inode_ops; inode->i_op = &cifs_dir_inode_ops;
...@@ -384,6 +388,9 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -384,6 +388,9 @@ int cifs_get_inode_info(struct inode **pinode,
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
inode->i_fop->lock = NULL; inode->i_fop->lock = NULL;
inode->i_data.a_ops = &cifs_addr_ops; inode->i_data.a_ops = &cifs_addr_ops;
if(pTcon->ses->server->maxBuf <
4096 + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops->readpages = NULL;
} else if (S_ISDIR(inode->i_mode)) { } else if (S_ISDIR(inode->i_mode)) {
cFYI(1, (" Directory inode ")); cFYI(1, (" Directory inode "));
inode->i_op = &cifs_dir_inode_ops; inode->i_op = &cifs_dir_inode_ops;
......
...@@ -200,7 +200,10 @@ static void fill_in_inode(struct inode *tmp_inode, ...@@ -200,7 +200,10 @@ static void fill_in_inode(struct inode *tmp_inode,
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop->lock = NULL; tmp_inode->i_fop->lock = NULL;
tmp_inode->i_data.a_ops = &cifs_addr_ops; tmp_inode->i_data.a_ops = &cifs_addr_ops;
if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
(cifs_sb->tcon->ses->server->maxBuf <
4096 + MAX_CIFS_HDR_SIZE))
tmp_inode->i_data.a_ops->readpages = NULL;
if(isNewInode) if(isNewInode)
return; /* No sense invalidating pages for new inode return; /* No sense invalidating pages for new inode
since have not started caching readahead file since have not started caching readahead file
...@@ -306,6 +309,10 @@ static void unix_fill_in_inode(struct inode *tmp_inode, ...@@ -306,6 +309,10 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop->lock = NULL; tmp_inode->i_fop->lock = NULL;
tmp_inode->i_data.a_ops = &cifs_addr_ops; tmp_inode->i_data.a_ops = &cifs_addr_ops;
if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
(cifs_sb->tcon->ses->server->maxBuf <
4096 + MAX_CIFS_HDR_SIZE))
tmp_inode->i_data.a_ops->readpages = NULL;
if(isNewInode) if(isNewInode)
return; /* No sense invalidating pages for new inode since we return; /* No sense invalidating pages for new inode since we
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment