From f4cfd69cf349dd27e00d5cf804b57aee04e059c2 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 14 Jul 2005 18:29:02 -0500 Subject: [CIFS] Fix path name conversion for long filenames when mapchars mount option was specified at mount time. Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/misc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/cifs/misc.c') diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 072b4ee8c53e..20ae4153f791 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -611,6 +611,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, src_char = source[i]; switch (src_char) { case 0: + target[j] = 0; goto ctoUCS_out; case ':': target[j] = cpu_to_le16(UNI_COLON); -- cgit v1.2.3 From 1982c344f1bf08118f7c224958b30c64e162009e Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 17 Aug 2005 12:38:22 -0700 Subject: [CIFS] Ensure that cifs multiplex ids do not collide. Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/cifsglob.h | 1 + fs/cifs/cifspdu.h | 19 ++++++------ fs/cifs/cifsproto.h | 6 ++-- fs/cifs/cifssmb.c | 23 +++++++++------ fs/cifs/connect.c | 9 ++++++ fs/cifs/misc.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 113 insertions(+), 29 deletions(-) (limited to 'fs/cifs/misc.c') diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d3773e57acf9..e8287f76484f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -147,6 +147,7 @@ struct TCP_Server_Info { /* (returned on Negotiate */ int capabilities; /* allow selective disabling of caps by smb sess */ __u16 timeZone; + __u16 CurrentMid; /* multiplex id - rotating counter */ char cryptKey[CIFS_CRYPTO_KEY_SIZE]; char workstation_RFC1001_name[16]; /* 16th byte is always zero */ __u32 sequence_number; /* needed for CIFS PDU signature */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 3cef57b7a34f..49cc66825309 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1961,18 +1961,17 @@ struct data_blob { perhaps add a CreateDevice - to create Pipes and other special .inodes Also note POSIX open flags 2) Close - to return the last write time to do cache across close more safely - 3) PosixQFSInfo - to return statfs info - 4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes) - 5) Mkdir - set mode + 3) FindFirst return unique inode number - what about resume key, two + forms short (matches readdir) and full (enough info to cache inodes) + 4) Mkdir - set mode And under consideration: - 6) FindClose2 (return nanosecond timestamp ??) - 7) Use nanosecond timestamps throughout all time fields if + 5) FindClose2 (return nanosecond timestamp ??) + 6) Use nanosecond timestamps throughout all time fields if corresponding attribute flag is set - 8) sendfile - handle based copy - 9) Direct i/o - 10) "POSIX ACL" support - 11) Misc fcntls? + 7) sendfile - handle based copy + 8) Direct i/o + 9) Misc fcntls? what about fixing 64 bit alignment @@ -2028,7 +2027,7 @@ struct data_blob { */ -/* xsymlink is a symlink format that can be used +/* xsymlink is a symlink format (used by MacOS) that can be used to save symlink info in a regular file when mounted to operating systems that do not support the cifs Unix extensions or EAs (for xattr diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 66eaa6b40373..b9b13e3fe79d 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -61,9 +61,9 @@ extern int decode_negTokenInit(unsigned char *security_blob, int length, extern int cifs_inet_pton(int, char * source, void *dst); extern int map_smb_to_linux_error(struct smb_hdr *smb); extern void header_assemble(struct smb_hdr *, char /* command */ , - const struct cifsTconInfo *, int /* specifies length - of fixed section (word count) in two byte units */ - ); + const struct cifsTconInfo *, int /* length of + fixed section (word count) in two byte units */); +extern __u16 GetNextMid(struct TCP_Server_Info *server); extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *); extern void DeleteOplockQEntry(struct oplock_q_entry *); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 1b073546f5d9..930be0927de2 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -330,7 +330,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) (void **) &pSMB, (void **) &pSMBr); if (rc) return rc; - + pSMB->hdr.Mid = GetNextMid(server); pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; if (extended_security) pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; @@ -415,15 +415,14 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) if(server->secMode & SECMODE_SIGN_REQUIRED) cERROR(1, ("Server requires /proc/fs/cifs/PacketSigningEnabled")); - server->secMode &= ~(SECMODE_SIGN_ENABLED | - SECMODE_SIGN_REQUIRED); + server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); } else if(sign_CIFS_PDUs == 1) { if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) - server->secMode &= ~(SECMODE_SIGN_ENABLED | - SECMODE_SIGN_REQUIRED); + server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); } } + cifs_buf_release(pSMB); return rc; } @@ -519,6 +518,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */ if(ses->server) { + pSMB->hdr.Mid = GetNextMid(ses->server); + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; @@ -2519,11 +2520,12 @@ findFirstRetry: rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); - if (rc) {/* BB add logic to retry regular search if Unix search - rejected unexpectedly by server */ + if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ /* BB Add code to handle unsupported level rc */ cFYI(1, ("Error in FindFirst = %d", rc)); - cifs_buf_release(pSMB); + + if (pSMB) + cifs_buf_release(pSMB); /* BB eventually could optimize out free and realloc of buf */ /* for this case */ @@ -2857,7 +2859,10 @@ getDFSRetry: (void **) &pSMBr); if (rc) return rc; - + + /* server pointer checked in called function, + but should never be null here anyway */ + pSMB->hdr.Mid = GetNextMid(ses->server); pSMB->hdr.Tid = ses->ipc_tid; pSMB->hdr.Uid = ses->Suid; if (ses->capabilities & CAP_STATUS32) { diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 36f78596c81a..9e8256003f73 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1857,6 +1857,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, NULL /* no tCon exists yet */ , 13 /* wct */ ); + smb_buffer->Mid = GetNextMid(ses->server); pSMB->req_no_secext.AndXCommand = 0xFF; pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); @@ -2132,6 +2133,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, NULL /* no tCon exists yet */ , 12 /* wct */ ); + + smb_buffer->Mid = GetNextMid(ses->server); pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; pSMB->req.AndXCommand = 0xFF; pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); @@ -2398,6 +2401,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, NULL /* no tCon exists yet */ , 12 /* wct */ ); + + smb_buffer->Mid = GetNextMid(ses->server); pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); @@ -2740,6 +2745,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, NULL /* no tCon exists yet */ , 12 /* wct */ ); + + smb_buffer->Mid = GetNextMid(ses->server); pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; pSMB->req.AndXCommand = 0xFF; @@ -3111,6 +3118,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, NULL /*no tid */ , 4 /*wct */ ); + + smb_buffer->Mid = GetNextMid(ses->server); smb_buffer->Uid = ses->Suid; pSMB = (TCONX_REQ *) smb_buffer; pSMBr = (TCONX_RSP *) smb_buffer_response; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 20ae4153f791..beeff8284169 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -34,8 +34,6 @@ extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; extern struct task_struct * oplockThread; -static __u16 GlobalMid; /* multiplex id - rotating counter */ - /* The xid serves as a useful identifier for each incoming vfs request, in a similar way to the mid which is useful to track each sent smb, and CurrentXid can also provide a running counter (although it @@ -51,6 +49,8 @@ _GetXid(void) GlobalTotalActiveXid++; if (GlobalTotalActiveXid > GlobalMaxActiveXid) GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ + if(GlobalTotalActiveXid > 65000) + cFYI(1,("warning: more than 65000 requests active")); xid = GlobalCurrentXid++; spin_unlock(&GlobalMid_Lock); return xid; @@ -218,6 +218,76 @@ cifs_small_buf_release(void *buf_to_free) return; } +/* + Find a free multiplex id (SMB mid). Otherwise there could be + mid collisions which might cause problems, demultiplexing the + wrong response to this request. Multiplex ids could collide if + one of a series requests takes much longer than the others, or + if a very large number of long lived requests (byte range + locks or FindNotify requests) are pending. No more than + 64K-1 requests can be outstanding at one time. If no + mids are available, return zero. A future optimization + could make the combination of mids and uid the key we use + to demultiplex on (rather than mid alone). + In addition to the above check, the cifs demultiplex + code already used the command code as a secondary + check of the frame and if signing is negotiated the + response would be discarded if the mid were the same + but the signature was wrong. Since the mid is not put in the + pending queue until later (when it is about to be dispatched) + we do have to limit the number of outstanding requests + to somewhat less than 64K-1 although it is hard to imagine + so many threads being in the vfs at one time. +*/ +__u16 GetNextMid(struct TCP_Server_Info *server) +{ + __u16 mid = 0; + __u16 last_mid; + int collision; + + if(server == NULL) + return mid; + + spin_lock(&GlobalMid_Lock); + last_mid = server->CurrentMid; /* we do not want to loop forever */ + server->CurrentMid++; + /* This nested loop looks more expensive than it is. + In practice the list of pending requests is short, + fewer than 50, and the mids are likely to be unique + on the first pass through the loop unless some request + takes longer than the 64 thousand requests before it + (and it would also have to have been a request that + did not time out) */ + while(server->CurrentMid != last_mid) { + struct list_head *tmp; + struct mid_q_entry *mid_entry; + + collision = 0; + if(server->CurrentMid == 0) + server->CurrentMid++; + + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct mid_q_entry, qhead); + + if ((mid_entry->mid == server->CurrentMid) && + (mid_entry->midState == MID_REQUEST_SUBMITTED)) { + /* This mid is in use, try a different one */ + collision = 1; + break; + } + } + if(collision == 0) { + mid = server->CurrentMid; + break; + } + server->CurrentMid++; + } + spin_unlock(&GlobalMid_Lock); + return mid; +} + +/* NB: MID can not be set if treeCon not passed in, in that + case it is responsbility of caller to set the mid */ void header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , const struct cifsTconInfo *treeCon, int word_count @@ -233,7 +303,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , (2 * word_count) + sizeof (struct smb_hdr) - 4 /* RFC 1001 length field does not count */ + 2 /* for bcc field itself */ ; - /* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */ + /* Note that this is the only network field that has to be converted + to big endian and it is done just before we send it */ buffer->Protocol[0] = 0xFF; buffer->Protocol[1] = 'S'; @@ -245,8 +316,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , buffer->Pid = cpu_to_le16((__u16)current->tgid); buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16)); spin_lock(&GlobalMid_Lock); - GlobalMid++; - buffer->Mid = GlobalMid; spin_unlock(&GlobalMid_Lock); if (treeCon) { buffer->Tid = treeCon->tid; @@ -256,8 +325,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , if (treeCon->ses->capabilities & CAP_STATUS32) { buffer->Flags2 |= SMBFLG2_ERR_STATUS; } - - buffer->Uid = treeCon->ses->Suid; /* always in LE format */ + /* Uid is not converted */ + buffer->Uid = treeCon->ses->Suid; + buffer->Mid = GetNextMid(treeCon->ses->server); if(multiuser_mount != 0) { /* For the multiuser case, there are few obvious technically */ /* possible mechanisms to match the local linux user (uid) */ -- cgit v1.2.3 From d3485d37c0b3292aec0618b6663c57542df5da99 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 19 Aug 2005 11:04:29 -0700 Subject: [CIFS] Finish cifs mount option which requests case insensitive path name matching. Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/cifs_fs_sb.h | 3 +-- fs/cifs/cifsglob.h | 5 +++-- fs/cifs/connect.c | 9 +++++++-- fs/cifs/misc.c | 2 ++ 4 files changed, 13 insertions(+), 6 deletions(-) (limited to 'fs/cifs/misc.c') diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 5fb695f1e50b..f799f6f0e729 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -26,8 +26,7 @@ #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ #define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */ #define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */ -#define CIFS_MOUNT_CASE_INSENS 0x100 /* Request case insenstive searches */ -#define CIFS_MOUNT_NO_BRL 0x200 /* No sending byte range locks to srv */ +#define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */ struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index e8287f76484f..e7ba48c61a7a 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -110,8 +110,8 @@ enum protocolEnum { */ struct TCP_Server_Info { - char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20'in 16th */ - char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; /* Unicode version of server_Name */ + char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20' 16th */ + char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; struct socket *ssocket; union { struct sockaddr_in sockAddr; @@ -231,6 +231,7 @@ struct cifsTconInfo { FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ FILE_SYSTEM_UNIX_INFO fsUnixInfo; unsigned retry:1; + unsigned nocase:1; /* BB add field for back pointer to sb struct? */ }; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 6b21f6aa9f60..ac2c8bdc8e55 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1048,6 +1048,11 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) vol->nobrl = 0; } else if (strnicmp(data, "nobrl", 5) == 0) { vol->nobrl = 1; + /* turn off mandatory locking in mode + if remote locking is turned off since the + local vfs will do advisory */ + if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP))) + vol->file_mode = S_IALLUGO; } else if (strnicmp(data, "setuids", 7) == 0) { vol->setuids = 1; } else if (strnicmp(data, "nosetuids", 9) == 0) { @@ -1707,8 +1712,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; if(volume_info.sfu_emul) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; - if(volume_info.nocase) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CASE_INSENS; if(volume_info.nobrl) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; @@ -1727,6 +1730,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, to the same server share the last value passed in for the retry flag is used */ tcon->retry = volume_info.retry; + tcon->nocase = volume_info.nocase; } else { tcon = tconInfoAlloc(); if (tcon == NULL) @@ -1755,6 +1759,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (!rc) { atomic_inc(&pSesInfo->inUse); tcon->retry = volume_info.retry; + tcon->nocase = volume_info.nocase; } } } diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index beeff8284169..40d50b77bfe7 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -375,6 +375,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , } if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) buffer->Flags2 |= SMBFLG2_DFS; + if (treeCon->nocase) + buffer->Flags |= SMBFLG_CASELESS; if((treeCon->ses) && (treeCon->ses->server)) if(treeCon->ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) -- cgit v1.2.3 From a45443475835ab4d1c753159812aca21b5c333a3 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 24 Aug 2005 13:59:35 -0700 Subject: CIFS: Reduce CONFIG_CIFS_STATS ifdefs Make cifs_stats code conditional in the header files to avoid ifdefs in the main code. Signed-off-by: Dave Kleikamp Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 28 +++++++++++++++++ fs/cifs/cifssmb.c | 88 +++++++++++++++--------------------------------------- fs/cifs/file.c | 34 ++++----------------- fs/cifs/misc.c | 4 +-- 4 files changed, 58 insertions(+), 96 deletions(-) (limited to 'fs/cifs/misc.c') diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index f143975627e0..9a3c85bdd77e 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -339,6 +339,34 @@ static inline const char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb) return '\\'; } +#ifdef CONFIG_CIFS_STATS +#define cifs_stats_inc atomic_inc + +static inline void cifs_stats_bytes_written(struct cifsTconInfo *tcon, + unsigned int bytes) +{ + if (bytes) { + spin_lock(&tcon->stat_lock); + tcon->bytes_written += bytes; + spin_unlock(&tcon->stat_lock); + } +} + +static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon, + unsigned int bytes) +{ + spin_lock(&tcon->stat_lock); + tcon->bytes_read += bytes; + spin_unlock(&tcon->stat_lock); +} +#else + +#define cifs_stats_inc(field) do {} while(0) +#define cifs_stats_bytes_written(tcon, bytes) do {} while(0) +#define cifs_stats_bytes_read(tcon, bytes) do {} while(0) + +#endif + /* one of these for every pending CIFS request to the server */ struct mid_q_entry { struct list_head qhead; /* mids waiting on reply from this server */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 811ab3dffafa..698cdcebca04 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -166,11 +166,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct); -#ifdef CONFIG_CIFS_STATS - if(tcon != NULL) { - atomic_inc(&tcon->num_smbs_sent); - } -#endif /* CONFIG_CIFS_STATS */ + if(tcon != NULL) + cifs_stats_inc(&tcon->num_smbs_sent); + return rc; } @@ -269,11 +267,9 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, wct /*wct */ ); -#ifdef CONFIG_CIFS_STATS - if(tcon != NULL) { - atomic_inc(&tcon->num_smbs_sent); - } -#endif /* CONFIG_CIFS_STATS */ + if(tcon != NULL) + cifs_stats_inc(&tcon->num_smbs_sent); + return rc; } @@ -584,9 +580,7 @@ DelFileRetry: pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_deletes); -#endif + cifs_stats_inc(&tcon->num_deletes); if (rc) { cFYI(1, ("Error in RMFile = %d", rc)); } @@ -631,9 +625,7 @@ RmDirRetry: pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_rmdirs); -#endif + cifs_stats_inc(&tcon->num_rmdirs); if (rc) { cFYI(1, ("Error in RMDir = %d", rc)); } @@ -677,9 +669,7 @@ MkDirRetry: pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_mkdirs); -#endif + cifs_stats_inc(&tcon->num_mkdirs); if (rc) { cFYI(1, ("Error in Mkdir = %d", rc)); } @@ -767,9 +757,7 @@ openRetry: /* long_op set to 1 to allow for oplock break timeouts */ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 1); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_opens); -#endif + cifs_stats_inc(&tcon->num_opens); if (rc) { cFYI(1, ("Error in Open = %d", rc)); } else { @@ -833,9 +821,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_reads); -#endif + cifs_stats_inc(&tcon->num_reads); if (rc) { cERROR(1, ("Send error in read = %d", rc)); } else { @@ -938,9 +924,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, long_op); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_writes); -#endif + cifs_stats_inc(&tcon->num_writes); if (rc) { cFYI(1, ("Send error in write = %d", rc)); *nbytes = 0; @@ -1013,9 +997,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len, buf, bytes_sent, &bytes_returned, long_op); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_writes); -#endif + cifs_stats_inc(&tcon->num_writes); if (rc) { cFYI(1, ("Send error in write = %d", rc)); *nbytes = 0; @@ -1091,9 +1073,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, timeout); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_locks); -#endif + cifs_stats_inc(&tcon->num_locks); if (rc) { cFYI(1, ("Send error in Lock = %d", rc)); } @@ -1127,9 +1107,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) pSMB->ByteCount = 0; rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_closes); -#endif + cifs_stats_inc(&tcon->num_closes); if (rc) { if(rc!=-EINTR) { /* EINTR is expected when user ctl-c to kill app */ @@ -1202,9 +1180,7 @@ renameRetry: rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_renames); -#endif + cifs_stats_inc(&tcon->num_renames); if (rc) { cFYI(1, ("Send error in rename = %d", rc)); } @@ -1283,9 +1259,7 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&pTcon->num_t2renames); -#endif + cifs_stats_inc(&pTcon->num_t2renames); if (rc) { cFYI(1,("Send error in Rename (by file handle) = %d", rc)); } @@ -1443,9 +1417,7 @@ createSymLinkRetry: pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_symlinks); -#endif + cifs_stats_inc(&tcon->num_symlinks); if (rc) { cFYI(1, ("Send error in SetPathInfo (create symlink) = %d", @@ -1535,9 +1507,7 @@ createHardLinkRetry: pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_hardlinks); -#endif + cifs_stats_inc(&tcon->num_hardlinks); if (rc) { cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc)); } @@ -1608,9 +1578,7 @@ winCreateHardLinkRetry: rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_hardlinks); -#endif + cifs_stats_inc(&tcon->num_hardlinks); if (rc) { cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); } @@ -2490,9 +2458,7 @@ findUniqueRetry: if (rc) { cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); } else { /* decode response */ -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_ffirst); -#endif + cifs_stats_inc(&tcon->num_ffirst); /* BB fill in */ } @@ -2592,9 +2558,7 @@ findFirstRetry: rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_ffirst); -#endif + cifs_stats_inc(&tcon->num_ffirst); if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ /* BB Add code to handle unsupported level rc */ @@ -2716,9 +2680,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_fnext); -#endif + cifs_stats_inc(&tcon->num_fnext); if (rc) { if (rc == -EBADF) { psrch_inf->endOfSearch = TRUE; @@ -2795,9 +2757,7 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle if (rc) { cERROR(1, ("Send error in FindClose = %d", rc)); } -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_fclose); -#endif + cifs_stats_inc(&tcon->num_fclose); cifs_small_buf_release(pSMB); /* Since session is dead, search handle closed on server already */ diff --git a/fs/cifs/file.c b/fs/cifs/file.c index b054df2dee1e..5857d12611e6 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -744,13 +744,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, 15 seconds is plenty */ } -#ifdef CONFIG_CIFS_STATS - if (total_written > 0) { - spin_lock(&pTcon->stat_lock); - pTcon->bytes_written += total_written; - spin_unlock(&pTcon->stat_lock); - } -#endif + cifs_stats_bytes_written(pTcon, total_written); /* since the write may have blocked check these pointers again */ if (file->f_dentry) { @@ -878,13 +872,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, 15 seconds is plenty */ } -#ifdef CONFIG_CIFS_STATS - if (total_written > 0) { - spin_lock(&pTcon->stat_lock); - pTcon->bytes_written += total_written; - spin_unlock(&pTcon->stat_lock); - } -#endif + cifs_stats_bytes_written(pTcon, total_written); /* since the write may have blocked check these pointers again */ if (file->f_dentry) { @@ -1245,11 +1233,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, return rc; } } else { -#ifdef CONFIG_CIFS_STATS - spin_lock(&pTcon->stat_lock); - pTcon->bytes_read += total_read; - spin_unlock(&pTcon->stat_lock); -#endif + cifs_stats_bytes_read(pTcon, bytes_read); *poffset += bytes_read; } } @@ -1312,11 +1296,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, return rc; } } else { -#ifdef CONFIG_CIFS_STATS - spin_lock(&pTcon->stat_lock); - pTcon->bytes_read += total_read; - spin_unlock(&pTcon->stat_lock); -#endif + cifs_stats_bytes_read(pTcon, total_read); *poffset += bytes_read; } } @@ -1488,11 +1468,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, le16_to_cpu(pSMBr->DataOffset), &lru_pvec); i += bytes_read >> PAGE_CACHE_SHIFT; -#ifdef CONFIG_CIFS_STATS - spin_lock(&pTcon->stat_lock); - pTcon->bytes_read += bytes_read; - spin_unlock(&pTcon->stat_lock); -#endif + cifs_stats_bytes_read(pTcon, bytes_read); if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { i++; /* account for partial page */ diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 40d50b77bfe7..fafbdbfa63a1 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -520,9 +520,7 @@ is_valid_oplock_break(struct smb_hdr *buf) list_for_each(tmp, &GlobalTreeConnectionList) { tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); if (tcon->tid == buf->Tid) { -#ifdef CONFIG_CIFS_STATS - atomic_inc(&tcon->num_oplock_brks); -#endif + cifs_stats_inc(&tcon->num_oplock_brks); list_for_each(tmp1,&tcon->openFileList){ netfile = list_entry(tmp1,struct cifsFileInfo, tlist); -- cgit v1.2.3 From 2096243885ee34b78cb57ce835e07c8536a67d2a Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 21 Sep 2005 22:05:57 -0700 Subject: [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: Steve French (sfrench@us.ibm.com) --- fs/cifs/CHANGES | 3 +- fs/cifs/cifsfs.c | 4 +++ fs/cifs/cifspdu.h | 8 +++++ fs/cifs/cifsproto.h | 2 ++ fs/cifs/cifssmb.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++---- fs/cifs/misc.c | 3 +- fs/cifs/netmisc.c | 2 +- 7 files changed, 107 insertions(+), 10 deletions(-) (limited to 'fs/cifs/misc.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 47ae68b51847..661b45906d09 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -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 ------------ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f738c8b19e3b..1f97d39100ee 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -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; diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index cf466595b0d4..3fa37790bea2 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -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; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 6943f7c6de08..0bace385e97a 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -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); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f72a61df3c68..daf717e6b6eb 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -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 diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index fafbdbfa63a1..26b35b55f31b 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -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) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 873b812c0f40..32efa32774d2 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -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 */ -- cgit v1.2.3 From 70ca734a14366b634224a1e4586d43b36b65ab67 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 22 Sep 2005 16:32:06 -0700 Subject: [CIFS] Various minor bigendian fixes and sparse level 2 warning message fixes Most important of these fixes mapchars on bigendian and a few statfs fields Signed-off-by: Shaggy (shaggy@austin.ibm.com) Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/CHANGES | 3 ++- fs/cifs/cifspdu.h | 2 +- fs/cifs/cifsproto.h | 1 + fs/cifs/cifssmb.c | 24 ++++++++++++++---------- fs/cifs/connect.c | 38 +++++++++++++++++++++++++------------- fs/cifs/misc.c | 12 +++++++----- fs/cifs/netmisc.c | 9 ++++++++- fs/cifs/transport.c | 4 ++-- 8 files changed, 60 insertions(+), 33 deletions(-) (limited to 'fs/cifs/misc.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 661b45906d09..535177238020 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -4,7 +4,8 @@ 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). Fix length check of received smbs -to be more accurate. +to be more accurate. Fix big endian problem with mapchars mount option, +and with a field returned by statfs. Version 1.36 ------------ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 3fa37790bea2..193f06eb43f9 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -697,7 +697,7 @@ typedef struct smb_com_openx_req { __le32 EndOfFile; __le32 Timeout; __le32 Reserved; - __u16 ByteCount; /* file name follows */ + __le16 ByteCount; /* file name follows */ char fileName[1]; } OPENX_REQ; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 0bace385e97a..dc5a6a6ff2f9 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -56,6 +56,7 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); extern int is_valid_oplock_break(struct smb_hdr *smb); extern int is_size_safe_to_change(struct cifsInodeInfo *); extern unsigned int smbCalcSize(struct smb_hdr *ptr); +extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, enum securityEnum *secType); extern int cifs_inet_pton(int, char * source, void *dst); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index daf717e6b6eb..52caac063a77 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -779,7 +779,7 @@ OldOpenRetry: /* BB FIXME END BB */ pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); - pSMB->OpenFunction = convert_disposition(openDisposition); + pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition)); count += name_len; pSMB->hdr.smb_buf_length += count; @@ -808,10 +808,12 @@ OldOpenRetry: pfile_info->LastAccessTime = 0; /* BB fixme */ pfile_info->LastWriteTime = 0; /* BB fixme */ pfile_info->ChangeTime = 0; /* BB fixme */ - pfile_info->Attributes = pSMBr->FileAttributes; + pfile_info->Attributes = + cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); /* the file_info buf is endian converted by caller */ - pfile_info->AllocationSize = pSMBr->EndOfFile; - pfile_info->EndOfFile = pSMBr->EndOfFile; + pfile_info->AllocationSize = + cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile)); + pfile_info->EndOfFile = pfile_info->AllocationSize; pfile_info->NumberOfLinks = cpu_to_le32(1); } } @@ -2390,9 +2392,11 @@ QInfRetry: cFYI(1, ("Send error in QueryInfo = %d", rc)); } else if (pFinfo) { /* decode response */ memset(pFinfo, 0, sizeof(FILE_ALL_INFO)); - pFinfo->AllocationSize = (__le64) pSMBr->size; - pFinfo->EndOfFile = (__le64) pSMBr->size; - pFinfo->Attributes = (__le32) pSMBr->attr; + pFinfo->AllocationSize = + cpu_to_le64(le32_to_cpu(pSMBr->size)); + pFinfo->EndOfFile = pFinfo->AllocationSize; + pFinfo->Attributes = + cpu_to_le32(le16_to_cpu(pSMBr->attr)); } else rc = -EIO; /* bad buffer passed in */ @@ -3722,16 +3726,16 @@ QFSPosixRetry: le64_to_cpu(response_data->TotalBlocks); FSData->f_bfree = le64_to_cpu(response_data->BlocksAvail); - if(response_data->UserBlocksAvail == -1) { + if(response_data->UserBlocksAvail == cpu_to_le64(-1)) { FSData->f_bavail = FSData->f_bfree; } else { FSData->f_bavail = le64_to_cpu(response_data->UserBlocksAvail); } - if(response_data->TotalFileNodes != -1) + if(response_data->TotalFileNodes != cpu_to_le64(-1)) FSData->f_files = le64_to_cpu(response_data->TotalFileNodes); - if(response_data->FreeFileNodes != -1) + if(response_data->FreeFileNodes != cpu_to_le64(-1)) FSData->f_ffree = le64_to_cpu(response_data->FreeFileNodes); } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 196976049c00..e27e5ad8b591 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -303,12 +303,12 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB) byte_count += total_in_buf2; BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); - byte_count = be32_to_cpu(pTargetSMB->smb_buf_length); + byte_count = pTargetSMB->smb_buf_length; byte_count += total_in_buf2; /* BB also add check that we are not beyond maximum buffer size */ - pTargetSMB->smb_buf_length = cpu_to_be32(byte_count); + pTargetSMB->smb_buf_length = byte_count; if(remaining == total_in_buf2) { cFYI(1,("found the last secondary response")); @@ -333,7 +333,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) struct cifsSesInfo *ses; struct task_struct *task_to_wake = NULL; struct mid_q_entry *mid_entry; - char *temp; + char temp; int isLargeBuf = FALSE; int isMultiRsp; int reconnect; @@ -435,22 +435,32 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) continue; } - /* the right amount was read from socket - 4 bytes */ + /* The right amount was read from socket - 4 bytes */ + /* so we can now interpret the length field */ + /* the first byte big endian of the length field, + is actually not part of the length but the type + with the most common, zero, as regular data */ + temp = *((char *) smb_buffer); + + /* Note that FC 1001 length is big endian on the wire, + but we convert it here so it is always manipulated + as host byte order */ pdu_length = ntohl(smb_buffer->smb_buf_length); - cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4)); + smb_buffer->smb_buf_length = pdu_length; + + cFYI(1,("rfc1002 length 0x%x)", pdu_length+4)); - temp = (char *) smb_buffer; - if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { + if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) { continue; - } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { + } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { cFYI(1,("Good RFC 1002 session rsp")); continue; - } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { + } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { /* we get this from Windows 98 instead of an error on SMB negprot response */ cFYI(1,("Negative RFC1002 Session Response Error 0x%x)", - temp[4])); + pdu_length)); if(server->tcpStatus == CifsNew) { /* if nack on negprot (rather than ret of smb negprot error) reconnecting @@ -472,9 +482,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) wake_up(&server->response_q); continue; } - } else if (temp[0] != (char) 0) { + } else if (temp != (char) 0) { cERROR(1,("Unknown RFC 1002 frame")); - cifs_dump_mem(" Received Data: ", temp, length); + cifs_dump_mem(" Received Data: ", (char *)smb_buffer, + length); cifs_reconnect(server); csocket = server->ssocket; continue; @@ -609,7 +620,8 @@ multi_t2_fnd: } else if ((is_valid_oplock_break(smb_buffer) == FALSE) && (isMultiRsp == FALSE)) { cERROR(1, ("No task to wake, unknown frame rcvd!")); - cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); + cifs_dump_mem("Received Data is: ",(char *)smb_buffer, + sizeof(struct smb_hdr)); } } /* end while !EXITING */ diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 26b35b55f31b..8a0edd695f84 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -419,7 +419,7 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid) int checkSMB(struct smb_hdr *smb, __u16 mid, int length) { - __u32 len = be32_to_cpu(smb->smb_buf_length); + __u32 len = smb->smb_buf_length; cFYI(0, ("Entering checkSMB with Length: %x, smb_buf_length: %x ", length, len)); @@ -448,9 +448,9 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) if (checkSMBhdr(smb, mid)) return 1; - if ((4 + len != smbCalcSize(smb)) + if ((4 + len != smbCalcSize_LE(smb)) || (4 + len != (unsigned int)length)) { - cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); + cERROR(1, ("smbCalcSize %x ", smbCalcSize_LE(smb))); cERROR(1, ("bad smb size detected. The Mid=%d", smb->Mid)); return 1; @@ -672,6 +672,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, int i,j,charlen; int len_remaining = maxlen; char src_char; + __u16 temp; if(!mapChars) return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); @@ -708,13 +709,14 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, break;*/ default: charlen = cp->char2uni(source+i, - len_remaining, target+j); + len_remaining, &temp); /* if no match, use question mark, which at least in some cases servers as wild card */ if(charlen < 1) { target[j] = cpu_to_le16(0x003f); charlen = 1; - } + } else + target[j] = cpu_to_le16(temp); len_remaining -= charlen; /* character may take more than one byte in the the source string, but will take exactly two diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 32efa32774d2..29e6efc5597c 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -868,7 +868,14 @@ unsigned int smbCalcSize(struct smb_hdr *ptr) { return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + - 2 /* size of the bcc field itself */ + BCC(ptr)); + 2 /* size of the bcc field */ + BCC(ptr)); +} + +unsigned int +smbCalcSize_LE(struct smb_hdr *ptr) +{ + return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + + 2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr))); } /* The following are taken from fs/ntfs/util.c */ diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index d5e0c4018f92..9e8e85a8d186 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -414,7 +414,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, spin_lock(&GlobalMid_Lock); if (midQ->resp_buf) { spin_unlock(&GlobalMid_Lock); - receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf); + receive_len = midQ->resp_buf->smb_buf_length; } else { cERROR(1,("No response buffer")); if(midQ->midState == MID_REQUEST_SUBMITTED) { @@ -665,7 +665,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, spin_lock(&GlobalMid_Lock); if (midQ->resp_buf) { spin_unlock(&GlobalMid_Lock); - receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf); + receive_len = midQ->resp_buf->smb_buf_length; } else { cERROR(1,("No response buffer")); if(midQ->midState == MID_REQUEST_SUBMITTED) { -- cgit v1.2.3 From 190fdeb84499a2dc046adae2eebfdda49e315e96 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 10 Oct 2005 11:48:26 -0700 Subject: [CIFS] Fix byte range locking to Windows when Windows server returns illegal RFC1001 length (which had caused the lock to block forever until killed). --- fs/cifs/CHANGES | 12 ++++++++++++ fs/cifs/README | 4 ++-- fs/cifs/TODO | 6 +++--- fs/cifs/misc.c | 22 +++++++++++++++------- 4 files changed, 32 insertions(+), 12 deletions(-) (limited to 'fs/cifs/misc.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 535177238020..1c249a2abae3 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,15 @@ +Version 1.38 +------------ +Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket) +to be smaller at first (but increasing) so large write performance performance +over GigE is better. Do not hang thread on illegal byte range lock response +from Windows (Windows can send an RFC1001 size which does not match smb size) by +allowing an SMBs TCP length to be up to a few bytes longer than it should be. +wsize and rsize can now be larger than negotiated buffer size if server +supports large readx/writex, even when directio mount flag not specified. +Write size will in many cases now be 16K instead of 4K which greatly helps +file copy performance on lightly loaded networks. + Version 1.37 ------------ Fix readdir caching when unlink removes file in current search buffer, diff --git a/fs/cifs/README b/fs/cifs/README index 3b610d08dc1e..5d9a953888d9 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -294,8 +294,8 @@ A partial list of the supported mount options follows: during the local client kernel build will be used. If server does not support Unicode, this parameter is unused. - rsize default read size - wsize default write size + rsize default read size (usually 16K) + wsize default write size (usually 16K, 32K is often better over GigE) rw mount the network share read-write (note that the server may still consider the share read-only) ro mount network share read-only diff --git a/fs/cifs/TODO b/fs/cifs/TODO index 0593f6447319..c909298d11ed 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO @@ -1,4 +1,4 @@ -version 1.36 September 6, 2005 +version 1.37 October 9, 2005 A Partial List of Missing Features ================================== @@ -38,8 +38,8 @@ by unlocking all known byte range locks that we locked on the file. i) quota support (needs minor kernel change since quota calls to make it to network filesystems or deviceless filesystems) -j) finish writepages support (multi-page write behind for improved -performance) and syncpage. Started by Shaggy. +j) investigate sync behavior (including syncpage) and check +for proper behavior of intr/nointr k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the extra copy in/out of the socket buffers in some cases. diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 8a0edd695f84..eba1de917f2a 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -420,6 +420,7 @@ int checkSMB(struct smb_hdr *smb, __u16 mid, int length) { __u32 len = smb->smb_buf_length; + __u32 clc_len; /* calculated length */ cFYI(0, ("Entering checkSMB with Length: %x, smb_buf_length: %x ", length, len)); @@ -440,20 +441,27 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) cERROR(1, ("smb_buf_length greater than MaxBufSize")); cERROR(1, - ("bad smb detected. Illegal length. The mid=%d", + ("bad smb detected. Illegal length. mid=%d", smb->Mid)); return 1; } if (checkSMBhdr(smb, mid)) return 1; - - if ((4 + len != smbCalcSize_LE(smb)) + clc_len = smbCalcSize_LE(smb); + if ((4 + len != clc_len) || (4 + len != (unsigned int)length)) { - cERROR(1, ("smbCalcSize %x ", smbCalcSize_LE(smb))); - cERROR(1, - ("bad smb size detected. The Mid=%d", smb->Mid)); - return 1; + cERROR(1, ("Calculated size 0x%x vs actual length 0x%x", + clc_len, 4 + len)); + cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid)); + /* Windows XP can return a few bytes too much, presumably + an illegal pad, at the end of byte range lock responses + so we allow for up to eight byte pad, as long as actual + received length is as long or longer than calculated length */ + if((4+len > clc_len) && (len <= clc_len + 3)) + return 0; + else + return 1; } return 0; } -- cgit v1.2.3