Commit 20962438 authored by Steve French's avatar Steve French
Browse files

[CIFS] Add support for legacy servers part nine. statfs (df and du) is now


functional, and the length check is fixed so readdir does not throw a
warning message when windows me messes up the response to FindFirst
of an empty dir (with only . and ..).

Signed-off-by: default avatarSteve French <(sfrench@us.ibm.com)>
parent e30dcf3a
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -3,7 +3,8 @@ Version 1.37
Fix readdir caching when unlink removes file in current search buffer,
and this is followed by a rewind search to just before the deleted entry.
Do not attempt to set ctime unless atime and/or mtime change requested
(most servers throw it away anyway).
(most servers throw it away anyway). Fix length check of received smbs
to be more accurate.

Version 1.36
------------
+4 −0
Original line number Diff line number Diff line
@@ -205,6 +205,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf)
#endif /* CIFS_EXPERIMENTAL */
	rc = CIFSSMBQFSInfo(xid, pTcon, buf);

	/* Old Windows servers do not support level 103, retry with level 
	   one if old server failed the previous call */ 
	if(rc)
		rc = SMBOldQFSInfo(xid, pTcon, buf);
	/*     
	   int f_type;
	   __fsid_t f_fsid;
+8 −0
Original line number Diff line number Diff line
@@ -1683,6 +1683,14 @@ typedef struct {
	__le32 BytesPerSector;
} FILE_SYSTEM_INFO;		/* size info, level 0x103 */

typedef struct {
	__le32 fsid;
	__le32 SectorsPerAllocationUnit;
	__le32 TotalAllocationUnits;
	__le32 FreeAllocationUnits;
	__le16  BytesPerSector;
} FILE_SYSTEM_ALLOC_INFO;

typedef struct {
	__le16 MajorVersionNumber;
	__le16 MinorVersionNumber;
+2 −0
Original line number Diff line number Diff line
@@ -133,6 +133,8 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
			int remap);
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
			struct kstatfs *FSData);
extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon,
			struct kstatfs *FSData);
extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
			__u64 cap);

+89 −6
Original line number Diff line number Diff line
@@ -3215,6 +3215,92 @@ GetDFSRefExit:
	return rc;
}

/* Query File System Info such as free space to old servers such as Win 9x */
int
SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
{
/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
	TRANSACTION2_QFSI_REQ *pSMB = NULL;
	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
	FILE_SYSTEM_ALLOC_INFO *response_data;
	int rc = 0;
	int bytes_returned = 0;
	__u16 params, byte_count;

	cFYI(1, ("OldQFSInfo"));
oldQFSInfoRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		(void **) &pSMBr);
	if (rc)
		return rc;
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	params = 2;     /* level */
	pSMB->TotalDataCount = 0;
	pSMB->MaxParameterCount = cpu_to_le16(2);
	pSMB->MaxDataCount = cpu_to_le16(1000);
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	byte_count = params + 1 /* pad */ ;
	pSMB->TotalParameterCount = cpu_to_le16(params);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
	pSMB->ParameterOffset = cpu_to_le16(offsetof(
	struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
	pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
	pSMB->hdr.smb_buf_length += byte_count;
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
		cFYI(1, ("Send error in QFSInfo = %d", rc));
	} else {                /* decode response */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);

		if (rc || (pSMBr->ByteCount < 18))
			rc = -EIO;      /* bad smb */
		else {
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
			cFYI(1,("qfsinf resp BCC: %d  Offset %d",
				 pSMBr->ByteCount, data_offset));

			response_data =
				(FILE_SYSTEM_ALLOC_INFO *) 
				(((char *) &pSMBr->hdr.Protocol) + data_offset);
			FSData->f_bsize =
				le16_to_cpu(response_data->BytesPerSector) *
				le32_to_cpu(response_data->
					SectorsPerAllocationUnit);
			FSData->f_blocks =
				le32_to_cpu(response_data->TotalAllocationUnits);
			FSData->f_bfree = FSData->f_bavail =
				le32_to_cpu(response_data->FreeAllocationUnits);
			cFYI(1,
			     ("Blocks: %lld  Free: %lld Block size %ld",
			      (unsigned long long)FSData->f_blocks,
			      (unsigned long long)FSData->f_bfree,
			      FSData->f_bsize));
		}
	}
	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto oldQFSInfoRetry;

	return rc;
}

int
CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
{
@@ -3236,7 +3322,7 @@ QFSInfoRetry:
	params = 2;	/* level */
	pSMB->TotalDataCount = 0;
	pSMB->MaxParameterCount = cpu_to_le16(2);
	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
	pSMB->MaxDataCount = cpu_to_le16(1000);
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
@@ -3259,17 +3345,14 @@ QFSInfoRetry:
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
		cERROR(1, ("Send error in QFSInfo = %d", rc));
		cFYI(1, ("Send error in QFSInfo = %d", rc));
	} else {		/* decode response */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);

		if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
		if (rc || (pSMBr->ByteCount < 24))
			rc = -EIO;	/* bad smb */
		else {
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
			cFYI(1,
				("Decoding qfsinfo response.  BCC: %d  Offset %d",
				pSMBr->ByteCount, data_offset));

			response_data =
			    (FILE_SYSTEM_INFO
Loading