Browse Source

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

Steve French 20 years ago
parent
commit
bfa0d75a1e
5 changed files with 39 additions and 137 deletions
  1. 0 3
      fs/cifs/cifsproto.h
  2. 20 79
      fs/cifs/cifssmb.c
  3. 4 54
      fs/cifs/file.c
  4. 7 0
      fs/cifs/inode.c
  5. 8 1
      fs/cifs/readdir.c

+ 0 - 3
fs/cifs/cifsproto.h

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

+ 20 - 79
fs/cifs/cifssmb.c

@@ -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,
 	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,12 +958,23 @@ 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);
-	pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
+	if(wct == 12)
+		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);
 	cifs_stats_inc(&tcon->num_reads);
 	cifs_stats_inc(&tcon->num_reads);

+ 4 - 54
fs/cifs/file.c

@@ -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,
 				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,
 	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,
 		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,
 				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,
 	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,
 	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,
 					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) {

+ 7 - 0
fs/cifs/inode.c

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

+ 8 - 1
fs/cifs/readdir.c

@@ -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,
 		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