Skip to content

Commit

Permalink
[CIFS] Add support for legacy servers part nine. statfs (df and du) i…
Browse files Browse the repository at this point in the history
…s 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: Steve French (sfrench@us.ibm.com)
  • Loading branch information
Steve French committed Sep 22, 2005
1 parent e30dcf3 commit 2096243
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 10 deletions.
3 changes: 2 additions & 1 deletion fs/cifs/CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -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
------------
Expand Down
4 changes: 4 additions & 0 deletions fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 8 additions & 0 deletions fs/cifs/cifspdu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
95 changes: 89 additions & 6 deletions fs/cifs/cifssmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -3215,6 +3215,92 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
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)
{
Expand All @@ -3236,7 +3322,7 @@ CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
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;
Expand All @@ -3259,17 +3345,14 @@ CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
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
Expand Down
3 changes: 1 addition & 2 deletions fs/cifs/misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,13 +450,12 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)

if ((4 + len != smbCalcSize(smb))
|| (4 + len != (unsigned int)length)) {
return 0;
} else {
cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb)));
cERROR(1,
("bad smb size detected. The Mid=%d", smb->Mid));
return 1;
}
return 0;
}
int
is_valid_oplock_break(struct smb_hdr *buf)
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/netmisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,7 @@ unsigned int
smbCalcSize(struct smb_hdr *ptr)
{
return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
BCC(ptr));
2 /* size of the bcc field itself */ + BCC(ptr));
}

/* The following are taken from fs/ntfs/util.c */
Expand Down

0 comments on commit 2096243

Please sign in to comment.