/* The xid serves as a useful identifier for each incoming vfs request, inasimilarwaytothemidwhichisusefultotrackeachsentsmb, andCurrentXidcanalsoprovidearunningcounter(althoughit willeventuallywrappastzero)ofthetotalvfsoperationshandled
since the cifs fs was mounted */
/* keep high water mark for number of simultaneous ops in filesystem */ if (GlobalTotalActiveXid > GlobalMaxActiveXid)
GlobalMaxActiveXid = GlobalTotalActiveXid; if (GlobalTotalActiveXid > 65000)
cifs_dbg(FYI, "warning: more than 65000 requests active\n");
xid = GlobalCurrentXid++;
spin_unlock(&GlobalMid_Lock); return xid;
}
/* clear the first few header bytes */ /* for most paths, more is cleared in header_assemble */
memset(ret_buf, 0, buf_size + 3);
atomic_inc(&buf_alloc_count); #ifdef CONFIG_CIFS_STATS2
atomic_inc(&total_buf_alloc_count); #endif/* CONFIG_CIFS_STATS2 */
return ret_buf;
}
void
cifs_buf_release(void *buf_to_free)
{ if (buf_to_free == NULL) { /* cifs_dbg(FYI, "Null buffer passed to cifs_buf_release\n");*/ return;
}
mempool_free(buf_to_free, cifs_req_poolp);
/* We could use negotiated size instead of max_msgsize - butitmaybemoreefficienttoalwaysallocsamesize albeitslightlylargerthannecessaryandmaxbuffersize
defaults to this and can not be bigger */
ret_buf = mempool_alloc(cifs_sm_req_poolp, GFP_NOFS); /* No need to clear memory here, cleared in header assemble */ /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
atomic_inc(&small_buf_alloc_count); #ifdef CONFIG_CIFS_STATS2
atomic_inc(&total_small_buf_alloc_count); #endif/* CONFIG_CIFS_STATS2 */
return ret_buf;
}
void
cifs_small_buf_release(void *buf_to_free)
{
if (buf_to_free == NULL) {
cifs_dbg(FYI, "Null buffer passed to cifs_small_buf_release\n"); return;
}
mempool_free(buf_to_free, cifs_sm_req_poolp);
/* NB: MID can not be set if treeCon not passed in, in that
case it is responsibility of caller to set the mid */ void
header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , conststruct cifs_tcon *treeCon, int word_count /* length of fixed section (word count) in two byte units */)
{ char *temp = (char *) buffer;
memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
buffer->smb_buf_length = cpu_to_be32(
(2 * word_count) + sizeof(struct smb_hdr) - 4/* RFC 1001 length field does not count */ + 2/* for bcc field itself */) ;
/* is this frame too small to even get to a BCC? */ if (total_read < 2 + sizeof(struct smb_hdr)) { if ((total_read >= sizeof(struct smb_hdr) - 1)
&& (smb->Status.CifsError != 0)) { /* it's an error return */
smb->WordCount = 0; /* some error cases do not return wct and bcc */ return0;
} elseif ((total_read == sizeof(struct smb_hdr) + 1) &&
(smb->WordCount == 0)) { char *tmp = (char *)smb; /* Need to work around a bug in two servers here */ /* First, check if the part of bcc they sent was zero */ if (tmp[sizeof(struct smb_hdr)] == 0) { /* some servers return only half of bcc *onsimpleresponses(wct,bccbothzero) *inparticularhaveseenthison *ulogoffXandFindClose.Thisleaves *onebyteofbccpotentiallyuninitialized
*/ /* zero rest of bcc */
tmp[sizeof(struct smb_hdr)+1] = 0; return0;
}
cifs_dbg(VFS, "rcvd invalid byte count (bcc)\n");
} else {
cifs_dbg(VFS, "Length less than smb header size\n");
} return -EIO;
} elseif (total_read < sizeof(*smb) + 2 * smb->WordCount) {
cifs_dbg(VFS, "%s: can't read BCC due to invalid WordCount(%u)\n",
__func__, smb->WordCount); return -EIO;
}
/* otherwise, there is enough to get to the BCC */ if (check_smb_hdr(smb)) return -EIO;
clc_len = smbCalcSize(smb);
if (4 + rfclen != total_read) {
cifs_dbg(VFS, "Length read does not match RFC1001 length %d\n",
rfclen); return -EIO;
}
if (4 + rfclen != clc_len) {
__u16 mid = get_mid(smb); /* check if bcc wrapped around for large read responses */ if ((rfclen > 64 * 1024) && (rfclen > clc_len)) { /* check if lengths match mod 64K */ if (((4 + rfclen) & 0xFFFF) == (clc_len & 0xFFFF)) return0; /* bcc wrapped */
}
cifs_dbg(FYI, "Calculated size %u vs length %u mismatch for mid=%u\n",
clc_len, 4 + rfclen, mid);
if (4 + rfclen < clc_len) {
cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=%u\n",
rfclen, mid); return -EIO;
} elseif (rfclen > clc_len + 512) { /* *Someservers(WindowsXPinparticular)sendmore *datathanthelengthsintheSMBpacketwould *indicateoncertaincalls(byterangelocksand *trans2findfirstcallsinparticular).Whilethe *clientcanhandlesuchaframebyignoringthe *trailingdata,wechooselimittheamountofextra *datato512bytes.
*/
cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for mid=%u\n",
rfclen, mid); return -EIO;
}
} return0;
}
cifs_dbg(FYI, "Checking for oplock break or dnotify response\n"); if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
(pSMB->hdr.Flags & SMBFLG_RESPONSE)) { struct smb_com_transaction_change_notify_rsp *pSMBr =
(struct smb_com_transaction_change_notify_rsp *)buf; struct file_notify_information *pnotify;
__u32 data_offset = 0;
size_t len = srv->total_read - sizeof(pSMBr->hdr.smb_buf_length);
if (get_bcc(buf) > sizeof(struct file_notify_information)) {
data_offset = le32_to_cpu(pSMBr->DataOffset);
if (data_offset >
len - sizeof(struct file_notify_information)) {
cifs_dbg(FYI, "Invalid data_offset %u\n",
data_offset); returntrue;
}
pnotify = (struct file_notify_information *)
((char *)&pSMBr->hdr.Protocol + data_offset);
cifs_dbg(FYI, "dnotify on %s Action: 0x%x\n",
pnotify->FileName, pnotify->Action); /* cifs_dump_mem("Rcvd notify Data: ",buf,
sizeof(struct smb_hdr)+60); */ returntrue;
} if (pSMBr->hdr.Status.CifsError) {
cifs_dbg(FYI, "notify err 0x%x\n",
pSMBr->hdr.Status.CifsError); returntrue;
} returnfalse;
} if (pSMB->hdr.Command != SMB_COM_LOCKING_ANDX) returnfalse; if (pSMB->hdr.Flags & SMBFLG_RESPONSE) { /* no sense logging error on invalid handle on oplock break-harmlessracebetweencloserequestandoplock breakresponseisexpectedfromtimetotimewritingout
large dirty files cached on the client */ if ((NT_STATUS_INVALID_HANDLE) ==
le32_to_cpu(pSMB->hdr.Status.CifsError)) {
cifs_dbg(FYI, "Invalid handle on oplock break\n"); returntrue;
} elseif (ERRbadfid ==
le16_to_cpu(pSMB->hdr.Status.DosError.Error)) { returntrue;
} else { returnfalse; /* on valid oplock brk we get "request" */
}
} if (pSMB->hdr.WordCount != 8) returnfalse;
cifs_dbg(FYI, "oplock type 0x%x level 0x%x\n",
pSMB->LockType, pSMB->OplockLevel); if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)) returnfalse;
/* If server is a channel, select the primary channel */
pserver = SERVER_IS_CHAN(srv) ? srv->primary_server : srv;
/* look up tcon based on tid & uid */
spin_lock(&cifs_tcp_ses_lock);
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { if (cifs_ses_exiting(ses)) continue;
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { if (tcon->tid != buf->Tid) continue;
if (cifs_sb->master_tlink)
tcon = cifs_sb_master_tcon(cifs_sb);
cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
cifs_sb->mnt_cifs_serverino_autodisabled = true;
cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s\n",
tcon ? tcon->tree_name : "new server");
cifs_dbg(VFS, "The server doesn't seem to support them properly or the files might be on different servers (DFS)\n");
cifs_dbg(VFS, "Hardlinks will not be recognized on this mount. Consider mounting with the \"noserverino\" option to silence this message.\n");
/* *Wewaitforoplockbreakstobeprocessedbeforeweattempttoperform *writes.
*/ int cifs_get_writer(struct cifsInodeInfo *cinode)
{ int rc;
start:
rc = wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_OPLOCK_BREAK,
TASK_KILLABLE); if (rc) return rc;
spin_lock(&cinode->writers_lock); if (!cinode->writers)
set_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags);
cinode->writers++; /* Check to see if we have started servicing an oplock break */ if (test_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags)) {
cinode->writers--; if (cinode->writers == 0) {
clear_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags);
wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS);
}
spin_unlock(&cinode->writers_lock); goto start;
}
spin_unlock(&cinode->writers_lock); return0;
}
if (*num_of_nodes < 1) {
cifs_dbg(VFS | ONCE, "%s: [path=%s] num_referrals must be at least > 0, but we got %d\n",
__func__, searchName, *num_of_nodes);
rc = -ENOENT; goto parse_DFS_referrals_exit;
}
if (sizeof(*rsp) + *num_of_nodes * sizeof(REFERRAL3) > rsp_size) {
cifs_dbg(VFS | ONCE, "%s: malformed buffer (size is %u, must be at least %zu)\n",
__func__, rsp_size, sizeof(*rsp) + *num_of_nodes * sizeof(REFERRAL3));
rc = -EINVAL; goto parse_DFS_referrals_exit;
}
ref = (struct dfs_referral_level_3 *) &(rsp->referrals); if (ref->VersionNumber != cpu_to_le16(3)) {
cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
le16_to_cpu(ref->VersionNumber));
rc = -EINVAL; goto parse_DFS_referrals_exit;
}
/* get the upper boundary of the resp buffer */
data_end = (char *)rsp + rsp_size;
/* collect necessary data from referrals */ for (i = 0; i < *num_of_nodes; i++) { char *temp; int max_len; struct dfs_info3_param *node = (*target_nodes)+i;
/* *Givedemultiplexthreadupto10secondstoeachtargetavailablefor *reconnect--shouldbegreaterthancifssockettimeoutwhichis7 *seconds. * *On"soft"mountswewaitonce.Hardmountskeepretryinguntil *processiskilledorservercomesbackon-line.
*/ do {
rc = wait_event_interruptible_timeout(server->response_q,
(server->tcpStatus != CifsNeedReconnect),
timeout * HZ); if (rc < 0) {
cifs_dbg(FYI, "%s: aborting reconnect due to received signal\n",
__func__); return -ERESTARTSYS;
}
/* are we still trying to reconnect? */
spin_lock(&server->srv_lock); if (server->tcpStatus != CifsNeedReconnect) {
spin_unlock(&server->srv_lock); return0;
}
spin_unlock(&server->srv_lock);
} while (retry);
cifs_dbg(FYI, "%s: gave up waiting on reconnect\n", __func__); return -EHOSTDOWN;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.25 Sekunden
(vorverarbeitet am 2026-09-30)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.