summaryrefslogtreecommitdiff
path: root/fs/smb/client/cifssmb.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/smb/client/cifssmb.c')
-rw-r--r--fs/smb/client/cifssmb.c1713
1 files changed, 1048 insertions, 665 deletions
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index 25503f1a4fd2..3db1a892c526 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -24,6 +24,8 @@
#include <linux/swap.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/uaccess.h>
+#include <linux/netfs.h>
+#include <trace/events/netfs.h>
#include "cifspdu.h"
#include "cifsfs.h"
#include "cifsglob.h"
@@ -68,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
@@ -113,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
@@ -153,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) {
@@ -164,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);
@@ -210,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);
@@ -222,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
@@ -239,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;
@@ -262,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? */
@@ -274,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 */
@@ -345,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;
@@ -354,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) {
@@ -403,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;
@@ -412,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");
@@ -439,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;
@@ -479,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;
@@ -491,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;
@@ -510,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
@@ -527,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);
@@ -557,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);
}
@@ -571,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;
@@ -590,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);
@@ -611,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");
@@ -621,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);
@@ -633,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);
@@ -646,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);
@@ -667,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;
@@ -676,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 =
@@ -698,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);
@@ -720,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);
@@ -738,10 +769,11 @@ PsxDelete:
int
CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
- struct cifs_sb_info *cifs_sb)
+ struct cifs_sb_info *cifs_sb, struct dentry *dentry)
{
DELETE_FILE_REQ *pSMB = NULL;
DELETE_FILE_RSP *pSMBr = NULL;
+ unsigned int in_len;
int rc = 0;
int bytes_returned;
int name_len;
@@ -750,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,
@@ -765,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)
@@ -786,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;
@@ -795,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,
@@ -809,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)
@@ -831,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);
@@ -839,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,
@@ -853,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)
@@ -876,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;
@@ -887,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 =
@@ -910,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);
@@ -931,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);
@@ -944,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)
@@ -970,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:
@@ -1022,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
@@ -1043,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;
@@ -1050,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 */
@@ -1074,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)
@@ -1094,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) {
@@ -1127,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 */
}
}
@@ -1155,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;
@@ -1191,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);
@@ -1213,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) {
@@ -1244,13 +1303,15 @@ openRetry:
*oplock |= CIFS_CREATE_ACTION;
if (buf) {
- /* copy from CreationTime to Attributes */
- memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
+ /* copy commonly used attributes */
+ memcpy(&buf->common_attributes,
+ &rsp->common_attributes,
+ sizeof(buf->common_attributes));
/* the file_info buf is endian converted by caller */
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);
@@ -1258,20 +1319,26 @@ 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_readdata *rdata = mid->callback_data;
- struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
- struct TCP_Server_Info *server = tcon->ses->server;
+ 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 smb_rqst rqst = { .rq_iov = rdata->iov,
- .rq_nvec = 2,
- .rq_iter_size = iov_iter_count(&rdata->iter),
- .rq_iter = rdata->iter };
- struct cifs_credits credits = { .value = 1, .instance = 0 };
+ .rq_nvec = 1,
+ .rq_iter = rdata->subreq.io_iter };
+ 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=%u\n",
+ cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu\n",
__func__, mid->mid, mid->mid_state, rdata->result,
- rdata->bytes);
+ rdata->subreq.len);
switch (mid->mid_state) {
case MID_RESPONSE_RECEIVED:
@@ -1279,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)
@@ -1290,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 */
@@ -1299,54 +1372,104 @@ 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;
}
- queue_work(cifsiod_wq, &rdata->work);
- release_mid(mid);
+ 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;
+ 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 */
int
-cifs_async_readv(struct cifs_readdata *rdata)
+cifs_async_readv(struct cifs_io_subrequest *rdata)
{
int rc;
READ_REQ *smb = NULL;
int wct;
- struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
+ 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=%u\n",
- __func__, rdata->offset, rdata->bytes);
+ cifs_dbg(FYI, "%s: offset=%llu bytes=%zu\n",
+ __func__, rdata->subreq.start, rdata->subreq.len);
if (tcon->ses->capabilities & CAP_LARGE_FILES)
wct = 12;
else {
wct = 10; /* old style read */
- if ((rdata->offset >> 32) > 0) {
+ 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->pid);
- smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
+ smb->hdr.Pid = cpu_to_le16((__u16)rdata->req->pid);
+ smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->req->pid >> 16));
smb->AndXCommand = 0xFF; /* none */
- smb->Fid = rdata->cfile->fid.netfid;
- smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
+ smb->Fid = rdata->req->cfile->fid.netfid;
+ smb->OffsetLow = cpu_to_le32(rdata->subreq.start & 0xFFFFFFFF);
if (wct == 12)
- smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
+ smb->OffsetHigh = cpu_to_le32(rdata->subreq.start >> 32);
smb->Remaining = 0;
- smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
- smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
+ smb->MaxCount = cpu_to_le16(rdata->subreq.len & 0xFFFF);
+ smb->MaxCountHigh = cpu_to_le32(rdata->subreq.len >> 16);
if (wct == 12)
smb->ByteCount = 0;
else {
@@ -1358,19 +1481,20 @@ cifs_async_readv(struct cifs_readdata *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);
- kref_get(&rdata->refcount);
rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
cifs_readv_callback, NULL, rdata, 0, NULL);
if (rc == 0)
cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
- else
- kref_put(&rdata->refcount, cifs_readdata_release);
-
cifs_small_buf_release(smb);
return rc;
}
@@ -1391,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);
@@ -1400,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));
@@ -1435,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);
@@ -1454,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) +
@@ -1499,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;
@@ -1513,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));
@@ -1553,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) {
@@ -1568,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);
@@ -1579,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) {
@@ -1611,18 +1739,24 @@ 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_writedata *wdata = mid->callback_data;
- struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
- unsigned int written;
+ 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;
switch (mid->mid_state) {
case MID_RESPONSE_RECEIVED:
- wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
- if (wdata->result != 0)
+ result = cifs_check_receive(mid, tcon->ses->server, 0);
+ if (result != 0)
break;
written = le16_to_cpu(smb->CountHigh);
@@ -1634,110 +1768,132 @@ cifs_writev_callback(struct mid_q_entry *mid)
* client. OS/2 servers are known to set incorrect
* CountHigh values.
*/
- if (written > wdata->bytes)
+ if (written > wdata->subreq.len)
written &= 0xFFFF;
- if (written < wdata->bytes)
- wdata->result = -ENOSPC;
- else
- wdata->bytes = written;
+ if (written < wdata->subreq.len) {
+ result = -ENOSPC;
+ } 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:
- wdata->result = -EAGAIN;
+ 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:
- wdata->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;
}
- queue_work(cifsiod_wq, &wdata->work);
- release_mid(mid);
+ 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);
+ 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);
}
/* cifs_async_writev - send an async write, and set up mid to handle result */
-int
-cifs_async_writev(struct cifs_writedata *wdata,
- void (*release)(struct kref *kref))
+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->cfile->tlink);
- struct kvec iov[2];
+ struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
+ struct kvec iov[1];
struct smb_rqst rqst = { };
+ unsigned int in_len;
if (tcon->ses->capabilities & CAP_LARGE_FILES) {
wct = 14;
} else {
wct = 12;
- if (wdata->offset >> 32 > 0) {
+ if (wdata->subreq.start >> 32 > 0) {
/* can not handle big offset for old srv */
- return -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->pid);
- smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->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->cfile->fid.netfid;
- smb->OffsetLow = cpu_to_le32(wdata->offset & 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->offset >> 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_iter = wdata->iter;
- rqst.rq_iter_size = iov_iter_count(&wdata->iter);
+ rqst.rq_nvec = 1;
+ rqst.rq_iter = wdata->subreq.io_iter;
- cifs_dbg(FYI, "async write at %llu %u bytes\n",
- wdata->offset, wdata->bytes);
+ cifs_dbg(FYI, "async write at %llu %zu bytes\n",
+ wdata->subreq.start, wdata->subreq.len);
- smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
- smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 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->bytes + 1);
- put_bcc(wdata->bytes + 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->bytes + 5);
- put_bcc(wdata->bytes + 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 */
}
- kref_get(&wdata->refcount);
rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
cifs_writev_callback, NULL, wdata, 0, NULL);
-
+ /* Can't touch wdata if rc == 0 */
if (rc == 0)
cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
- else
- kref_put(&wdata->refcount, release);
async_writev_out:
- cifs_small_buf_release(smb);
- return rc;
+ cifs_small_buf_release(req);
+out:
+ if (rc) {
+ add_credits_and_wake_if(wdata->server, &wdata->credits, 0);
+ cifs_write_subrequest_terminated(wdata, rc);
+ }
}
int
@@ -1755,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;
@@ -1766,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));
@@ -1790,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 */ {
@@ -1821,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);
@@ -1853,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;
@@ -1860,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);
@@ -1871,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);
@@ -1900,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 */
@@ -1941,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)
@@ -1969,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;
@@ -1980,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;
@@ -1991,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);
@@ -2009,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
@@ -2029,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);
@@ -2052,32 +2215,34 @@ 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 *)
((char *)&pSMBr->hdr.Protocol + data_offset);
if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
- pLockData->fl_type = F_UNLCK;
+ pLockData->c.flc_type = F_UNLCK;
else {
if (parm_data->lock_type ==
cpu_to_le16(CIFS_RDLCK))
- pLockData->fl_type = F_RDLCK;
+ pLockData->c.flc_type = F_RDLCK;
else if (parm_data->lock_type ==
cpu_to_le16(CIFS_WRLCK))
- pLockData->fl_type = F_WRLCK;
+ pLockData->c.flc_type = F_WRLCK;
pLockData->fl_start = le64_to_cpu(parm_data->start);
pLockData->fl_end = pLockData->fl_start +
(le64_to_cpu(parm_data->length) ?
le64_to_cpu(parm_data->length) - 1 : 0);
- pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
+ pLockData->c.flc_pid = -le32_to_cpu(parm_data->pid);
}
}
@@ -2096,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) {
@@ -2130,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)
@@ -2147,14 +2318,15 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
return rc;
}
-int
-CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
- const char *from_name, const char *to_name,
- struct cifs_sb_info *cifs_sb)
+int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
+ struct dentry *source_dentry,
+ const char *from_name, const char *to_name,
+ struct cifs_sb_info *cifs_sb)
{
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;
@@ -2164,8 +2336,9 @@ 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 =
@@ -2195,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)
@@ -2219,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;
@@ -2229,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;
@@ -2238,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 */
@@ -2278,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)
@@ -2296,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;
@@ -2376,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 =
@@ -2397,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,
@@ -2428,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)
@@ -2452,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;
@@ -2463,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,
@@ -2482,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,
@@ -2512,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)
@@ -2528,14 +2641,16 @@ createHardLinkRetry:
return rc;
}
-int
-CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
- const char *from_name, const char *to_name,
- struct cifs_sb_info *cifs_sb)
+int CIFSCreateHardLink(const unsigned int xid,
+ struct cifs_tcon *tcon,
+ struct dentry *source_dentry,
+ const char *from_name, const char *to_name,
+ struct cifs_sb_info *cifs_sb)
{
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;
@@ -2546,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 |
@@ -2581,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)
@@ -2605,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;
@@ -2616,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 =
@@ -2640,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;
@@ -2651,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);
@@ -2664,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);
@@ -2690,137 +2809,258 @@ querySymLinkRetry:
return rc;
}
-/*
- * Recent Windows versions now create symlinks more frequently
- * and they use the "reparse point" mechanism below. We can of course
- * do symlinks nicely to Samba and other servers which support the
- * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
- * "MF" symlinks optionally, but for recent Windows we really need to
- * reenable the code below and fix the cifs_symlink callers to handle this.
- * In the interim this code has been moved to its own config option so
- * it is not compiled in by default until callers fixed up and more tested.
- */
-int
-CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
- __u16 fid, char **symlinkinfo,
- const struct nls_table *nls_codepage)
+int cifs_query_reparse_point(const unsigned int xid,
+ struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const char *full_path,
+ u32 *tag, struct kvec *rsp,
+ int *rsp_buftype)
{
- int rc = 0;
- int bytes_returned;
- struct smb_com_transaction_ioctl_req *pSMB;
- struct smb_com_transaction_ioctl_rsp *pSMBr;
- bool is_unicode;
- unsigned int sub_len;
- char *sub_start;
- struct reparse_symlink_data *reparse_buf;
- struct reparse_posix_data *posix_buf;
- __u32 data_offset, data_count;
- char *end_of_smb;
+ struct reparse_data_buffer *buf;
+ struct cifs_open_parms oparms;
+ 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;
+ int oplock = 0;
+ int rc;
- cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
- rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
- (void **) &pSMBr);
+ cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path);
+
+ 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,
+ .desired_access = FILE_READ_ATTRIBUTES,
+ .create_options = cifs_create_options(cifs_sb,
+ OPEN_REPARSE_POINT),
+ .disposition = FILE_OPEN,
+ .path = full_path,
+ .fid = &fid,
+ };
+
+ rc = CIFS_open(xid, &oparms, &oplock, NULL);
if (rc)
return rc;
- pSMB->TotalParameterCount = 0 ;
- pSMB->TotalDataCount = 0;
- pSMB->MaxParameterCount = cpu_to_le32(2);
+ rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon,
+ (void **)&io_req, (void **)&io_rsp);
+ if (rc < 0)
+ goto error;
+ in_len = rc;
+
+ io_req->TotalParameterCount = 0;
+ io_req->TotalDataCount = 0;
+ io_req->MaxParameterCount = cpu_to_le32(0);
/* BB find exact data count max from sess structure BB */
- pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
- pSMB->MaxSetupCount = 4;
- pSMB->Reserved = 0;
- pSMB->ParameterOffset = 0;
- pSMB->DataCount = 0;
- pSMB->DataOffset = 0;
- pSMB->SetupCount = 4;
- pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
- pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
- pSMB->IsFsctl = 1; /* FSCTL */
- pSMB->IsRootFlag = 0;
- pSMB->Fid = fid; /* file handle always le */
- pSMB->ByteCount = 0;
+ io_req->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
+ io_req->MaxSetupCount = 1;
+ io_req->Reserved = 0;
+ io_req->ParameterOffset = 0;
+ io_req->DataCount = 0;
+ io_req->DataOffset = 0;
+ io_req->SetupCount = 4;
+ io_req->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
+ io_req->ParameterCount = io_req->TotalParameterCount;
+ io_req->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
+ io_req->IsFsctl = 1;
+ io_req->IsRootFlag = 0;
+ io_req->Fid = fid.netfid;
+ io_req->ByteCount = 0;
+
+ 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;
+
+ data_offset = le32_to_cpu(io_rsp->DataOffset);
+ data_count = le32_to_cpu(io_rsp->DataCount);
+ if (get_bcc(&io_rsp->hdr) < 2 || data_offset > 512 ||
+ !data_count || data_count > 2048) {
+ rc = smb_EIO2(smb_eio_trace_qreparse_sizes_wrong,
+ get_bcc(&io_rsp->hdr), data_count);
+ goto error;
+ }
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
- goto qreparse_out;
+ /* 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;
}
- data_offset = le32_to_cpu(pSMBr->DataOffset);
- data_count = le32_to_cpu(pSMBr->DataCount);
- if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
- /* BB also check enough total bytes returned */
- rc = -EIO; /* bad smb */
- goto qreparse_out;
- }
- if (!data_count || (data_count > 2048)) {
- rc = -EIO;
- cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
- goto qreparse_out;
- }
- end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
- reparse_buf = (struct reparse_symlink_data *)
- ((char *)&pSMBr->hdr.Protocol + data_offset);
- if ((char *)reparse_buf >= end_of_smb) {
- rc = -EIO;
- goto qreparse_out;
- }
- if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
- cifs_dbg(FYI, "NFS style reparse tag\n");
- posix_buf = (struct reparse_posix_data *)reparse_buf;
-
- if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
- cifs_dbg(FYI, "unsupported file type 0x%llx\n",
- le64_to_cpu(posix_buf->InodeType));
- rc = -EOPNOTSUPP;
- goto qreparse_out;
- }
- is_unicode = true;
- sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
- if (posix_buf->PathBuffer + sub_len > end_of_smb) {
- cifs_dbg(FYI, "reparse buf beyond SMB\n");
- rc = -EIO;
- goto qreparse_out;
- }
- *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
- sub_len, is_unicode, nls_codepage);
- goto qreparse_out;
- } else if (reparse_buf->ReparseTag !=
- cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
- rc = -EOPNOTSUPP;
- goto qreparse_out;
+ /*
+ * 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;
}
- /* Reparse tag is NTFS symlink */
- sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
- reparse_buf->PathBuffer;
- sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
- if (sub_start + sub_len > end_of_smb) {
- cifs_dbg(FYI, "reparse buf beyond SMB\n");
- rc = -EIO;
- goto qreparse_out;
+ end = 2 + get_bcc(&io_rsp->hdr) + (__u8 *)&io_rsp->ByteCount;
+ start = (__u8 *)&io_rsp->hdr.Protocol + data_offset;
+ if (start >= end) {
+ 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;
+ }
+
+ data_count = le16_to_cpu(io_rsp->ByteCount);
+ buf = (struct reparse_data_buffer *)start;
+ len = sizeof(*buf);
+ if (data_count < len ||
+ data_count < le16_to_cpu(buf->ReparseDataLength) + len) {
+ rc = smb_EIO2(smb_eio_trace_qreparse_rep_datalen,
+ data_count, le16_to_cpu(buf->ReparseDataLength) + len);
+ goto error;
}
- if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
- is_unicode = true;
- else
- is_unicode = false;
-
- /* BB FIXME investigate remapping reserved chars here */
- *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
- nls_codepage);
- if (!*symlinkinfo)
- rc = -ENOMEM;
-qreparse_out:
- cifs_buf_release(pSMB);
+
+ *tag = le32_to_cpu(buf->ReparseTag);
+ rsp->iov_base = io_rsp;
+ rsp->iov_len = io_rsp_len;
+ *rsp_buftype = CIFS_LARGE_BUFFER;
+ CIFSSMBClose(xid, tcon, fid.netfid);
+ return 0;
+
+error:
+ cifs_buf_release(io_req);
+ CIFSSMBClose(xid, tcon, fid.netfid);
+ 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);
/*
- * Note: On -EAGAIN error only caller can retry on handle based calls
- * since file handle passed in no longer valid.
+ * 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.
*/
- return rc;
+ 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
@@ -2831,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);
@@ -2850,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;
@@ -2860,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);
@@ -3002,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
*
@@ -3060,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;
@@ -3070,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 =
@@ -3098,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;
@@ -3109,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) {
@@ -3123,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);
@@ -3150,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;
@@ -3160,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,
@@ -3181,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 */
@@ -3204,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);
@@ -3242,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;
@@ -3252,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;
@@ -3266,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;
@@ -3278,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);
@@ -3292,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);
@@ -3300,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 *)
@@ -3334,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);
@@ -3347,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
@@ -3411,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");
@@ -3426,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);
@@ -3464,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;
}
@@ -3481,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;
@@ -3501,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;
@@ -3540,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",
@@ -3571,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;
@@ -3579,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 =
@@ -3594,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);
@@ -3619,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);
@@ -3636,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;
@@ -3643,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;
@@ -3657,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;
@@ -3669,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);
@@ -3680,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,
@@ -3707,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;
@@ -3716,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 =
@@ -3740,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;
@@ -3754,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);
@@ -3765,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);
@@ -3803,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;
@@ -3810,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;
@@ -3824,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;
@@ -3836,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);
@@ -3848,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,
@@ -3874,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;
@@ -3883,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 =
@@ -3907,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;
@@ -3918,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);
@@ -3930,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,
@@ -3958,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;
@@ -3969,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);
@@ -3979,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;
@@ -3993,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);
@@ -4004,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;
}
}
@@ -4020,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 */
@@ -4030,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);
@@ -4098,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;
@@ -4112,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;
@@ -4126,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;
@@ -4154,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);
@@ -4223,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);
@@ -4231,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);
@@ -4258,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;
@@ -4268,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 =
@@ -4293,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;
@@ -4304,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);
@@ -4318,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);
@@ -4326,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 *)
@@ -4350,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;
@@ -4367,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 */
@@ -4412,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);
@@ -4420,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);
@@ -4433,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;
}
@@ -4465,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;
@@ -4473,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;
@@ -4489,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);
@@ -4507,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",
@@ -4551,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;
@@ -4560,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;
@@ -4576,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);
@@ -4594,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 =
@@ -4616,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,
@@ -4638,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;
@@ -4646,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;
@@ -4663,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);
@@ -4682,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 =
@@ -4708,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;
@@ -4716,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;
@@ -4733,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;
@@ -4741,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);
@@ -4753,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 =
@@ -4779,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;
@@ -4787,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;
@@ -4806,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);
@@ -4822,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 =
@@ -4848,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;
@@ -4857,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;
@@ -4866,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);
@@ -4894,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);
@@ -4924,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;
@@ -4932,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;
@@ -4951,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);
@@ -4967,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 =
@@ -5019,11 +5334,12 @@ QFSPosixRetry:
int
CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
- bool set_allocation)
+ bool set_allocation, struct dentry *dentry)
{
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;
@@ -5035,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 =
@@ -5057,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)
@@ -5089,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);
@@ -5111,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));
@@ -5130,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);
@@ -5146,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;
@@ -5168,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",
@@ -5183,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
@@ -5194,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));
@@ -5213,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);
@@ -5239,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",
@@ -5259,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));
@@ -5278,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);
@@ -5301,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);
@@ -5352,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;
@@ -5364,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 =
@@ -5388,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;
@@ -5407,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);
@@ -5480,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));
@@ -5499,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);
@@ -5523,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",
@@ -5548,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;
@@ -5558,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 =
@@ -5582,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);
@@ -5599,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);
@@ -5636,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;
@@ -5650,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 =
@@ -5674,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;
@@ -5685,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);
@@ -5702,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;
}
@@ -5732,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;
}
@@ -5749,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;
}
@@ -5758,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;
}
@@ -5820,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;
@@ -5830,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 =
@@ -5863,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;
@@ -5880,10 +6265,8 @@ SetEARetry:
parm_data->list.EA_flags = 0;
/* we checked above that name len is less than 255 */
parm_data->list.name_len = (__u8)name_len;
- /* EA names are always ASCII */
- if (ea_name)
- strncpy(parm_data->list.name, ea_name, name_len);
- parm_data->list.name[name_len] = '\0';
+ /* EA names are always ASCII and NUL-terminated */
+ strscpy(parm_data->list.name, ea_name ?: "", name_len + 1);
parm_data->list.value_len = cpu_to_le16(ea_value_len);
/* caller ensures that ea_value_len is less than 64K but
we need to ensure that it fits within the smb */
@@ -5899,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);