📄 connect.c
字号:
smb_msg.msg_controllen = 0; pdu_length = 4; /* enought to get RFC1001 header */incomplete_rcv:#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8) smb_msg.msg_iov = &iov; smb_msg.msg_iovlen = 1; length = sock_recvmsg(csocket, &smb_msg, pdu_length, 0);#else length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, pdu_length, 0 /* BB other flags? */);#endif if (kthread_should_stop()) { break; } else if (server->tcpStatus == CifsNeedReconnect) { cFYI(1, ("Reconnect after server stopped responding")); cifs_reconnect(server); cFYI(1, ("call to reconnect done")); csocket = server->ssocket; continue; } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { msleep(1); /* minimum sleep to prevent looping allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung */ continue; } else if (length <= 0) { if (server->tcpStatus == CifsNew) { cFYI(1, ("tcp session abend after SMBnegprot")); /* some servers kill the TCP session rather than returning an SMB negprot error, in which case reconnecting here is not going to help, and so simply return error to mount */ break; }#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12) if (!try_to_freeze() && (length == -EINTR)) {#else if (length == -EINTR) {#endif cFYI(1, ("cifsd thread killed")); break; } cFYI(1, ("Reconnect after unexpected peek error %d", length)); cifs_reconnect(server); csocket = server->ssocket; wake_up(&server->response_q); continue; } else if (length < 4) { cFYI(1, ("less than four bytes received (%d bytes)", length)); pdu_length -= length; msleep(1); goto incomplete_rcv; } /* The right amount was read from socket - 4 bytes */ /* so we can now interpret the length field */ /* the first byte big endian of the length field, is actually not part of the length but the type with the most common, zero, as regular data */ temp = *((char *) smb_buffer); /* Note that FC 1001 length is big endian on the wire, but we convert it here so it is always manipulated as host byte order */ pdu_length = ntohl(smb_buffer->smb_buf_length); smb_buffer->smb_buf_length = pdu_length; cFYI(1, ("rfc1002 length 0x%x", pdu_length+4)); if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) { continue; } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { cFYI(1, ("Good RFC 1002 session rsp")); continue; } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { /* we get this from Windows 98 instead of an error on SMB negprot response */ cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)", pdu_length)); if (server->tcpStatus == CifsNew) { /* if nack on negprot (rather than ret of smb negprot error) reconnecting not going to help, ret error to mount */ break; } else { /* give server a second to clean up before reconnect attempt */ msleep(1000); /* always try 445 first on reconnect since we get NACK on some if we ever connected to port 139 (the NACK is since we do not begin with RFC1001 session initialize frame) */ server->addr.sockAddr.sin_port = htons(CIFS_PORT); cifs_reconnect(server); csocket = server->ssocket; wake_up(&server->response_q); continue; } } else if (temp != (char) 0) { cERROR(1, ("Unknown RFC 1002 frame")); cifs_dump_mem(" Received Data: ", (char *)smb_buffer, length); cifs_reconnect(server); csocket = server->ssocket; continue; } /* else we have an SMB response */ if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) || (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) { cERROR(1, ("Invalid size SMB length %d pdu_length %d", length, pdu_length+4)); cifs_reconnect(server); csocket = server->ssocket; wake_up(&server->response_q); continue; } /* else length ok */ reconnect = 0; if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) { isLargeBuf = TRUE; memcpy(bigbuf, smallbuf, 4); smb_buffer = bigbuf; } length = 0; iov.iov_base = 4 + (char *)smb_buffer; iov.iov_len = pdu_length; for (total_read = 0; total_read < pdu_length; total_read += length) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8) length = sock_recvmsg(csocket, &smb_msg, pdu_length - total_read, 0);#else length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, pdu_length - total_read, 0);#endif if (kthread_should_stop() || (length == -EINTR)) { /* then will exit */ reconnect = 2; break; } else if (server->tcpStatus == CifsNeedReconnect) { cifs_reconnect(server); csocket = server->ssocket; /* Reconnect wakes up rspns q */ /* Now we will reread sock */ reconnect = 1; break; } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { msleep(1); /* minimum sleep to prevent looping, allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung*/ continue; } else if (length <= 0) { cERROR(1, ("Received no data, expecting %d", pdu_length - total_read)); cifs_reconnect(server); csocket = server->ssocket; reconnect = 1; break; } } if (reconnect == 2) break; else if (reconnect == 1) continue; length += 4; /* account for rfc1002 hdr */ dump_smb(smb_buffer, length); if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) { cifs_dump_mem("Bad SMB: ", smb_buffer, 48); continue; } task_to_wake = NULL; spin_lock(&GlobalMid_Lock); list_for_each(tmp, &server->pending_mid_q) { mid_entry = list_entry(tmp, struct mid_q_entry, qhead); if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED) && (mid_entry->command == smb_buffer->Command)) { if (check2ndT2(smb_buffer,server->maxBuf) > 0) { /* We have a multipart transact2 resp */ isMultiRsp = TRUE; if (mid_entry->resp_buf) { /* merge response - fix up 1st*/ if (coalesce_t2(smb_buffer, mid_entry->resp_buf)) { mid_entry->multiRsp = 1; break; } else { /* all parts received */ mid_entry->multiEnd = 1; goto multi_t2_fnd; } } else { if (!isLargeBuf) { cERROR(1,("1st trans2 resp needs bigbuf")); /* BB maybe we can fix this up, switch to already allocated large buffer? */ } else { /* Have first buffer */ mid_entry->resp_buf = smb_buffer; mid_entry->largeBuf = 1; bigbuf = NULL; } } break; } mid_entry->resp_buf = smb_buffer; if (isLargeBuf) mid_entry->largeBuf = 1; else mid_entry->largeBuf = 0;multi_t2_fnd: task_to_wake = mid_entry->tsk; mid_entry->midState = MID_RESPONSE_RECEIVED;#ifdef CONFIG_CIFS_STATS2 mid_entry->when_received = jiffies;#endif /* so we do not time out requests to server which is still responding (since server could be busy but not dead) */ server->lstrp = jiffies; break; } } spin_unlock(&GlobalMid_Lock); if (task_to_wake) { /* Was previous buf put in mpx struct for multi-rsp? */ if (!isMultiRsp) { /* smb buffer will be freed by user thread */ if (isLargeBuf) bigbuf = NULL; else smallbuf = NULL; } wake_up_process(task_to_wake); } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE) && (isMultiRsp == FALSE)) { cERROR(1, ("No task to wake, unknown frame received! " "NumMids %d", midCount.counter)); cifs_dump_mem("Received Data is: ", (char *)smb_buffer, sizeof(struct smb_hdr));#ifdef CONFIG_CIFS_DEBUG2 cifs_dump_detail(smb_buffer); cifs_dump_mids(server);#endif /* CIFS_DEBUG2 */ } } /* end while !EXITING */ spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; server->tsk = NULL; /* check if we have blocked requests that need to free */ /* Note that cifs_max_pending is normally 50, but can be set at module install time to as little as two */ if (atomic_read(&server->inFlight) >= cifs_max_pending) atomic_set(&server->inFlight, cifs_max_pending - 1); /* We do not want to set the max_pending too low or we could end up with the counter going negative */ spin_unlock(&GlobalMid_Lock); /* Although there should not be any requests blocked on this queue it can not hurt to be paranoid and try to wake up requests that may haven been blocked when more than 50 at time were on the wire to the same server - they now will see the session is in exit state and get out of SendReceive. */ wake_up_all(&server->request_q); /* give those requests time to exit */ msleep(125); if (server->ssocket) { sock_release(csocket); server->ssocket = NULL; }#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8) set_fs(temp_fs);#endif /* buffer usuallly freed in free_mid - need to free it here on exit */ if (bigbuf != NULL) cifs_buf_release(bigbuf); if (smallbuf != NULL) cifs_small_buf_release(smallbuf); read_lock(&GlobalSMBSeslock); if (list_empty(&server->pending_mid_q)) { /* loop through server session structures attached to this and mark them dead */ list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); if (ses->server == server) { ses->status = CifsExiting; ses->server = NULL; } } read_unlock(&GlobalSMBSeslock); } else { /* although we can not zero the server struct pointer yet, since there are active requests which may depnd on them, mark the corresponding SMB sessions as exiting too */ list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); if (ses->server == server) ses->status = CifsExiting; } spin_lock(&GlobalMid_Lock); list_for_each(tmp, &server->pending_mid_q) { mid_entry = list_entry(tmp, struct mid_q_entry, qhead); if (mid_entry->midState == MID_REQUEST_SUBMITTED) { cFYI(1, ("Clearing Mid 0x%x - waking up ", mid_entry->mid)); task_to_wake = mid_entry->tsk; if (task_to_wake) wake_up_process(task_to_wake); } } spin_unlock(&GlobalMid_Lock); read_unlock(&GlobalSMBSeslock); /* 1/8th of sec is more than enough time for them to exit */ msleep(125); } if (!list_empty(&server->pending_mid_q)) { /* mpx threads have not exited yet give them at least the smb send timeout time for long ops */ /* due to delays on oplock break requests, we need to wait at least 45 seconds before giving up on a request getting a response and going ahead and killing cifsd */ cFYI(1, ("Wait for exit from demultiplex thread")); msleep(46000); /* if threads still have not exited they are probably never coming home not much else we can do but free the memory */ } write_lock(&GlobalSMBSeslock); atomic_dec(&tcpSesAllocCount); length = tcpSesAllocCount.counter; /* last chance to mark ses pointers invalid if there are any pointing to this (e.g if a crazy root user tried to kill cifsd kernel thread explicitly this might happen) */ list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); if (ses->server == server) ses->server = NULL; } write_unlock(&GlobalSMBSeslock); kfree(server);#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) if (length > 0) mempool_resize(cifs_req_poolp, length + cifs_min_rcv, GFP_KERNEL);#endif /* BB PORT - do we need complete_and_exit here? BB */ return 0;}static intcifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol){ char *value; char *data; unsigned int temp_len, i, j; char separator[2]; separator[0] = ','; separator[1] = 0; if (Local_System_Name[0] != 0) memcpy(vol->source_rfc1001_name, Local_System_Name, 15); else {#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) char *nodename = utsname()->nodename;#else char *nodename = system_utsname.nodename;#endif int n = strnlen(nodename, 15); memset(vol->source_rfc1001_name, 0x20, 15); for (i = 0; i < n; i++) { /* does not have to be perfect mapping since field is informational, only used for servers that do not support port 445 and it can be overridden at mount time */ vol->source_rfc1001_name[i] = toupper(nodename[i]); } } vol->source_rfc1001_name[15] = 0; /* null target name indicates to use *SMBSERVR default called name if we end up sending RFC1001 session initialize */ vol->target_rfc1001_name[0] = 0; vol->linux_uid = current->uid; /* current->euid instead? */ vol->linux_gid = current->gid; vol->dir_mode = S_IRWXUGO; /* 2767 perms indicate mandatory locking support */ vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ vol->rw = TRUE; /* default is always to request posix paths. */ vol->posix_paths = 1; if (!options) return 1; if (strncmp(options, "sep=", 4) == 0) { if (options[4] != 0) { separator[0] = options[4];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -