diff options
Diffstat (limited to 'fs/smb/client/cifssmb.c')
| -rw-r--r-- | fs/smb/client/cifssmb.c | 1401 |
1 files changed, 903 insertions, 498 deletions
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 595c4b673707..3db1a892c526 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -70,10 +70,9 @@ static struct { static int cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) { - int rc; - struct cifs_ses *ses; struct TCP_Server_Info *server; - struct nls_table *nls_codepage = NULL; + struct cifs_ses *ses; + int rc; /* * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for @@ -115,24 +114,26 @@ again: mutex_lock(&ses->session_mutex); /* - * Recheck after acquire mutex. If another thread is negotiating - * and the server never sends an answer the socket will be closed - * and tcpStatus set to reconnect. + * Handle the case where a concurrent thread failed to negotiate or + * killed a channel. */ spin_lock(&server->srv_lock); - if (server->tcpStatus == CifsNeedReconnect) { + switch (server->tcpStatus) { + case CifsExiting: spin_unlock(&server->srv_lock); mutex_unlock(&ses->session_mutex); - - if (tcon->retry) - goto again; - rc = -EHOSTDOWN; - goto out; + return -EHOSTDOWN; + case CifsNeedReconnect: + spin_unlock(&server->srv_lock); + mutex_unlock(&ses->session_mutex); + if (!tcon->retry) + return -EHOSTDOWN; + goto again; + default: + break; } spin_unlock(&server->srv_lock); - nls_codepage = ses->local_nls; - /* * need to prevent multiple threads trying to simultaneously * reconnect the same SMB session @@ -155,8 +156,21 @@ again: spin_unlock(&ses->ses_lock); rc = cifs_negotiate_protocol(0, ses, server); - if (!rc) - rc = cifs_setup_session(0, ses, server, nls_codepage); + if (rc) { + mutex_unlock(&ses->session_mutex); + if (!tcon->retry) + return -EHOSTDOWN; + goto again; + } + rc = cifs_setup_session(0, ses, server, ses->local_nls); + if ((rc == -EACCES) || (rc == -EHOSTDOWN) || (rc == -EKEYREVOKED)) { + /* + * Try alternate password for next reconnect if an alternate + * password is available. + */ + if (ses->password2) + swap(ses->password2, ses->password); + } /* do we need to reconnect tcon? */ if (rc || !tcon->need_reconnect) { @@ -166,7 +180,7 @@ again: skip_sess_setup: cifs_mark_open_files_invalid(tcon); - rc = cifs_tree_connect(0, tcon, nls_codepage); + rc = cifs_tree_connect(0, tcon); mutex_unlock(&ses->session_mutex); cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc); @@ -212,6 +226,7 @@ static int small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon, void **request_buf) { + unsigned int in_len; int rc; rc = cifs_reconnect_tcon(tcon, smb_command); @@ -224,13 +239,13 @@ small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon, return -ENOMEM; } - header_assemble((struct smb_hdr *) *request_buf, smb_command, - tcon, wct); + in_len = header_assemble((struct smb_hdr *) *request_buf, smb_command, + tcon, wct); if (tcon != NULL) cifs_stats_inc(&tcon->num_smbs_sent); - return 0; + return in_len; } int @@ -241,7 +256,7 @@ small_smb_init_no_tc(const int smb_command, const int wct, struct smb_hdr *buffer; rc = small_smb_init(smb_command, wct, NULL, request_buf); - if (rc) + if (rc < 0) return rc; buffer = (struct smb_hdr *)*request_buf; @@ -264,6 +279,8 @@ static int __smb_init(int smb_command, int wct, struct cifs_tcon *tcon, void **request_buf, void **response_buf) { + unsigned int in_len; + *request_buf = cifs_buf_get(); if (*request_buf == NULL) { /* BB should we add a retry in here if not a writepage? */ @@ -276,13 +293,13 @@ __smb_init(int smb_command, int wct, struct cifs_tcon *tcon, if (response_buf) *response_buf = *request_buf; - header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, - wct); + in_len = header_assemble((struct smb_hdr *)*request_buf, smb_command, tcon, + wct); if (tcon != NULL) cifs_stats_inc(&tcon->num_smbs_sent); - return 0; + return in_len; } /* If the return code is zero, this function must fill in request_buf pointer */ @@ -347,7 +364,7 @@ vt2_err: } static int -decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr) +decode_ext_sec_blob(struct cifs_ses *ses, SMB_NEGOTIATE_RSP *pSMBr) { int rc = 0; u16 count; @@ -356,7 +373,8 @@ decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr) count = get_bcc(&pSMBr->hdr); if (count < SMB1_CLIENT_GUID_SIZE) - return -EIO; + return smb_EIO2(smb_eio_trace_neg_sec_blob_too_small, + count, SMB1_CLIENT_GUID_SIZE); spin_lock(&cifs_tcp_ses_lock); if (server->srv_count > 1) { @@ -405,8 +423,9 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server) { - NEGOTIATE_REQ *pSMB; - NEGOTIATE_RSP *pSMBr; + SMB_NEGOTIATE_REQ *pSMB; + SMB_NEGOTIATE_RSP *pSMBr; + unsigned int in_len; int rc = 0; int bytes_returned; int i; @@ -414,16 +433,20 @@ CIFSSMBNegotiate(const unsigned int xid, if (!server) { WARN(1, "%s: server is NULL!\n", __func__); - return -EIO; + return smb_EIO(smb_eio_trace_null_pointers); } rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ , (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->hdr.Mid = get_next_mid(server); - pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS); + pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS; + + if (ses->unicode != 0) + pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; if (should_set_ext_sec_flag(ses->sectype)) { cifs_dbg(FYI, "Requesting extended security\n"); @@ -441,10 +464,10 @@ CIFSSMBNegotiate(const unsigned int xid, memcpy(&pSMB->DialectsArray[count], protocols[i].name, len); count += len; } - inc_rfc1001_len(pSMB, count); + in_len += count; pSMB->ByteCount = cpu_to_le16(count); - rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc != 0) goto neg_err_exit; @@ -481,6 +504,7 @@ CIFSSMBNegotiate(const unsigned int xid, server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf); server->capabilities = le32_to_cpu(pSMBr->Capabilities); + server->session_key_id = pSMBr->SessionKey; server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); server->timeAdj *= 60; @@ -493,7 +517,8 @@ CIFSSMBNegotiate(const unsigned int xid, server->negflavor = CIFS_NEGFLAVOR_EXTENDED; rc = decode_ext_sec_blob(ses, pSMBr); } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { - rc = -EIO; /* no crypt key only if plain text pwd */ + /* no crypt key only if plain text pwd */ + rc = smb_EIO(smb_eio_trace_neg_no_crypt_key); } else { server->negflavor = CIFS_NEGFLAVOR_UNENCAP; server->capabilities &= ~CAP_EXTENDED_SECURITY; @@ -512,13 +537,14 @@ int CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon) { struct smb_hdr *smb_buffer; + unsigned int in_len; int rc = 0; cifs_dbg(FYI, "In tree disconnect\n"); /* BB: do we need to check this? These should never be NULL. */ if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) - return -EIO; + return smb_EIO(smb_eio_trace_null_pointers); /* * No need to return error on this operation if tid invalidated and @@ -529,16 +555,17 @@ CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon) spin_lock(&tcon->ses->chan_lock); if ((tcon->need_reconnect) || CIFS_ALL_CHANS_NEED_RECONNECT(tcon->ses)) { spin_unlock(&tcon->ses->chan_lock); - return -EIO; + return smb_EIO(smb_eio_trace_tdis_in_reconnect); } spin_unlock(&tcon->ses->chan_lock); rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, (void **)&smb_buffer); - if (rc) + if (rc < 0) return rc; + in_len = rc; - rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, in_len, 0); cifs_small_buf_release(smb_buffer); if (rc) cifs_dbg(FYI, "Tree disconnect failed %d\n", rc); @@ -559,12 +586,11 @@ CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon) * FIXME: maybe we should consider checking that the reply matches request? */ static void -cifs_echo_callback(struct mid_q_entry *mid) +cifs_echo_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid) { - struct TCP_Server_Info *server = mid->callback_data; struct cifs_credits credits = { .value = 1, .instance = 0 }; - release_mid(mid); + release_mid(server, mid); add_credits(server, &credits, CIFS_ECHO_OP); } @@ -573,15 +599,19 @@ CIFSSMBEcho(struct TCP_Server_Info *server) { ECHO_REQ *smb; int rc = 0; - struct kvec iov[2]; - struct smb_rqst rqst = { .rq_iov = iov, - .rq_nvec = 2 }; + struct kvec iov[1]; + struct smb_rqst rqst = { + .rq_iov = iov, + .rq_nvec = ARRAY_SIZE(iov), + }; + unsigned int in_len; cifs_dbg(FYI, "In echo request\n"); rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (server->capabilities & CAP_UNICODE) smb->hdr.Flags2 |= SMBFLG2_UNICODE; @@ -592,12 +622,10 @@ CIFSSMBEcho(struct TCP_Server_Info *server) put_unaligned_le16(1, &smb->EchoCount); put_bcc(1, &smb->hdr); smb->Data[0] = 'a'; - inc_rfc1001_len(smb, 3); + in_len += 3; - iov[0].iov_len = 4; + iov[0].iov_len = in_len; iov[0].iov_base = smb; - iov[1].iov_len = get_rfc1002_length(smb); - iov[1].iov_base = (char *)smb + 4; rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL, server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL); @@ -613,6 +641,7 @@ int CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses) { LOGOFF_ANDX_REQ *pSMB; + unsigned int in_len; int rc = 0; cifs_dbg(FYI, "In SMBLogoff for session disconnect\n"); @@ -623,7 +652,7 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses) * should probably be a BUG() */ if (!ses || !ses->server) - return -EIO; + return smb_EIO(smb_eio_trace_null_pointers); mutex_lock(&ses->session_mutex); spin_lock(&ses->chan_lock); @@ -635,10 +664,11 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses) spin_unlock(&ses->chan_lock); rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB); - if (rc) { + if (rc < 0) { mutex_unlock(&ses->session_mutex); return rc; } + in_len = rc; pSMB->hdr.Mid = get_next_mid(ses->server); @@ -648,7 +678,7 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses) pSMB->hdr.Uid = ses->Suid; pSMB->AndXCommand = 0xFF; - rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0); + rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, in_len, 0); cifs_small_buf_release(pSMB); session_already_dead: mutex_unlock(&ses->session_mutex); @@ -669,6 +699,7 @@ CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; struct unlink_psx_rq *pRqD; + unsigned int in_len; int name_len; int rc = 0; int bytes_returned = 0; @@ -678,8 +709,9 @@ CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon, PsxDelete: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = @@ -700,14 +732,11 @@ PsxDelete: pSMB->Timeout = 0; pSMB->Reserved2 = 0; param_offset = offsetof(struct smb_com_transaction2_spi_req, - InformationLevel) - 4; + InformationLevel); offset = param_offset + params; - /* Setup pointer to Request Data (inode type). - * Note that SMB offsets are from the beginning of SMB which is 4 bytes - * in, after RFC1001 field - */ - pRqD = (struct unlink_psx_rq *)((char *)(pSMB) + offset + 4); + /* Setup pointer to Request Data (inode type). */ + pRqD = (struct unlink_psx_rq *)((char *)(pSMB) + offset); pRqD->type = cpu_to_le16(type); pSMB->ParameterOffset = cpu_to_le16(param_offset); pSMB->DataOffset = cpu_to_le16(offset); @@ -722,9 +751,9 @@ PsxDelete: pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) cifs_dbg(FYI, "Posix delete returned %d\n", rc); @@ -744,6 +773,7 @@ CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name, { DELETE_FILE_REQ *pSMB = NULL; DELETE_FILE_RSP *pSMBr = NULL; + unsigned int in_len; int rc = 0; int bytes_returned; int name_len; @@ -752,8 +782,9 @@ CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name, DelFileRetry: rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name, @@ -767,9 +798,9 @@ DelFileRetry: pSMB->SearchAttributes = cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM); pSMB->BufferFormat = 0x04; - inc_rfc1001_len(pSMB, name_len + 1); + in_len += name_len + 1; pSMB->ByteCount = cpu_to_le16(name_len + 1); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes); if (rc) @@ -788,6 +819,7 @@ CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, { DELETE_DIRECTORY_REQ *pSMB = NULL; DELETE_DIRECTORY_RSP *pSMBr = NULL; + unsigned int in_len; int rc = 0; int bytes_returned; int name_len; @@ -797,8 +829,9 @@ CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name, RmDirRetry: rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, @@ -811,9 +844,9 @@ RmDirRetry: } pSMB->BufferFormat = 0x04; - inc_rfc1001_len(pSMB, name_len + 1); + in_len += name_len + 1; pSMB->ByteCount = cpu_to_le16(name_len + 1); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs); if (rc) @@ -833,6 +866,7 @@ CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode, int rc = 0; CREATE_DIRECTORY_REQ *pSMB = NULL; CREATE_DIRECTORY_RSP *pSMBr = NULL; + unsigned int in_len; int bytes_returned; int name_len; int remap = cifs_remap(cifs_sb); @@ -841,8 +875,9 @@ CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode, MkDirRetry: rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, @@ -855,9 +890,9 @@ MkDirRetry: } pSMB->BufferFormat = 0x04; - inc_rfc1001_len(pSMB, name_len + 1); + in_len += name_len + 1; pSMB->ByteCount = cpu_to_le16(name_len + 1); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs); if (rc) @@ -878,6 +913,7 @@ CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon, { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; + unsigned int in_len; int name_len; int rc = 0; int bytes_returned = 0; @@ -889,8 +925,9 @@ CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon, PsxCreat: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = @@ -912,10 +949,9 @@ PsxCreat: pSMB->Timeout = 0; pSMB->Reserved2 = 0; param_offset = offsetof(struct smb_com_transaction2_spi_req, - InformationLevel) - 4; + InformationLevel); offset = param_offset + params; - /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ - pdata = (OPEN_PSX_REQ *)((char *)(pSMB) + offset + 4); + pdata = (OPEN_PSX_REQ *)((char *)(pSMB) + offset); pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); pdata->Permissions = cpu_to_le64(mode); pdata->PosixOpenFlags = cpu_to_le32(posix_flags); @@ -933,9 +969,9 @@ PsxCreat: pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "Posix create returned %d\n", rc); @@ -946,13 +982,14 @@ PsxCreat: rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) { - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_create_rsp_too_small, + get_bcc(&pSMBr->hdr), sizeof(OPEN_PSX_RSP)); goto psx_create_err; } /* copy return information to pRetData */ - psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol - + le16_to_cpu(pSMBr->t2.DataOffset)); + psx_rsp = (OPEN_PSX_RSP *) + ((char *)pSMBr + le16_to_cpu(pSMBr->t2.DataOffset)); *pOplock = le16_to_cpu(psx_rsp->OplockFlags); if (netfid) @@ -972,9 +1009,9 @@ PsxCreat: pRetData->Type = cpu_to_le32(-1); goto psx_create_err; } - memcpy((char *) pRetData, - (char *)psx_rsp + sizeof(OPEN_PSX_RSP), - sizeof(FILE_UNIX_BASIC_INFO)); + memcpy(pRetData, + (char *)psx_rsp + sizeof(OPEN_PSX_RSP), + sizeof(*pRetData)); } psx_create_err: @@ -1024,15 +1061,31 @@ static __u16 convert_disposition(int disposition) static int access_flags_to_smbopen_mode(const int access_flags) { - int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE); - - if (masked_flags == GENERIC_READ) - return SMBOPEN_READ; - else if (masked_flags == GENERIC_WRITE) + /* + * SYSTEM_SECURITY grants both read and write access to SACL, treat is as read/write. + * MAXIMUM_ALLOWED grants as many access as possible, so treat it as read/write too. + * SYNCHRONIZE as is does not grant any specific access, so do not check its mask. + * If only SYNCHRONIZE bit is specified then fallback to read access. + */ + bool with_write_flags = access_flags & (FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA | + FILE_DELETE_CHILD | FILE_WRITE_ATTRIBUTES | DELETE | + WRITE_DAC | WRITE_OWNER | SYSTEM_SECURITY | + MAXIMUM_ALLOWED | GENERIC_WRITE | GENERIC_ALL); + bool with_read_flags = access_flags & (FILE_READ_DATA | FILE_READ_EA | FILE_EXECUTE | + FILE_READ_ATTRIBUTES | READ_CONTROL | + SYSTEM_SECURITY | MAXIMUM_ALLOWED | GENERIC_ALL | + GENERIC_EXECUTE | GENERIC_READ); + bool with_execute_flags = access_flags & (FILE_EXECUTE | MAXIMUM_ALLOWED | GENERIC_ALL | + GENERIC_EXECUTE); + + if (with_write_flags && with_read_flags) + return SMBOPEN_READWRITE; + else if (with_write_flags) return SMBOPEN_WRITE; - - /* just go for read/write */ - return SMBOPEN_READWRITE; + else if (with_execute_flags) + return SMBOPEN_EXECUTE; + else + return SMBOPEN_READ; } int @@ -1045,6 +1098,7 @@ SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, int rc; OPENX_REQ *pSMB = NULL; OPENX_RSP *pSMBr = NULL; + unsigned int in_len; int bytes_returned; int name_len; __u16 count; @@ -1052,8 +1106,9 @@ SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon, OldOpenRetry: rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->AndXCommand = 0xFF; /* none */ @@ -1076,8 +1131,8 @@ OldOpenRetry: pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO); pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags)); pSMB->Mode |= cpu_to_le16(0x40); /* deny none */ - /* set file as system file if special file such - as fifo and server expecting SFU style and + /* set file as system file if special file such as fifo, + * socket, char or block and server expecting SFU style and no Unix extensions */ if (create_options & CREATE_OPTION_SPECIAL) @@ -1096,10 +1151,10 @@ OldOpenRetry: pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition)); count += name_len; - inc_rfc1001_len(pSMB, count); + in_len += count; pSMB->ByteCount = cpu_to_le16(count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *)pSMBr, &bytes_returned, 0); cifs_stats_inc(&tcon->stats.cifs_stats.num_opens); if (rc) { @@ -1129,7 +1184,7 @@ OldOpenRetry: cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile)); pfile_info->EndOfFile = pfile_info->AllocationSize; pfile_info->NumberOfLinks = cpu_to_le32(1); - pfile_info->DeletePending = 0; + pfile_info->DeletePending = 0; /* successful open = not delete pending */ } } @@ -1157,12 +1212,14 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock, int desired_access = oparms->desired_access; int disposition = oparms->disposition; const char *path = oparms->path; + unsigned int in_len; openRetry: rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req, (void **)&rsp); - if (rc) + if (rc < 0) return rc; + in_len = rc; /* no commands go after this */ req->AndXCommand = 0xFF; @@ -1193,8 +1250,8 @@ openRetry: req->AllocationSize = 0; /* - * Set file as system file if special file such as fifo and server - * expecting SFU style and no Unix extensions. + * Set file as system file if special file such as fifo, socket, char + * or block and server expecting SFU style and no Unix extensions. */ if (create_options & CREATE_OPTION_SPECIAL) req->FileAttributes = cpu_to_le32(ATTR_SYSTEM); @@ -1215,15 +1272,15 @@ openRetry: req->CreateDisposition = cpu_to_le32(disposition); req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); - /* BB Expirement with various impersonation levels and verify */ + /* BB Experiment with various impersonation levels and verify */ req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY; count += name_len; - inc_rfc1001_len(req, count); + in_len += count; req->ByteCount = cpu_to_le16(count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req, in_len, (struct smb_hdr *)rsp, &bytes_returned, 0); cifs_stats_inc(&tcon->stats.cifs_stats.num_opens); if (rc) { @@ -1254,7 +1311,7 @@ openRetry: buf->AllocationSize = rsp->AllocationSize; buf->EndOfFile = rsp->EndOfFile; buf->NumberOfLinks = cpu_to_le32(1); - buf->DeletePending = 0; + buf->DeletePending = 0; /* successful open = not delete pending */ } cifs_buf_release(req); @@ -1262,15 +1319,22 @@ openRetry: } static void -cifs_readv_callback(struct mid_q_entry *mid) +cifs_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid) { struct cifs_io_subrequest *rdata = mid->callback_data; + struct netfs_inode *ictx = netfs_inode(rdata->rreq->inode); struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink); - struct TCP_Server_Info *server = tcon->ses->server; struct smb_rqst rqst = { .rq_iov = rdata->iov, - .rq_nvec = 2, + .rq_nvec = 1, .rq_iter = rdata->subreq.io_iter }; - struct cifs_credits credits = { .value = 1, .instance = 0 }; + struct cifs_credits credits = { + .value = 1, + .instance = 0, + .rreq_debug_id = rdata->rreq->debug_id, + .rreq_debug_index = rdata->subreq.debug_index, + }; + unsigned int rreq_debug_id = rdata->rreq->debug_id; + unsigned int subreq_debug_index = rdata->subreq.debug_index; cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu\n", __func__, mid->mid, mid->mid_state, rdata->result, @@ -1282,6 +1346,7 @@ cifs_readv_callback(struct mid_q_entry *mid) if (server->sign) { int rc = 0; + iov_iter_truncate(&rqst.rq_iter, rdata->got_bytes); rc = cifs_verify_signature(&rqst, server, mid->sequence_number); if (rc) @@ -1293,7 +1358,12 @@ cifs_readv_callback(struct mid_q_entry *mid) cifs_stats_bytes_read(tcon, rdata->got_bytes); break; case MID_REQUEST_SUBMITTED: + trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_req_submitted); + goto do_retry; case MID_RETRY_NEEDED: + trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_retry_needed); +do_retry: + __set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags); rdata->result = -EAGAIN; if (server->sign && rdata->got_bytes) /* reset bytes number since we can not check a sign */ @@ -1302,19 +1372,61 @@ cifs_readv_callback(struct mid_q_entry *mid) task_io_account_read(rdata->got_bytes); cifs_stats_bytes_read(tcon, rdata->got_bytes); break; + case MID_RESPONSE_MALFORMED: + trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_malformed); + rdata->result = smb_EIO(smb_eio_trace_read_rsp_malformed); + break; default: - rdata->result = -EIO; + trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_unknown); + rdata->result = smb_EIO1(smb_eio_trace_read_mid_state_unknown, + mid->mid_state); + break; } - if (rdata->result == 0 || rdata->result == -EAGAIN) - iov_iter_advance(&rdata->subreq.io_iter, rdata->got_bytes); + if (rdata->result == -ENODATA) { + rdata->result = 0; + __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); + trace_smb3_read_err(rdata->rreq->debug_id, + rdata->subreq.debug_index, + rdata->xid, + rdata->req->cfile->fid.persistent_fid, + tcon->tid, tcon->ses->Suid, + rdata->subreq.start + rdata->subreq.transferred, + rdata->subreq.len - rdata->subreq.transferred, + rdata->result); + } else { + size_t trans = rdata->subreq.transferred + rdata->got_bytes; + if (trans < rdata->subreq.len && + rdata->subreq.start + trans >= ictx->remote_i_size) { + rdata->result = 0; + __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); + } else if (rdata->got_bytes > 0) { + __set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags); + } + if (rdata->got_bytes) + __set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags); + trace_smb3_read_done(rdata->rreq->debug_id, + rdata->subreq.debug_index, + rdata->xid, + rdata->req->cfile->fid.persistent_fid, + tcon->tid, tcon->ses->Suid, + rdata->subreq.start + rdata->subreq.transferred, + rdata->got_bytes); + } + + trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, rdata->credits.value, + server->credits, server->in_flight, + 0, cifs_trace_rw_credits_read_response_clear); rdata->credits.value = 0; - netfs_subreq_terminated(&rdata->subreq, - (rdata->result == 0 || rdata->result == -EAGAIN) ? - rdata->got_bytes : rdata->result, - false); - release_mid(mid); + rdata->subreq.error = rdata->result; + rdata->subreq.transferred += rdata->got_bytes; + trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress); + netfs_read_subreq_terminated(&rdata->subreq); + release_mid(server, mid); add_credits(server, &credits, 0); + trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0, + server->credits, server->in_flight, + credits.value, cifs_trace_rw_credits_read_response_add); } /* cifs_async_readv - send an async write, and set up mid to handle result */ @@ -1326,7 +1438,8 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) int wct; struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink); struct smb_rqst rqst = { .rq_iov = rdata->iov, - .rq_nvec = 2 }; + .rq_nvec = 1 }; + unsigned int in_len; cifs_dbg(FYI, "%s: offset=%llu bytes=%zu\n", __func__, rdata->subreq.start, rdata->subreq.len); @@ -1337,13 +1450,14 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) wct = 10; /* old style read */ if ((rdata->subreq.start >> 32) > 0) { /* can not handle this big offset for old */ - return -EIO; + return smb_EIO(smb_eio_trace_read_too_far); } } rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb); - if (rc) + if (rc < 0) return rc; + in_len = rc; smb->hdr.Pid = cpu_to_le16((__u16)rdata->req->pid); smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->req->pid >> 16)); @@ -1367,9 +1481,14 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) /* 4 for RFC1001 length + 1 for BCC */ rdata->iov[0].iov_base = smb; - rdata->iov[0].iov_len = 4; - rdata->iov[1].iov_base = (char *)smb + 4; - rdata->iov[1].iov_len = get_rfc1002_length(smb); + rdata->iov[0].iov_len = in_len; + + trace_smb3_read_enter(rdata->rreq->debug_id, + rdata->subreq.debug_index, + rdata->xid, + rdata->req->cfile->fid.netfid, + tcon->tid, tcon->ses->Suid, + rdata->subreq.start, rdata->subreq.len); rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive, cifs_readv_callback, NULL, rdata, 0, NULL); @@ -1396,6 +1515,7 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms, __u16 netfid = io_parms->netfid; __u64 offset = io_parms->offset; struct cifs_tcon *tcon = io_parms->tcon; + unsigned int in_len; unsigned int count = io_parms->length; cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid); @@ -1405,14 +1525,15 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms, wct = 10; /* old style read */ if ((offset >> 32) > 0) { /* can not handle this big offset for old */ - return -EIO; + return smb_EIO(smb_eio_trace_read_too_far); } } *nbytes = 0; rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB); - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->hdr.Pid = cpu_to_le16((__u16)pid); pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); @@ -1440,7 +1561,7 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms, } iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; + iov[0].iov_len = in_len; rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type, CIFS_LOG_ERROR, &rsp_iov); cifs_small_buf_release(pSMB); @@ -1459,7 +1580,8 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms, || (data_length > count)) { cifs_dbg(FYI, "bad length %d for count %d\n", data_length, count); - rc = -EIO; + rc = smb_EIO2(smb_eio_trace_read_overlarge, + data_length, count); *nbytes = 0; } else { pReadData = (char *) (&pSMBr->hdr.Protocol) + @@ -1504,7 +1626,7 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms, __u16 netfid = io_parms->netfid; __u64 offset = io_parms->offset; struct cifs_tcon *tcon = io_parms->tcon; - unsigned int count = io_parms->length; + unsigned int count = io_parms->length, in_len; *nbytes = 0; @@ -1518,14 +1640,15 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms, wct = 12; if ((offset >> 32) > 0) { /* can not handle big offset for old srv */ - return -EIO; + return smb_EIO(smb_eio_trace_write_too_far); } } rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->hdr.Pid = cpu_to_le16((__u16)pid); pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); @@ -1558,7 +1681,7 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms, if (bytes_sent > count) bytes_sent = count; pSMB->DataOffset = - cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4); + cpu_to_le16(offsetof(struct smb_com_write_req, Data)); if (buf) memcpy(pSMB->Data, buf, bytes_sent); else if (count != 0) { @@ -1573,7 +1696,7 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms, pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; if (wct == 14) pSMB->ByteCount = cpu_to_le16(byte_count); @@ -1584,7 +1707,7 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms, pSMBW->ByteCount = cpu_to_le16(byte_count); } - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); if (rc) { @@ -1616,12 +1739,17 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms, * workqueue completion task. */ static void -cifs_writev_callback(struct mid_q_entry *mid) +cifs_writev_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid) { struct cifs_io_subrequest *wdata = mid->callback_data; struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink); WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf; - struct cifs_credits credits = { .value = 1, .instance = 0 }; + struct cifs_credits credits = { + .value = 1, + .instance = 0, + .rreq_debug_id = wdata->rreq->debug_id, + .rreq_debug_index = wdata->subreq.debug_index, + }; ssize_t result; size_t written; @@ -1643,23 +1771,45 @@ cifs_writev_callback(struct mid_q_entry *mid) if (written > wdata->subreq.len) written &= 0xFFFF; - if (written < wdata->subreq.len) + if (written < wdata->subreq.len) { result = -ENOSPC; - else + } else { result = written; + if (written > 0) + __set_bit(NETFS_SREQ_MADE_PROGRESS, &wdata->subreq.flags); + } break; case MID_REQUEST_SUBMITTED: + trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_req_submitted); + __set_bit(NETFS_SREQ_NEED_RETRY, &wdata->subreq.flags); + result = -EAGAIN; + break; case MID_RETRY_NEEDED: + trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_retry_needed); + __set_bit(NETFS_SREQ_NEED_RETRY, &wdata->subreq.flags); result = -EAGAIN; break; + case MID_RESPONSE_MALFORMED: + trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_malformed); + result = smb_EIO(smb_eio_trace_write_rsp_malformed); + break; default: - result = -EIO; + trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_unknown); + result = smb_EIO1(smb_eio_trace_write_mid_state_unknown, + mid->mid_state); break; } + trace_smb3_rw_credits(credits.rreq_debug_id, credits.rreq_debug_index, + wdata->credits.value, + server->credits, server->in_flight, + 0, cifs_trace_rw_credits_write_response_clear); wdata->credits.value = 0; - cifs_write_subrequest_terminated(wdata, result, true); - release_mid(mid); + cifs_write_subrequest_terminated(wdata, result); + release_mid(server, mid); + trace_smb3_rw_credits(credits.rreq_debug_id, credits.rreq_debug_index, 0, + server->credits, server->in_flight, + credits.value, cifs_trace_rw_credits_write_response_add); add_credits(tcon->ses->server, &credits, 0); } @@ -1668,11 +1818,12 @@ void cifs_async_writev(struct cifs_io_subrequest *wdata) { int rc = -EACCES; - WRITE_REQ *smb = NULL; + WRITE_REQ *req = NULL; int wct; struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink); - struct kvec iov[2]; + struct kvec iov[1]; struct smb_rqst rqst = { }; + unsigned int in_len; if (tcon->ses->capabilities & CAP_LARGE_FILES) { wct = 14; @@ -1680,57 +1831,54 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) wct = 12; if (wdata->subreq.start >> 32 > 0) { /* can not handle big offset for old srv */ - rc = -EIO; + rc = smb_EIO(smb_eio_trace_write_too_far); goto out; } } - rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb); - if (rc) + rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&req); + if (rc < 0) goto async_writev_out; + in_len = rc; - smb->hdr.Pid = cpu_to_le16((__u16)wdata->req->pid); - smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->req->pid >> 16)); + req->hdr.Pid = cpu_to_le16((__u16)wdata->req->pid); + req->hdr.PidHigh = cpu_to_le16((__u16)(wdata->req->pid >> 16)); - smb->AndXCommand = 0xFF; /* none */ - smb->Fid = wdata->req->cfile->fid.netfid; - smb->OffsetLow = cpu_to_le32(wdata->subreq.start & 0xFFFFFFFF); + req->AndXCommand = 0xFF; /* none */ + req->Fid = wdata->req->cfile->fid.netfid; + req->OffsetLow = cpu_to_le32(wdata->subreq.start & 0xFFFFFFFF); if (wct == 14) - smb->OffsetHigh = cpu_to_le32(wdata->subreq.start >> 32); - smb->Reserved = 0xFFFFFFFF; - smb->WriteMode = 0; - smb->Remaining = 0; + req->OffsetHigh = cpu_to_le32(wdata->subreq.start >> 32); + req->Reserved = 0xFFFFFFFF; + req->WriteMode = 0; + req->Remaining = 0; - smb->DataOffset = - cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4); + req->DataOffset = + cpu_to_le16(offsetof(struct smb_com_write_req, Data)); - /* 4 for RFC1001 length + 1 for BCC */ - iov[0].iov_len = 4; - iov[0].iov_base = smb; - iov[1].iov_len = get_rfc1002_length(smb) + 1; - iov[1].iov_base = (char *)smb + 4; + iov[0].iov_base = req; + iov[0].iov_len = in_len + 1; /* +1 for BCC */ rqst.rq_iov = iov; - rqst.rq_nvec = 2; + rqst.rq_nvec = 1; rqst.rq_iter = wdata->subreq.io_iter; - rqst.rq_iter_size = iov_iter_count(&wdata->subreq.io_iter); cifs_dbg(FYI, "async write at %llu %zu bytes\n", wdata->subreq.start, wdata->subreq.len); - smb->DataLengthLow = cpu_to_le16(wdata->subreq.len & 0xFFFF); - smb->DataLengthHigh = cpu_to_le16(wdata->subreq.len >> 16); + req->DataLengthLow = cpu_to_le16(wdata->subreq.len & 0xFFFF); + req->DataLengthHigh = cpu_to_le16(wdata->subreq.len >> 16); if (wct == 14) { - inc_rfc1001_len(&smb->hdr, wdata->subreq.len + 1); - put_bcc(wdata->subreq.len + 1, &smb->hdr); + in_len += wdata->subreq.len + 1; + put_bcc(wdata->subreq.len + 1, &req->hdr); } else { /* wct == 12 */ - struct smb_com_writex_req *smbw = - (struct smb_com_writex_req *)smb; - inc_rfc1001_len(&smbw->hdr, wdata->subreq.len + 5); - put_bcc(wdata->subreq.len + 5, &smbw->hdr); - iov[1].iov_len += 4; /* pad bigger by four bytes */ + struct smb_com_writex_req *reqw = + (struct smb_com_writex_req *)req; + in_len += wdata->subreq.len + 5; + put_bcc(wdata->subreq.len + 5, &reqw->hdr); + iov[0].iov_len += 4; /* pad bigger by four bytes */ } rc = cifs_call_async(tcon->ses->server, &rqst, NULL, @@ -1740,11 +1888,11 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); async_writev_out: - cifs_small_buf_release(smb); + cifs_small_buf_release(req); out: if (rc) { add_credits_and_wake_if(wdata->server, &wdata->credits, 0); - cifs_write_subrequest_terminated(wdata, rc, false); + cifs_write_subrequest_terminated(wdata, rc); } } @@ -1763,6 +1911,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms, struct cifs_tcon *tcon = io_parms->tcon; unsigned int count = io_parms->length; struct kvec rsp_iov; + unsigned int in_len; *nbytes = 0; @@ -1774,12 +1923,13 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms, wct = 12; if ((offset >> 32) > 0) { /* can not handle big offset for old srv */ - return -EIO; + return smb_EIO(smb_eio_trace_write_too_far); } } rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB); - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->hdr.Pid = cpu_to_le16((__u16)pid); pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); @@ -1798,16 +1948,16 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms, pSMB->Remaining = 0; pSMB->DataOffset = - cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4); + cpu_to_le16(offsetof(struct smb_com_write_req, Data)); pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF); pSMB->DataLengthHigh = cpu_to_le16(count >> 16); /* header + 1 byte pad */ - smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1; + smb_hdr_len = in_len + 1; if (wct == 14) - inc_rfc1001_len(pSMB, count + 1); + in_len += count + 1; else /* wct == 12 */ - inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */ + in_len += count + 5; /* smb data starts later */ if (wct == 14) pSMB->ByteCount = cpu_to_le16(count + 1); else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ { @@ -1829,7 +1979,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms, cifs_dbg(FYI, "Send error Write2 = %d\n", rc); } else if (resp_buf_type == 0) { /* presumably this can not happen, but best to be safe */ - rc = -EIO; + rc = smb_EIO1(smb_eio_trace_write_bad_buf_type, resp_buf_type); } else { WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base; *nbytes = le16_to_cpu(pSMBr->CountHigh); @@ -1861,6 +2011,7 @@ int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon, LOCK_REQ *pSMB = NULL; struct kvec iov[2]; struct kvec rsp_iov; + unsigned int in_len; int resp_buf_type; __u16 count; @@ -1868,8 +2019,9 @@ int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon, num_lock, num_unlock); rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->Timeout = 0; pSMB->NumberOfLocks = cpu_to_le16(num_lock); @@ -1879,11 +2031,11 @@ int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon, pSMB->Fid = netfid; /* netfid stays le */ count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); - inc_rfc1001_len(pSMB, count); + in_len += count; pSMB->ByteCount = cpu_to_le16(count); iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 - + iov[0].iov_len = in_len - (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); iov[1].iov_base = (char *)buf; iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); @@ -1908,16 +2060,18 @@ CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon, int rc = 0; LOCK_REQ *pSMB = NULL; /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */ + unsigned int in_len; int bytes_returned; - int flags = 0; + int flags = CIFS_WINDOWS_LOCK | CIFS_INTERRUPTIBLE_WAIT; __u16 count; cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n", (int)waitFlag, numLock); rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) { /* no response expected */ @@ -1949,14 +2103,15 @@ CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon, /* oplock break */ count = 0; } - inc_rfc1001_len(pSMB, count); + in_len += count; pSMB->ByteCount = cpu_to_le16(count); if (waitFlag) - rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, - (struct smb_hdr *) pSMB, &bytes_returned); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, + (struct smb_hdr *) pSMB, &bytes_returned, + flags); else - rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, in_len, flags); cifs_small_buf_release(pSMB); cifs_stats_inc(&tcon->stats.cifs_stats.num_locks); if (rc) @@ -1977,8 +2132,9 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon, struct smb_com_transaction2_sfi_req *pSMB = NULL; struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; struct cifs_posix_lock *parm_data; + unsigned int in_len; int rc = 0; - int timeout = 0; + int sr_flags = CIFS_INTERRUPTIBLE_WAIT; int bytes_returned = 0; int resp_buf_type = 0; __u16 params, param_offset, offset, byte_count, count; @@ -1988,9 +2144,9 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon, cifs_dbg(FYI, "Posix Lock\n"); rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); - - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB; @@ -1999,7 +2155,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon, pSMB->Reserved = 0; pSMB->Flags = 0; pSMB->Reserved2 = 0; - param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; + param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid); offset = param_offset + params; count = sizeof(struct cifs_posix_lock); @@ -2017,13 +2173,11 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon, pSMB->TotalDataCount = pSMB->DataCount; pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->ParameterOffset = cpu_to_le16(param_offset); - /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ - parm_data = (struct cifs_posix_lock *) - (((char *)pSMB) + offset + 4); + parm_data = (struct cifs_posix_lock *)(((char *)pSMB) + offset); parm_data->lock_type = cpu_to_le16(lock_type); if (waitFlag) { - timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */ + sr_flags |= CIFS_BLOCKING_OP; /* blocking operation, no timeout */ parm_data->lock_flags = cpu_to_le16(1); pSMB->Timeout = cpu_to_le32(-1); } else @@ -2037,16 +2191,17 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon, pSMB->Fid = smb_file_id; pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); if (waitFlag) { - rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, - (struct smb_hdr *) pSMBr, &bytes_returned); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, + (struct smb_hdr *) pSMBr, &bytes_returned, + sr_flags); } else { iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; + iov[0].iov_len = in_len; rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, - &resp_buf_type, timeout, &rsp_iov); + &resp_buf_type, sr_flags, &rsp_iov); pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base; } cifs_small_buf_release(pSMB); @@ -2060,13 +2215,15 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon, rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) { - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_lock_bcc_too_small, + get_bcc(&pSMBr->hdr), sizeof(*parm_data)); goto plk_err_exit; } data_offset = le16_to_cpu(pSMBr->t2.DataOffset); data_count = le16_to_cpu(pSMBr->t2.DataCount); if (data_count < sizeof(struct cifs_posix_lock)) { - rc = -EIO; + rc = smb_EIO2(smb_eio_trace_lock_data_too_small, + data_count, sizeof(struct cifs_posix_lock)); goto plk_err_exit; } parm_data = (struct cifs_posix_lock *) @@ -2104,19 +2261,22 @@ CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id) { int rc = 0; CLOSE_REQ *pSMB = NULL; + unsigned int in_len; + cifs_dbg(FYI, "In CIFSSMBClose\n"); /* do not retry on dead session on close */ rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB); if (rc == -EAGAIN) return 0; - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->FileID = (__u16) smb_file_id; pSMB->LastWriteTime = 0xFFFFFFFF; pSMB->ByteCount = 0; - rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, in_len, 0); cifs_small_buf_release(pSMB); cifs_stats_inc(&tcon->stats.cifs_stats.num_closes); if (rc) { @@ -2138,15 +2298,18 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id) { int rc = 0; FLUSH_REQ *pSMB = NULL; + unsigned int in_len; + cifs_dbg(FYI, "In CIFSSMBFlush\n"); rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB); - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->FileID = (__u16) smb_file_id; pSMB->ByteCount = 0; - rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, in_len, 0); cifs_small_buf_release(pSMB); cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes); if (rc) @@ -2163,6 +2326,7 @@ int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, int rc = 0; RENAME_REQ *pSMB = NULL; RENAME_RSP *pSMBr = NULL; + unsigned int in_len; int bytes_returned; int name_len, name_len2; __u16 count; @@ -2172,8 +2336,9 @@ int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon, renameRetry: rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->BufferFormat = 0x04; pSMB->SearchAttributes = @@ -2203,10 +2368,10 @@ renameRetry: } count = 1 /* 1st signature byte */ + name_len + name_len2; - inc_rfc1001_len(pSMB, count); + in_len += count; pSMB->ByteCount = cpu_to_le16(count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); cifs_stats_inc(&tcon->stats.cifs_stats.num_renames); if (rc) @@ -2227,6 +2392,7 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, struct smb_com_transaction2_sfi_req *pSMB = NULL; struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; struct set_file_rename *rename_info; + unsigned int in_len; char *data_offset; char dummy_string[30]; int rc = 0; @@ -2237,8 +2403,9 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, cifs_dbg(FYI, "Rename to File by handle\n"); rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; params = 6; pSMB->MaxSetupCount = 0; @@ -2246,11 +2413,10 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; + param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid); offset = param_offset + params; - /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ - data_offset = (char *)(pSMB) + offset + 4; + data_offset = (char *)(pSMB) + offset; rename_info = (struct set_file_rename *) data_offset; pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */ @@ -2286,9 +2452,9 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames); if (rc) @@ -2304,75 +2470,13 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon, } int -CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon, - const char *fromName, const __u16 target_tid, const char *toName, - const int flags, const struct nls_table *nls_codepage, int remap) -{ - int rc = 0; - COPY_REQ *pSMB = NULL; - COPY_RSP *pSMBr = NULL; - int bytes_returned; - int name_len, name_len2; - __u16 count; - - cifs_dbg(FYI, "In CIFSSMBCopy\n"); -copyRetry: - rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB, - (void **) &pSMBr); - if (rc) - return rc; - - pSMB->BufferFormat = 0x04; - pSMB->Tid2 = target_tid; - - pSMB->Flags = cpu_to_le16(flags & COPY_TREE); - - if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName, - fromName, PATH_MAX, nls_codepage, - remap); - name_len++; /* trailing null */ - name_len *= 2; - pSMB->OldFileName[name_len] = 0x04; /* pad */ - /* protocol requires ASCII signature byte on Unicode string */ - pSMB->OldFileName[name_len + 1] = 0x00; - name_len2 = - cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], - toName, PATH_MAX, nls_codepage, remap); - name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; - name_len2 *= 2; /* convert to bytes */ - } else { - name_len = copy_path_name(pSMB->OldFileName, fromName); - pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ - name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName); - name_len2++; /* signature byte */ - } - - count = 1 /* 1st signature byte */ + name_len + name_len2; - inc_rfc1001_len(pSMB, count); - pSMB->ByteCount = cpu_to_le16(count); - - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *) pSMBr, &bytes_returned, 0); - if (rc) { - cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n", - rc, le16_to_cpu(pSMBr->CopyCount)); - } - cifs_buf_release(pSMB); - - if (rc == -EAGAIN) - goto copyRetry; - - return rc; -} - -int CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon, const char *fromName, const char *toName, const struct nls_table *nls_codepage, int remap) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; + unsigned int in_len; char *data_offset; int name_len; int name_len_target; @@ -2384,8 +2488,9 @@ CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon, createSymLinkRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = @@ -2405,11 +2510,10 @@ createSymLinkRetry: pSMB->Timeout = 0; pSMB->Reserved2 = 0; param_offset = offsetof(struct smb_com_transaction2_spi_req, - InformationLevel) - 4; + InformationLevel); offset = param_offset + params; - /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ - data_offset = (char *)pSMB + offset + 4; + data_offset = (char *)pSMB + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = cifsConvertToUTF16((__le16 *) data_offset, toName, @@ -2436,9 +2540,9 @@ createSymLinkRetry: pSMB->DataOffset = cpu_to_le16(offset); pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks); if (rc) @@ -2460,6 +2564,7 @@ CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; + unsigned int in_len; char *data_offset; int name_len; int name_len_target; @@ -2471,8 +2576,9 @@ CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon, createHardLinkRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName, @@ -2490,11 +2596,10 @@ createHardLinkRetry: pSMB->Timeout = 0; pSMB->Reserved2 = 0; param_offset = offsetof(struct smb_com_transaction2_spi_req, - InformationLevel) - 4; + InformationLevel); offset = param_offset + params; - /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ - data_offset = (char *)pSMB + offset + 4; + data_offset = (char *)pSMB + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = cifsConvertToUTF16((__le16 *) data_offset, fromName, @@ -2520,9 +2625,9 @@ createHardLinkRetry: pSMB->DataOffset = cpu_to_le16(offset); pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks); if (rc) @@ -2545,6 +2650,7 @@ int CIFSCreateHardLink(const unsigned int xid, int rc = 0; NT_RENAME_REQ *pSMB = NULL; RENAME_RSP *pSMBr = NULL; + unsigned int in_len; int bytes_returned; int name_len, name_len2; __u16 count; @@ -2555,8 +2661,9 @@ winCreateHardLinkRetry: rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->SearchAttributes = cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | @@ -2590,10 +2697,10 @@ winCreateHardLinkRetry: } count = 1 /* string type byte */ + name_len + name_len2; - inc_rfc1001_len(pSMB, count); + in_len += count; pSMB->ByteCount = cpu_to_le16(count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks); if (rc) @@ -2614,6 +2721,7 @@ CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, /* SMB_QUERY_FILE_UNIX_LINK */ TRANSACTION2_QPI_REQ *pSMB = NULL; TRANSACTION2_QPI_RSP *pSMBr = NULL; + unsigned int in_len; int rc = 0; int bytes_returned; int name_len; @@ -2625,8 +2733,9 @@ CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, querySymLinkRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = @@ -2649,7 +2758,7 @@ querySymLinkRetry: pSMB->Timeout = 0; pSMB->Reserved2 = 0; pSMB->ParameterOffset = cpu_to_le16(offsetof( - struct smb_com_transaction2_qpi_req, InformationLevel) - 4); + struct smb_com_transaction2_qpi_req, InformationLevel)); pSMB->DataCount = 0; pSMB->DataOffset = 0; pSMB->SetupCount = 1; @@ -2660,10 +2769,10 @@ querySymLinkRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc); @@ -2673,7 +2782,8 @@ querySymLinkRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); /* BB also check enough total bytes returned */ if (rc || get_bcc(&pSMBr->hdr) < 2) - rc = -EIO; + rc = smb_EIO2(smb_eio_trace_qsym_bcc_too_small, + get_bcc(&pSMBr->hdr), 2); else { bool is_unicode; u16 count = le16_to_cpu(pSMBr->t2.DataCount); @@ -2711,6 +2821,7 @@ int cifs_query_reparse_point(const unsigned int xid, TRANSACT_IOCTL_REQ *io_req = NULL; TRANSACT_IOCTL_RSP *io_rsp = NULL; struct cifs_fid fid; + unsigned int in_len; __u32 data_offset, data_count, len; __u8 *start, *end; int io_rsp_len; @@ -2722,6 +2833,9 @@ int cifs_query_reparse_point(const unsigned int xid, if (cap_unix(tcon->ses)) return -EOPNOTSUPP; + if (!CIFS_REPARSE_SUPPORT(tcon)) + return -EOPNOTSUPP; + oparms = (struct cifs_open_parms) { .tcon = tcon, .cifs_sb = cifs_sb, @@ -2739,15 +2853,16 @@ int cifs_query_reparse_point(const unsigned int xid, rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **)&io_req, (void **)&io_rsp); - if (rc) + if (rc < 0) goto error; + in_len = rc; io_req->TotalParameterCount = 0; io_req->TotalDataCount = 0; - io_req->MaxParameterCount = cpu_to_le32(2); + io_req->MaxParameterCount = cpu_to_le32(0); /* BB find exact data count max from sess structure BB */ io_req->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00); - io_req->MaxSetupCount = 4; + io_req->MaxSetupCount = 1; io_req->Reserved = 0; io_req->ParameterOffset = 0; io_req->DataCount = 0; @@ -2761,7 +2876,7 @@ int cifs_query_reparse_point(const unsigned int xid, io_req->Fid = fid.netfid; io_req->ByteCount = 0; - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)io_req, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)io_req, in_len, (struct smb_hdr *)io_rsp, &io_rsp_len, 0); if (rc) goto error; @@ -2770,14 +2885,35 @@ int cifs_query_reparse_point(const unsigned int xid, data_count = le32_to_cpu(io_rsp->DataCount); if (get_bcc(&io_rsp->hdr) < 2 || data_offset > 512 || !data_count || data_count > 2048) { - rc = -EIO; + rc = smb_EIO2(smb_eio_trace_qreparse_sizes_wrong, + get_bcc(&io_rsp->hdr), data_count); + goto error; + } + + /* SetupCount must be 1, otherwise offset to ByteCount is incorrect. */ + if (io_rsp->SetupCount != 1) { + rc = smb_EIO2(smb_eio_trace_qreparse_setup_count, + io_rsp->SetupCount, 1); + goto error; + } + + /* + * ReturnedDataLen is output length of executed IOCTL. + * DataCount is output length transferred over network. + * Check that we have full FSCTL_GET_REPARSE_POINT buffer. + */ + if (data_count != le16_to_cpu(io_rsp->ReturnedDataLen)) { + rc = smb_EIO2(smb_eio_trace_qreparse_ret_datalen, + data_count, le16_to_cpu(io_rsp->ReturnedDataLen)); goto error; } end = 2 + get_bcc(&io_rsp->hdr) + (__u8 *)&io_rsp->ByteCount; start = (__u8 *)&io_rsp->hdr.Protocol + data_offset; if (start >= end) { - rc = -EIO; + rc = smb_EIO2(smb_eio_trace_qreparse_data_area, + (unsigned long)start - (unsigned long)io_rsp, + (unsigned long)end - (unsigned long)io_rsp); goto error; } @@ -2786,7 +2922,8 @@ int cifs_query_reparse_point(const unsigned int xid, len = sizeof(*buf); if (data_count < len || data_count < le16_to_cpu(buf->ReparseDataLength) + len) { - rc = -EIO; + rc = smb_EIO2(smb_eio_trace_qreparse_rep_datalen, + data_count, le16_to_cpu(buf->ReparseDataLength) + len); goto error; } @@ -2803,6 +2940,129 @@ error: return rc; } +struct inode *cifs_create_reparse_inode(struct cifs_open_info_data *data, + struct super_block *sb, + const unsigned int xid, + struct cifs_tcon *tcon, + const char *full_path, + bool directory, + struct kvec *reparse_iov, + struct kvec *xattr_iov) +{ + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct cifs_open_parms oparms; + TRANSACT_IOCTL_REQ *io_req; + struct inode *new = NULL; + struct kvec in_iov[2]; + struct kvec out_iov; + struct cifs_fid fid; + unsigned int in_len; + int oplock = 0; + int buf_type = 0; + int rc; + + cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path); + + /* + * If server filesystem does not support reparse points then do not + * attempt to create reparse point. This will prevent creating unusable + * empty object on the server. + */ + if (!CIFS_REPARSE_SUPPORT(tcon)) + return ERR_PTR(-EOPNOTSUPP); + +#ifndef CONFIG_CIFS_XATTR + if (xattr_iov) + return ERR_PTR(-EOPNOTSUPP); +#endif + + oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, + FILE_READ_ATTRIBUTES | FILE_WRITE_DATA | FILE_WRITE_EA, + FILE_CREATE, + (directory ? CREATE_NOT_FILE : CREATE_NOT_DIR) | OPEN_REPARSE_POINT, + ACL_NO_MODE); + oparms.fid = &fid; + + rc = CIFS_open(xid, &oparms, &oplock, NULL); + if (rc) + return ERR_PTR(rc); + +#ifdef CONFIG_CIFS_XATTR + if (xattr_iov) { + struct smb2_file_full_ea_info *ea; + + ea = &((struct smb2_create_ea_ctx *)xattr_iov->iov_base)->ea; + while (1) { + rc = CIFSSMBSetEA(xid, + tcon, + full_path, + &ea->ea_data[0], + &ea->ea_data[ea->ea_name_length+1], + le16_to_cpu(ea->ea_value_length), + cifs_sb->local_nls, + cifs_sb); + if (rc) + goto out_close; + if (le32_to_cpu(ea->next_entry_offset) == 0) + break; + ea = (struct smb2_file_full_ea_info *)((u8 *)ea + + le32_to_cpu(ea->next_entry_offset)); + } + } +#endif + + rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **)&io_req, NULL); + if (rc < 0) + goto out_close; + in_len = rc; + in_len += sizeof(io_req->Pad); + + /* NT IOCTL response contains one-word long output setup buffer with size of output data. */ + io_req->MaxSetupCount = 1; + /* NT IOCTL response does not contain output parameters. */ + io_req->MaxParameterCount = cpu_to_le32(0); + /* FSCTL_SET_REPARSE_POINT response contains empty output data. */ + io_req->MaxDataCount = cpu_to_le32(0); + + io_req->TotalParameterCount = cpu_to_le32(0); + io_req->TotalDataCount = cpu_to_le32(reparse_iov->iov_len); + io_req->ParameterCount = io_req->TotalParameterCount; + io_req->ParameterOffset = cpu_to_le32(0); + io_req->DataCount = io_req->TotalDataCount; + io_req->DataOffset = cpu_to_le32(offsetof(typeof(*io_req), Data)); + io_req->SetupCount = 4; + io_req->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); + io_req->FunctionCode = cpu_to_le32(FSCTL_SET_REPARSE_POINT); + io_req->Fid = fid.netfid; + io_req->IsFsctl = 1; + io_req->IsRootFlag = 0; + io_req->ByteCount = cpu_to_le16(le32_to_cpu(io_req->DataCount) + sizeof(io_req->Pad)); + + in_iov[0].iov_base = (char *)io_req; + in_iov[0].iov_len = in_len; + in_iov[1] = *reparse_iov; + rc = SendReceive2(xid, tcon->ses, in_iov, ARRAY_SIZE(in_iov), &buf_type, + CIFS_NO_RSP_BUF, &out_iov); + + cifs_buf_release(io_req); + + if (!rc) + rc = cifs_get_inode_info(&new, full_path, data, sb, xid, NULL); + +out_close: + CIFSSMBClose(xid, tcon, fid.netfid); + + /* + * If CREATE was successful but FSCTL_SET_REPARSE_POINT failed then + * remove the intermediate object created by CREATE. Otherwise + * empty object stay on the server when reparse call failed. + */ + if (rc) + CIFSSMBDelFile(xid, tcon, full_path, cifs_sb, NULL); + + return rc ? ERR_PTR(rc) : new; +} + int CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid) @@ -2811,12 +3071,14 @@ CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon, int bytes_returned; struct smb_com_transaction_compr_ioctl_req *pSMB; struct smb_com_transaction_ioctl_rsp *pSMBr; + unsigned int in_len; cifs_dbg(FYI, "Set compression for %u\n", fid); rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT); @@ -2830,7 +3092,7 @@ CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon, pSMB->DataCount = cpu_to_le32(2); pSMB->DataOffset = cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req, - compression_state) - 4); /* 84 */ + compression_state)); /* 84 */ pSMB->SetupCount = 4; pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); pSMB->ParameterCount = 0; @@ -2840,9 +3102,9 @@ CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon, pSMB->Fid = fid; /* file handle always le */ /* 3 byte pad, followed by 2 byte compress state */ pSMB->ByteCount = cpu_to_le16(5); - inc_rfc1001_len(pSMB, 5); + in_len += 5; - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc); @@ -2982,7 +3244,7 @@ static void cifs_init_ace(struct cifs_posix_ace *cifs_ace, /** * posix_acl_to_cifs - convert ACLs from POSIX ACL to cifs format - * @parm_data: ACLs in cifs format to conver to + * @parm_data: ACLs in cifs format to convert to * @acl: ACLs in POSIX ACL format to convert from * @acl_type: the type of POSIX ACLs stored in @acl * @@ -3040,6 +3302,7 @@ int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon, /* SMB_QUERY_POSIX_ACL */ TRANSACTION2_QPI_REQ *pSMB = NULL; TRANSACTION2_QPI_RSP *pSMBr = NULL; + unsigned int in_len; int rc = 0; int bytes_returned; int name_len; @@ -3050,8 +3313,9 @@ int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon, queryAclRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = @@ -3078,7 +3342,7 @@ queryAclRetry: pSMB->Reserved2 = 0; pSMB->ParameterOffset = cpu_to_le16( offsetof(struct smb_com_transaction2_qpi_req, - InformationLevel) - 4); + InformationLevel)); pSMB->DataCount = 0; pSMB->DataOffset = 0; pSMB->SetupCount = 1; @@ -3089,10 +3353,10 @@ queryAclRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get); if (rc) { @@ -3103,7 +3367,8 @@ queryAclRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); /* BB also check enough total bytes returned */ if (rc || get_bcc(&pSMBr->hdr) < 2) - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_getacl_bcc_too_small, + get_bcc(&pSMBr->hdr), 2); else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); __u16 count = le16_to_cpu(pSMBr->t2.DataCount); @@ -3130,6 +3395,7 @@ int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon, { struct smb_com_transaction2_spi_req *pSMB = NULL; struct smb_com_transaction2_spi_rsp *pSMBr = NULL; + unsigned int in_len; char *parm_data; int name_len; int rc = 0; @@ -3140,8 +3406,9 @@ int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon, setAclRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, @@ -3161,9 +3428,9 @@ setAclRetry: pSMB->Timeout = 0; pSMB->Reserved2 = 0; param_offset = offsetof(struct smb_com_transaction2_spi_req, - InformationLevel) - 4; + InformationLevel); offset = param_offset + params; - parm_data = ((char *)pSMB) + sizeof(pSMB->hdr.smb_buf_length) + offset; + parm_data = ((char *)pSMB) + offset; pSMB->ParameterOffset = cpu_to_le16(param_offset); /* convert to on the wire format for POSIX ACL */ @@ -3184,9 +3451,9 @@ setAclRetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc); @@ -3222,6 +3489,7 @@ CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon, int rc = 0; struct smb_t2_qfi_req *pSMB = NULL; struct smb_t2_qfi_rsp *pSMBr = NULL; + unsigned int in_len; int bytes_returned; __u16 params, byte_count; @@ -3232,8 +3500,9 @@ CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon, GetExtAttrRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; params = 2 /* level */ + 2 /* fid */; pSMB->t2.TotalDataCount = 0; @@ -3246,7 +3515,7 @@ GetExtAttrRetry: pSMB->t2.Timeout = 0; pSMB->t2.Reserved2 = 0; pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req, - Fid) - 4); + Fid)); pSMB->t2.DataCount = 0; pSMB->t2.DataOffset = 0; pSMB->t2.SetupCount = 1; @@ -3258,10 +3527,10 @@ GetExtAttrRetry: pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS); pSMB->Pad = 0; pSMB->Fid = netfid; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->t2.ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "error %d in GetExtAttr\n", rc); @@ -3272,7 +3541,8 @@ GetExtAttrRetry: if (rc || get_bcc(&pSMBr->hdr) < 2) /* If rc should we check for EOPNOSUPP and disable the srvino flag? or in caller? */ - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_getextattr_bcc_too_small, + get_bcc(&pSMBr->hdr), 2); else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); __u16 count = le16_to_cpu(pSMBr->t2.DataCount); @@ -3280,7 +3550,8 @@ GetExtAttrRetry: if (count != 16) { cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n"); - rc = -EIO; + rc = smb_EIO2(smb_eio_trace_getextattr_inv_size, + count, 16); goto GetExtAttrOut; } pfinfo = (struct file_chattr_info *) @@ -3314,11 +3585,13 @@ smb_init_nttransact(const __u16 sub_command, const int setup_count, int rc; __u32 temp_offset; struct smb_com_ntransact_req *pSMB; + unsigned int in_len; rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon, (void **)&pSMB); - if (rc) + if (rc < 0) return rc; + in_len = rc; *ret_buf = (void *)pSMB; pSMB->Reserved = 0; pSMB->TotalParameterCount = cpu_to_le32(parm_len); @@ -3327,12 +3600,12 @@ smb_init_nttransact(const __u16 sub_command, const int setup_count, pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->DataCount = pSMB->TotalDataCount; temp_offset = offsetof(struct smb_com_ntransact_req, Parms) + - (setup_count * 2) - 4 /* for rfc1001 length itself */; + (setup_count * 2); pSMB->ParameterOffset = cpu_to_le32(temp_offset); pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len); pSMB->SetupCount = setup_count; /* no need to le convert byte fields */ pSMB->SubCommand = cpu_to_le16(sub_command); - return 0; + return in_len; } static int @@ -3391,13 +3664,14 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata, /* Get Security Descriptor (by handle) from remote server for a file or dir */ int CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, - struct cifs_ntsd **acl_inf, __u32 *pbuflen) + struct smb_ntsd **acl_inf, __u32 *pbuflen, __u32 info) { int rc = 0; int buf_type = 0; QUERY_SEC_DESC_REQ *pSMB; struct kvec iov[1]; struct kvec rsp_iov; + unsigned int in_len; cifs_dbg(FYI, "GetCifsACL\n"); @@ -3406,19 +3680,19 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, 8 /* parm len */, tcon, (void **) &pSMB); - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->MaxParameterCount = cpu_to_le32(4); /* BB TEST with big acls that might need to be e.g. larger than 16K */ pSMB->MaxSetupCount = 0; pSMB->Fid = fid; /* file handle always le */ - pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP | - CIFS_ACL_DACL); + pSMB->AclFlags = cpu_to_le32(info); pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */ - inc_rfc1001_len(pSMB, 11); + in_len += 11; iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; + iov[0].iov_len = in_len; rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0, &rsp_iov); @@ -3444,7 +3718,8 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, pSMBr, parm, *acl_inf); if (le32_to_cpu(pSMBr->ParameterCount) != 4) { - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_getcifsacl_param_count, + le32_to_cpu(pSMBr->ParameterCount), 4); *pbuflen = 0; goto qsec_out; } @@ -3461,7 +3736,7 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, /* check if buffer is big enough for the acl header followed by the smallest SID */ - if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) || + if ((*pbuflen < sizeof(struct smb_ntsd) + 8) || (*pbuflen >= 64 * 1024)) { cifs_dbg(VFS, "bad acl length %d\n", *pbuflen); rc = -EINVAL; @@ -3481,24 +3756,26 @@ qsec_out: int CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, - struct cifs_ntsd *pntsd, __u32 acllen, int aclflag) + struct smb_ntsd *pntsd, __u32 acllen, int aclflag) { __u16 byte_count, param_count, data_count, param_offset, data_offset; int rc = 0; int bytes_returned = 0; SET_SEC_DESC_REQ *pSMB = NULL; + unsigned int in_len; void *pSMBr; setCifsAclRetry: rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; param_count = 8; - param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4; + param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid); data_count = acllen; data_offset = param_offset + param_count; byte_count = 3 /* pad */ + param_count; @@ -3520,13 +3797,12 @@ setCifsAclRetry: pSMB->AclFlags = cpu_to_le32(aclflag); if (pntsd && acllen) { - memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) + - data_offset, pntsd, acllen); - inc_rfc1001_len(pSMB, byte_count + data_count); + memcpy((char *)pSMBr + data_offset, pntsd, acllen); + in_len += byte_count + data_count; } else - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n", @@ -3551,6 +3827,7 @@ SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon, { QUERY_INFORMATION_REQ *pSMB; QUERY_INFORMATION_RSP *pSMBr; + unsigned int in_len; int rc = 0; int bytes_returned; int name_len; @@ -3559,8 +3836,9 @@ SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon, QInfRetry: rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = @@ -3574,10 +3852,10 @@ QInfRetry: } pSMB->BufferFormat = 0x04; name_len++; /* account for buffer type byte */ - inc_rfc1001_len(pSMB, (__u16)name_len); + in_len += name_len; pSMB->ByteCount = cpu_to_le16(name_len); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc); @@ -3599,8 +3877,10 @@ QInfRetry: data->EndOfFile = data->AllocationSize; data->Attributes = cpu_to_le32(le16_to_cpu(pSMBr->attr)); - } else - rc = -EIO; /* bad buffer passed in */ + } else { + /* bad buffer passed in */ + rc = smb_EIO(smb_eio_trace_null_pointers); + } cifs_buf_release(pSMB); @@ -3616,6 +3896,7 @@ CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, { struct smb_t2_qfi_req *pSMB = NULL; struct smb_t2_qfi_rsp *pSMBr = NULL; + unsigned int in_len; int rc = 0; int bytes_returned; __u16 params, byte_count; @@ -3623,8 +3904,9 @@ CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, QFileInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; params = 2 /* level */ + 2 /* fid */; pSMB->t2.TotalDataCount = 0; @@ -3637,7 +3919,7 @@ QFileInfoRetry: pSMB->t2.Timeout = 0; pSMB->t2.Reserved2 = 0; pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req, - Fid) - 4); + Fid)); pSMB->t2.DataCount = 0; pSMB->t2.DataOffset = 0; pSMB->t2.SetupCount = 1; @@ -3649,10 +3931,10 @@ QFileInfoRetry: pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); pSMB->Pad = 0; pSMB->Fid = netfid; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->t2.ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc); @@ -3660,9 +3942,11 @@ QFileInfoRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc) /* BB add auto retry on EOPNOTSUPP? */ - rc = -EIO; + rc = smb_EIO2(smb_eio_trace_qfileinfo_invalid, + get_bcc(&pSMBr->hdr), 40); else if (get_bcc(&pSMBr->hdr) < 40) - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_qfileinfo_bcc_too_small, + get_bcc(&pSMBr->hdr), 40); else if (pFindData) { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); memcpy((char *) pFindData, @@ -3687,6 +3971,7 @@ CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, /* level 263 SMB_QUERY_FILE_ALL_INFO */ TRANSACTION2_QPI_REQ *pSMB = NULL; TRANSACTION2_QPI_RSP *pSMBr = NULL; + unsigned int in_len; int rc = 0; int bytes_returned; int name_len; @@ -3696,8 +3981,9 @@ CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, QPathInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = @@ -3720,7 +4006,7 @@ QPathInfoRetry: pSMB->Timeout = 0; pSMB->Reserved2 = 0; pSMB->ParameterOffset = cpu_to_le16(offsetof( - struct smb_com_transaction2_qpi_req, InformationLevel) - 4); + struct smb_com_transaction2_qpi_req, InformationLevel)); pSMB->DataCount = 0; pSMB->DataOffset = 0; pSMB->SetupCount = 1; @@ -3734,10 +4020,10 @@ QPathInfoRetry: else pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc); @@ -3745,12 +4031,15 @@ QPathInfoRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc) /* BB add auto retry on EOPNOTSUPP? */ - rc = -EIO; + rc = smb_EIO2(smb_eio_trace_qpathinfo_invalid, + get_bcc(&pSMBr->hdr), 40); else if (!legacy && get_bcc(&pSMBr->hdr) < 40) - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_qpathinfo_bcc_too_small, + get_bcc(&pSMBr->hdr), 40); else if (legacy && get_bcc(&pSMBr->hdr) < 24) - rc = -EIO; /* 24 or 26 expected but we do not read - last field */ + /* 24 or 26 expected but we do not read last field */ + rc = smb_EIO2(smb_eio_trace_qpathinfo_bcc_too_small, + get_bcc(&pSMBr->hdr), 24); else if (data) { int size; __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -3783,6 +4072,7 @@ CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, { struct smb_t2_qfi_req *pSMB = NULL; struct smb_t2_qfi_rsp *pSMBr = NULL; + unsigned int in_len; int rc = 0; int bytes_returned; __u16 params, byte_count; @@ -3790,8 +4080,9 @@ CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon, UnixQFileInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; params = 2 /* level */ + 2 /* fid */; pSMB->t2.TotalDataCount = 0; @@ -3804,7 +4095,7 @@ UnixQFileInfoRetry: pSMB->t2.Timeout = 0; pSMB->t2.Reserved2 = 0; pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req, - Fid) - 4); + Fid)); pSMB->t2.DataCount = 0; pSMB->t2.DataOffset = 0; pSMB->t2.SetupCount = 1; @@ -3816,10 +4107,10 @@ UnixQFileInfoRetry: pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); pSMB->Pad = 0; pSMB->Fid = netfid; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->t2.ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc); @@ -3828,7 +4119,8 @@ UnixQFileInfoRetry: if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n"); - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_unixqfileinfo_bcc_too_small, + get_bcc(&pSMBr->hdr), sizeof(FILE_UNIX_BASIC_INFO)); } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); memcpy((char *) pFindData, @@ -3854,6 +4146,7 @@ CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, /* SMB_QUERY_FILE_UNIX_BASIC */ TRANSACTION2_QPI_REQ *pSMB = NULL; TRANSACTION2_QPI_RSP *pSMBr = NULL; + unsigned int in_len; int rc = 0; int bytes_returned = 0; int name_len; @@ -3863,8 +4156,9 @@ CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon, UnixQPathInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = @@ -3887,7 +4181,7 @@ UnixQPathInfoRetry: pSMB->Timeout = 0; pSMB->Reserved2 = 0; pSMB->ParameterOffset = cpu_to_le16(offsetof( - struct smb_com_transaction2_qpi_req, InformationLevel) - 4); + struct smb_com_transaction2_qpi_req, InformationLevel)); pSMB->DataCount = 0; pSMB->DataOffset = 0; pSMB->SetupCount = 1; @@ -3898,10 +4192,10 @@ UnixQPathInfoRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc); @@ -3910,7 +4204,8 @@ UnixQPathInfoRetry: if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n"); - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_unixqpathinfo_bcc_too_small, + get_bcc(&pSMBr->hdr), sizeof(FILE_UNIX_BASIC_INFO)); } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); memcpy((char *) pFindData, @@ -3938,7 +4233,7 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, TRANSACTION2_FFIRST_RSP *pSMBr = NULL; T2_FFIRST_RSP_PARMS *parms; struct nls_table *nls_codepage; - unsigned int lnoff; + unsigned int in_len, lnoff; __u16 params, byte_count; int bytes_returned = 0; int name_len, remap; @@ -3949,8 +4244,9 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, findFirstRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; nls_codepage = cifs_sb->local_nls; remap = cifs_remap(cifs_sb); @@ -3959,7 +4255,7 @@ findFirstRetry: name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, PATH_MAX, nls_codepage, remap); - /* We can not add the asterik earlier in case + /* We can not add the asterisk earlier in case it got remapped to 0xF03A as if it were part of the directory name instead of a wildcard */ name_len *= 2; @@ -3973,6 +4269,12 @@ findFirstRetry: pSMB->FileName[name_len] = 0; pSMB->FileName[name_len+1] = 0; name_len += 2; + } else if (!searchName[0]) { + pSMB->FileName[0] = CIFS_DIR_SEP(cifs_sb); + pSMB->FileName[1] = 0; + pSMB->FileName[2] = 0; + pSMB->FileName[3] = 0; + name_len = 4; } } else { name_len = copy_path_name(pSMB->FileName, searchName); @@ -3984,6 +4286,10 @@ findFirstRetry: pSMB->FileName[name_len] = '*'; pSMB->FileName[name_len+1] = 0; name_len += 2; + } else if (!searchName[0]) { + pSMB->FileName[0] = CIFS_DIR_SEP(cifs_sb); + pSMB->FileName[1] = 0; + name_len = 2; } } @@ -4000,8 +4306,7 @@ findFirstRetry: pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->ParameterOffset = cpu_to_le16( - offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - - 4); + offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)); pSMB->DataCount = 0; pSMB->DataOffset = 0; pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */ @@ -4010,16 +4315,16 @@ findFirstRetry: pSMB->SearchAttributes = cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); - pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO)); + pSMB->SearchCount = cpu_to_le16(msearch ? CIFSMaxBufSize/sizeof(FILE_UNIX_INFO) : 1); pSMB->SearchFlags = cpu_to_le16(search_flags); pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); /* BB what should we set StorageType to? Does it matter? BB */ pSMB->SearchStorageType = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst); @@ -4078,7 +4383,7 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, TRANSACTION2_FNEXT_REQ *pSMB = NULL; TRANSACTION2_FNEXT_RSP *pSMBr = NULL; T2_FNEXT_RSP_PARMS *parms; - unsigned int name_len; + unsigned int name_len, in_len; unsigned int lnoff; __u16 params, byte_count; char *response_data; @@ -4092,8 +4397,9 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; params = 14; /* includes 2 bytes of null string, converted to LE below*/ byte_count = 0; @@ -4106,7 +4412,7 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, pSMB->Timeout = 0; pSMB->Reserved2 = 0; pSMB->ParameterOffset = cpu_to_le16( - offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4); + offsetof(struct smb_com_transaction2_fnext_req, SearchHandle)); pSMB->DataCount = 0; pSMB->DataOffset = 0; pSMB->SetupCount = 1; @@ -4134,10 +4440,10 @@ int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, byte_count = params + 1 /* pad */ ; pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext); @@ -4203,6 +4509,7 @@ CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon, { int rc = 0; FINDCLOSE_REQ *pSMB = NULL; + unsigned int in_len; cifs_dbg(FYI, "In CIFSSMBFindClose\n"); rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB); @@ -4211,12 +4518,13 @@ CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon, as file handle has been closed */ if (rc == -EAGAIN) return 0; - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->FileID = searchHandle; pSMB->ByteCount = 0; - rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, in_len, 0); cifs_small_buf_release(pSMB); if (rc) cifs_dbg(VFS, "Send error in FindClose = %d\n", rc); @@ -4238,6 +4546,7 @@ CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon, int rc = 0; TRANSACTION2_QPI_REQ *pSMB = NULL; TRANSACTION2_QPI_RSP *pSMBr = NULL; + unsigned int in_len; int name_len, bytes_returned; __u16 params, byte_count; @@ -4248,8 +4557,9 @@ CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon, GetInodeNumberRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = @@ -4273,7 +4583,7 @@ GetInodeNumberRetry: pSMB->Timeout = 0; pSMB->Reserved2 = 0; pSMB->ParameterOffset = cpu_to_le16(offsetof( - struct smb_com_transaction2_qpi_req, InformationLevel) - 4); + struct smb_com_transaction2_qpi_req, InformationLevel)); pSMB->DataCount = 0; pSMB->DataOffset = 0; pSMB->SetupCount = 1; @@ -4284,10 +4594,10 @@ GetInodeNumberRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc); @@ -4298,7 +4608,8 @@ GetInodeNumberRetry: if (rc || get_bcc(&pSMBr->hdr) < 2) /* If rc should we check for EOPNOSUPP and disable the srvino flag? or in caller? */ - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_getsrvinonum_bcc_too_small, + get_bcc(&pSMBr->hdr), 2); else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); __u16 count = le16_to_cpu(pSMBr->t2.DataCount); @@ -4306,7 +4617,8 @@ GetInodeNumberRetry: /* BB Do we need a cast or hash here ? */ if (count < 8) { cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n"); - rc = -EIO; + rc = smb_EIO2(smb_eio_trace_getsrvinonum_size, + count, 8); goto GetInodeNumOut; } pfinfo = (struct file_internal_info *) @@ -4330,6 +4642,7 @@ CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses, /* TRANS2_GET_DFS_REFERRAL */ TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; + unsigned int in_len; int rc = 0; int bytes_returned; int name_len; @@ -4347,10 +4660,11 @@ getDFSRetry: * CIFSGetDFSRefer() may be called from cifs_reconnect_tcon() and thus * causing an infinite recursion. */ - rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, - (void **)&pSMB, (void **)&pSMBr); - if (rc) + rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, + (void **)&pSMB, (void **)&pSMBr); + if (rc < 0) return rc; + in_len = rc; /* server pointer checked in called function, but should never be null here anyway */ @@ -4392,7 +4706,7 @@ getDFSRetry: pSMB->Timeout = 0; pSMB->Reserved2 = 0; pSMB->ParameterOffset = cpu_to_le16(offsetof( - struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4); + struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel)); pSMB->SetupCount = 1; pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL); @@ -4400,10 +4714,10 @@ getDFSRetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->MaxReferralLevel = cpu_to_le16(3); - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc); @@ -4413,7 +4727,8 @@ getDFSRetry: /* BB Also check if enough total bytes returned? */ if (rc || get_bcc(&pSMBr->hdr) < 17) { - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_getdfsrefer_bcc_too_small, + get_bcc(&pSMBr->hdr), 17); goto GetDFSRefExit; } @@ -4445,6 +4760,7 @@ SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, TRANSACTION2_QFSI_REQ *pSMB = NULL; TRANSACTION2_QFSI_RSP *pSMBr = NULL; FILE_SYSTEM_ALLOC_INFO *response_data; + unsigned int in_len; int rc = 0; int bytes_returned = 0; __u16 params, byte_count; @@ -4453,8 +4769,9 @@ SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, oldQFSInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; params = 2; /* level */ pSMB->TotalDataCount = 0; @@ -4469,17 +4786,17 @@ oldQFSInfoRetry: pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->ParameterOffset = cpu_to_le16(offsetof( - struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); + struct smb_com_transaction2_qfsi_req, InformationLevel)); 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); - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc); @@ -4487,7 +4804,8 @@ oldQFSInfoRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc || get_bcc(&pSMBr->hdr) < 18) - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_oldqfsinfo_bcc_too_small, + get_bcc(&pSMBr->hdr), 18); else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n", @@ -4531,7 +4849,8 @@ CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; TRANSACTION2_QFSI_RSP *pSMBr = NULL; - FILE_SYSTEM_INFO *response_data; + FILE_SYSTEM_SIZE_INFO *response_data; + unsigned int in_len; int rc = 0; int bytes_returned = 0; __u16 params, byte_count; @@ -4540,8 +4859,9 @@ CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, QFSInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; params = 2; /* level */ pSMB->TotalDataCount = 0; @@ -4556,17 +4876,17 @@ QFSInfoRetry: pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->ParameterOffset = cpu_to_le16(offsetof( - struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); + struct smb_com_transaction2_qfsi_req, InformationLevel)); 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_QUERY_FS_SIZE_INFO); - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc); @@ -4574,12 +4894,13 @@ QFSInfoRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc || get_bcc(&pSMBr->hdr) < 24) - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_qfsinfo_bcc_too_small, + get_bcc(&pSMBr->hdr), 24); else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); response_data = - (FILE_SYSTEM_INFO + (FILE_SYSTEM_SIZE_INFO *) (((char *) &pSMBr->hdr.Protocol) + data_offset); FSData->f_bsize = @@ -4596,7 +4917,7 @@ QFSInfoRetry: FSData->f_blocks = le64_to_cpu(response_data->TotalAllocationUnits); FSData->f_bfree = FSData->f_bavail = - le64_to_cpu(response_data->FreeAllocationUnits); + le64_to_cpu(response_data->AvailableAllocationUnits); cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n", (unsigned long long)FSData->f_blocks, (unsigned long long)FSData->f_bfree, @@ -4618,6 +4939,7 @@ CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon) TRANSACTION2_QFSI_REQ *pSMB = NULL; TRANSACTION2_QFSI_RSP *pSMBr = NULL; FILE_SYSTEM_ATTRIBUTE_INFO *response_data; + unsigned int in_len; int rc = 0; int bytes_returned = 0; __u16 params, byte_count; @@ -4626,8 +4948,9 @@ CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon) QFSAttributeRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; params = 2; /* level */ pSMB->TotalDataCount = 0; @@ -4643,17 +4966,17 @@ QFSAttributeRetry: pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->ParameterOffset = cpu_to_le16(offsetof( - struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); + struct smb_com_transaction2_qfsi_req, InformationLevel)); 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_QUERY_FS_ATTRIBUTE_INFO); - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc); @@ -4662,7 +4985,8 @@ QFSAttributeRetry: if (rc || get_bcc(&pSMBr->hdr) < 13) { /* BB also check if enough bytes returned */ - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_qfsattrinfo_bcc_too_small, + get_bcc(&pSMBr->hdr), 13); } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); response_data = @@ -4688,6 +5012,7 @@ CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon) TRANSACTION2_QFSI_REQ *pSMB = NULL; TRANSACTION2_QFSI_RSP *pSMBr = NULL; FILE_SYSTEM_DEVICE_INFO *response_data; + unsigned int in_len; int rc = 0; int bytes_returned = 0; __u16 params, byte_count; @@ -4696,8 +5021,9 @@ CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon) QFSDeviceRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; params = 2; /* level */ pSMB->TotalDataCount = 0; @@ -4713,7 +5039,7 @@ QFSDeviceRetry: pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->ParameterOffset = cpu_to_le16(offsetof( - struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); + struct smb_com_transaction2_qfsi_req, InformationLevel)); pSMB->DataCount = 0; pSMB->DataOffset = 0; @@ -4721,10 +5047,10 @@ QFSDeviceRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO); - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc); @@ -4733,7 +5059,9 @@ QFSDeviceRetry: if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_SYSTEM_DEVICE_INFO)) - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_qfsdevinfo_bcc_too_small, + get_bcc(&pSMBr->hdr), + sizeof(FILE_SYSTEM_DEVICE_INFO)); else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); response_data = @@ -4759,6 +5087,7 @@ CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon) TRANSACTION2_QFSI_REQ *pSMB = NULL; TRANSACTION2_QFSI_RSP *pSMBr = NULL; FILE_SYSTEM_UNIX_INFO *response_data; + unsigned int in_len; int rc = 0; int bytes_returned = 0; __u16 params, byte_count; @@ -4767,8 +5096,9 @@ CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon) QFSUnixRetry: rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; params = 2; /* level */ pSMB->TotalDataCount = 0; @@ -4786,15 +5116,15 @@ QFSUnixRetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->ParameterOffset = cpu_to_le16(offsetof(struct - smb_com_transaction2_qfsi_req, InformationLevel) - 4); + smb_com_transaction2_qfsi_req, InformationLevel)); pSMB->SetupCount = 1; pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO); - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc); @@ -4802,7 +5132,8 @@ QFSUnixRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc || get_bcc(&pSMBr->hdr) < 13) { - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_qfsunixinfo_bcc_too_small, + get_bcc(&pSMBr->hdr), 13); } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); response_data = @@ -4828,6 +5159,7 @@ CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap) /* level 0x200 SMB_SET_CIFS_UNIX_INFO */ TRANSACTION2_SETFSI_REQ *pSMB = NULL; TRANSACTION2_SETFSI_RSP *pSMBr = NULL; + unsigned int in_len; int rc = 0; int bytes_returned = 0; __u16 params, param_offset, offset, byte_count; @@ -4837,8 +5169,9 @@ SETFSUnixRetry: /* BB switch to small buf init to save memory */ rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; params = 4; /* 2 bytes zero followed by info level. */ pSMB->MaxSetupCount = 0; @@ -4846,8 +5179,7 @@ SETFSUnixRetry: pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - - 4; + param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum); offset = param_offset + params; pSMB->MaxParameterCount = cpu_to_le16(4); @@ -4874,10 +5206,10 @@ SETFSUnixRetry: pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION); pSMB->ClientUnixCap = cpu_to_le64(cap); - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc); @@ -4904,6 +5236,7 @@ CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon, TRANSACTION2_QFSI_REQ *pSMB = NULL; TRANSACTION2_QFSI_RSP *pSMBr = NULL; FILE_SYSTEM_POSIX_INFO *response_data; + unsigned int in_len; int rc = 0; int bytes_returned = 0; __u16 params, byte_count; @@ -4912,8 +5245,9 @@ CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon, QFSPosixRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; params = 2; /* level */ pSMB->TotalDataCount = 0; @@ -4931,15 +5265,15 @@ QFSPosixRetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->ParameterOffset = cpu_to_le16(offsetof(struct - smb_com_transaction2_qfsi_req, InformationLevel) - 4); + smb_com_transaction2_qfsi_req, InformationLevel)); pSMB->SetupCount = 1; pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO); - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc); @@ -4947,7 +5281,8 @@ QFSPosixRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc || get_bcc(&pSMBr->hdr) < 13) { - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_qfsposixinfo_bcc_too_small, + get_bcc(&pSMBr->hdr), 13); } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); response_data = @@ -5004,6 +5339,7 @@ CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon, struct smb_com_transaction2_spi_req *pSMB = NULL; struct smb_com_transaction2_spi_rsp *pSMBr = NULL; struct file_end_of_file_info *parm_data; + unsigned int in_len; int name_len; int rc = 0; int bytes_returned = 0; @@ -5015,8 +5351,9 @@ CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon, SetEOFRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = @@ -5037,7 +5374,7 @@ SetEOFRetry: pSMB->Timeout = 0; pSMB->Reserved2 = 0; param_offset = offsetof(struct smb_com_transaction2_spi_req, - InformationLevel) - 4; + InformationLevel); offset = param_offset + params; if (set_allocation) { if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) @@ -5069,10 +5406,10 @@ SetEOFRetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; parm_data->FileSize = cpu_to_le64(size); pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc); @@ -5091,15 +5428,16 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, { struct smb_com_transaction2_sfi_req *pSMB = NULL; struct file_end_of_file_info *parm_data; + unsigned int in_len; int rc = 0; __u16 params, param_offset, offset, byte_count, count; cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n", (long long)size); rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); - - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid); pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16)); @@ -5110,7 +5448,7 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; + param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid); offset = param_offset + params; count = sizeof(struct file_end_of_file_info); @@ -5126,9 +5464,8 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, pSMB->TotalDataCount = pSMB->DataCount; pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->ParameterOffset = cpu_to_le16(param_offset); - /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ parm_data = - (struct file_end_of_file_info *)(((char *)pSMB) + offset + 4); + (struct file_end_of_file_info *)(((char *)pSMB) + offset); pSMB->DataOffset = cpu_to_le16(offset); parm_data->FileSize = cpu_to_le64(size); pSMB->Fid = cfile->fid.netfid; @@ -5148,9 +5485,9 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); } pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, in_len, 0); cifs_small_buf_release(pSMB); if (rc) { cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n", @@ -5163,6 +5500,65 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +int +SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon, + const char *fileName, __le32 attributes, __le64 write_time, + const struct nls_table *nls_codepage, + struct cifs_sb_info *cifs_sb) +{ + SETATTR_REQ *pSMB; + SETATTR_RSP *pSMBr; + struct timespec64 ts; + unsigned int in_len; + int bytes_returned; + int name_len; + int rc; + + cifs_dbg(FYI, "In %s path %s\n", __func__, fileName); + +retry: + rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc < 0) + return rc; + in_len = rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifsConvertToUTF16((__le16 *) pSMB->fileName, + fileName, PATH_MAX, nls_codepage, + cifs_remap(cifs_sb)); + name_len++; /* trailing null */ + name_len *= 2; + } else { + name_len = copy_path_name(pSMB->fileName, fileName); + } + /* Only few attributes can be set by this command, others are not accepted by Win9x. */ + pSMB->attr = cpu_to_le16(le32_to_cpu(attributes) & + (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE)); + /* Zero write time value (in both NT and SETATTR formats) means to not change it. */ + if (le64_to_cpu(write_time) != 0) { + ts = cifs_NTtimeToUnix(write_time); + pSMB->last_write_time = cpu_to_le32(ts.tv_sec); + } + pSMB->BufferFormat = 0x04; + name_len++; /* account for buffer type byte */ + in_len += name_len; + pSMB->ByteCount = cpu_to_le16(name_len); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) + cifs_dbg(FYI, "Send error in %s = %d\n", __func__, rc); + + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto retry; + + return rc; +} + /* Some legacy servers such as NT4 require that the file times be set on an open handle, rather than by pathname - this is awkward due to potential access conflicts on the open, but it is unavoidable for these @@ -5174,15 +5570,16 @@ CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener) { struct smb_com_transaction2_sfi_req *pSMB = NULL; + unsigned int in_len; char *data_offset; int rc = 0; __u16 params, param_offset, offset, byte_count, count; cifs_dbg(FYI, "Set Times (via SetFileInfo)\n"); rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); - - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); @@ -5193,11 +5590,10 @@ CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; + param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid); offset = param_offset + params; - data_offset = (char *)pSMB + - offsetof(struct smb_hdr, Protocol) + offset; + data_offset = (char *)pSMB + offset; count = sizeof(FILE_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); @@ -5219,10 +5615,10 @@ CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, else pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); - rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, in_len, 0); cifs_small_buf_release(pSMB); if (rc) cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n", @@ -5239,15 +5635,16 @@ CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon, bool delete_file, __u16 fid, __u32 pid_of_opener) { struct smb_com_transaction2_sfi_req *pSMB = NULL; + unsigned int in_len; char *data_offset; int rc = 0; __u16 params, param_offset, offset, byte_count, count; cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n"); rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); - - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); @@ -5258,11 +5655,9 @@ CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon, pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; + param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid); offset = param_offset + params; - - /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ - data_offset = (char *)(pSMB) + offset + 4; + data_offset = (char *)(pSMB) + offset; count = 1; pSMB->MaxParameterCount = cpu_to_le16(2); @@ -5281,10 +5676,10 @@ CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon, pSMB->Fid = fid; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); *data_offset = delete_file ? 1 : 0; - rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, in_len, 0); cifs_small_buf_release(pSMB); if (rc) cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc); @@ -5332,6 +5727,7 @@ CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; + unsigned int in_len; int name_len; int rc = 0; int bytes_returned = 0; @@ -5344,8 +5740,9 @@ CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, SetTimesRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = @@ -5368,9 +5765,9 @@ SetTimesRetry: pSMB->Timeout = 0; pSMB->Reserved2 = 0; param_offset = offsetof(struct smb_com_transaction2_spi_req, - InformationLevel) - 4; + InformationLevel); offset = param_offset + params; - data_offset = (char *) (&pSMB->hdr.Protocol) + offset; + data_offset = (char *)pSMB + offsetof(typeof(*pSMB), hdr.Protocol) + offset; pSMB->ParameterOffset = cpu_to_le16(param_offset); pSMB->DataOffset = cpu_to_le16(offset); pSMB->SetupCount = 1; @@ -5387,10 +5784,10 @@ SetTimesRetry: else pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc); @@ -5460,15 +5857,16 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, u16 fid, u32 pid_of_opener) { struct smb_com_transaction2_sfi_req *pSMB = NULL; + unsigned int in_len; char *data_offset; int rc = 0; u16 params, param_offset, offset, byte_count, count; cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n"); rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); - - if (rc) + if (rc < 0) return rc; + in_len = rc; pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); @@ -5479,11 +5877,10 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, pSMB->Flags = 0; pSMB->Timeout = 0; pSMB->Reserved2 = 0; - param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; + param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid); offset = param_offset + params; - data_offset = (char *)pSMB + - offsetof(struct smb_hdr, Protocol) + offset; + data_offset = (char *)pSMB + offset; count = sizeof(FILE_UNIX_BASIC_INFO); @@ -5503,12 +5900,12 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon, pSMB->Fid = fid; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args); - rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0); + rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, in_len, 0); cifs_small_buf_release(pSMB); if (rc) cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n", @@ -5528,6 +5925,7 @@ CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; + unsigned int in_len; int name_len; int rc = 0; int bytes_returned = 0; @@ -5538,8 +5936,9 @@ CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon, setPermsRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = @@ -5562,10 +5961,9 @@ setPermsRetry: pSMB->Timeout = 0; pSMB->Reserved2 = 0; param_offset = offsetof(struct smb_com_transaction2_spi_req, - InformationLevel) - 4; + InformationLevel); offset = param_offset + params; - /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */ - data_offset = (FILE_UNIX_BASIC_INFO *)((char *) pSMB + offset + 4); + data_offset = (FILE_UNIX_BASIC_INFO *)((char *) pSMB + offset); memset(data_offset, 0, count); pSMB->DataOffset = cpu_to_le16(offset); pSMB->ParameterOffset = cpu_to_le16(param_offset); @@ -5579,12 +5977,12 @@ setPermsRetry: pSMB->TotalDataCount = pSMB->DataCount; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; cifs_fill_unix_set_info(data_offset, args); pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc); @@ -5616,6 +6014,7 @@ CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon, TRANSACTION2_QPI_RSP *pSMBr = NULL; int remap = cifs_remap(cifs_sb); struct nls_table *nls_codepage = cifs_sb->local_nls; + unsigned int in_len; int rc = 0; int bytes_returned; int list_len; @@ -5630,8 +6029,9 @@ CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon, QAllEAsRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { list_len = @@ -5654,7 +6054,7 @@ QAllEAsRetry: pSMB->Timeout = 0; pSMB->Reserved2 = 0; pSMB->ParameterOffset = cpu_to_le16(offsetof( - struct smb_com_transaction2_qpi_req, InformationLevel) - 4); + struct smb_com_transaction2_qpi_req, InformationLevel)); pSMB->DataCount = 0; pSMB->DataOffset = 0; pSMB->SetupCount = 1; @@ -5665,10 +6065,10 @@ QAllEAsRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc); @@ -5682,7 +6082,8 @@ QAllEAsRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc || get_bcc(&pSMBr->hdr) < 4) { - rc = -EIO; /* bad smb */ + rc = smb_EIO2(smb_eio_trace_qalleas_bcc_too_small, + get_bcc(&pSMBr->hdr), 4); goto QAllEAsOut; } @@ -5712,7 +6113,9 @@ QAllEAsRetry: end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr); if ((char *)ea_response_data + list_len > end_of_smb) { cifs_dbg(FYI, "EA list appears to go beyond SMB\n"); - rc = -EIO; + rc = smb_EIO2(smb_eio_trace_qalleas_overlong, + (unsigned long)ea_response_data + list_len - (unsigned long)pSMBr, + (unsigned long)end_of_smb - (unsigned long)pSMBr); goto QAllEAsOut; } @@ -5729,7 +6132,7 @@ QAllEAsRetry: /* make sure we can read name_len and value_len */ if (list_len < 0) { cifs_dbg(FYI, "EA entry goes beyond length of list\n"); - rc = -EIO; + rc = smb_EIO1(smb_eio_trace_qalleas_ea_overlong, list_len); goto QAllEAsOut; } @@ -5738,7 +6141,7 @@ QAllEAsRetry: list_len -= name_len + 1 + value_len; if (list_len < 0) { cifs_dbg(FYI, "EA entry goes beyond length of list\n"); - rc = -EIO; + rc = smb_EIO1(smb_eio_trace_qalleas_ea_overlong, list_len); goto QAllEAsOut; } @@ -5800,6 +6203,7 @@ CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, struct smb_com_transaction2_spi_req *pSMB = NULL; struct smb_com_transaction2_spi_rsp *pSMBr = NULL; struct fealist *parm_data; + unsigned int in_len; int name_len; int rc = 0; int bytes_returned = 0; @@ -5810,8 +6214,9 @@ CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, SetEARetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); - if (rc) + if (rc < 0) return rc; + in_len = rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = @@ -5843,12 +6248,12 @@ SetEARetry: pSMB->Timeout = 0; pSMB->Reserved2 = 0; param_offset = offsetof(struct smb_com_transaction2_spi_req, - InformationLevel) - 4; + InformationLevel); offset = param_offset + params; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_EA); - parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset; + parm_data = (void *)pSMB + offset; pSMB->ParameterOffset = cpu_to_le16(param_offset); pSMB->DataOffset = cpu_to_le16(offset); pSMB->SetupCount = 1; @@ -5877,9 +6282,9 @@ SetEARetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->Reserved4 = 0; - inc_rfc1001_len(pSMB, byte_count); + in_len += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc); |
