📄 connect.c
字号:
set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/8); if(server->ssocket) { sock_release(csocket); server->ssocket = NULL; } if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */ cifs_buf_release(smb_buffer); 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 { 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); set_current_state(TASK_INTERRUPTIBLE); /* 1/8th of sec is more than enough time for them to exit */ schedule_timeout(HZ/8); } 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 */ cFYI(1, ("Wait for exit from demultiplex thread")); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(46 * HZ); /* if threads still have not exited they are probably never coming home not much else we can do but free the memory */ } kfree(server); write_lock(&GlobalSMBSeslock); atomic_dec(&tcpSesAllocCount); length = tcpSesAllocCount.counter; write_unlock(&GlobalSMBSeslock); if(length > 0) { mempool_resize(cifs_req_poolp, length + CIFS_MIN_RCV_POOL, GFP_KERNEL); } set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/4); return 0;}static void * cifs_kcalloc(size_t size, int type){ void *addr; addr = kmalloc(size, type); if (addr) memset(addr, 0, size); return addr;}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; memset(vol->source_rfc1001_name,0x20,15); for(i=0;i < strnlen(system_utsname.nodename,15);i++) { /* does not have to be a perfect mapping since the 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(system_utsname.nodename[i]); } vol->source_rfc1001_name[15] = 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; if (!options) return 1; if(strncmp(options,"sep=",4) == 0) { if(options[4] != 0) { separator[0] = options[4]; options += 5; } else { cFYI(1,("Null separator not allowed")); } } while ((data = strsep(&options, separator)) != NULL) { if (!*data) continue; if ((value = strchr(data, '=')) != NULL) *value++ = '\0'; if (strnicmp(data, "user", 4) == 0) { if (!value || !*value) { printk(KERN_WARNING "CIFS: invalid or missing username\n"); return 1; /* needs_arg; */ } if (strnlen(value, 200) < 200) { vol->username = value; } else { printk(KERN_WARNING "CIFS: username too long\n"); return 1; } } else if (strnicmp(data, "pass", 4) == 0) { if (!value || !*value) { vol->password = NULL; continue; } temp_len = strlen(value); /* removed password length check, NTLM passwords can be arbitrarily long */ /* if comma in password, the string will be prematurely null terminated. Commas in password are specified across the cifs mount interface by a double comma ie ,, and a comma used as in other cases ie ',' as a parameter delimiter/separator is single and due to the strsep above is temporarily zeroed. */ /* NB: password legally can have multiple commas and the only illegal character in a password is null */ if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) { /* reinsert comma */ value[temp_len] = separator[0]; temp_len+=2; /* move after the second comma */ while(value[temp_len] != 0) { if((value[temp_len] == separator[0]) && (value[temp_len+1] != separator[0])) { /* single comma indicating start of next parm */ break; } temp_len++; } if(value[temp_len] == 0) { options = NULL; } else { value[temp_len] = 0; /* move options to point to start of next parm */ options = value + temp_len + 1; } /* go from value to (value + temp_len) condensing double commas to singles */ vol->password = cifs_kcalloc(temp_len, GFP_KERNEL); for(i=0,j=0;i<temp_len;i++,j++) { vol->password[j] = value[i]; if(value[i] == separator[0] && value[i+1] == separator[0]) { /* skip second comma */ i++; } } /* value[temp_len] is zeroed above so vol->password[temp_len] guaranteed to be null */ } else { vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL); strcpy(vol->password, value); } } else if (strnicmp(data, "ip", 2) == 0) { if (!value || !*value) { vol->UNCip = NULL; } else if (strnlen(value, 35) < 35) { vol->UNCip = value; } else { printk(KERN_WARNING "CIFS: ip address too long\n"); return 1; } } else if ((strnicmp(data, "unc", 3) == 0) || (strnicmp(data, "target", 6) == 0) || (strnicmp(data, "path", 4) == 0)) { if (!value || !*value) { printk(KERN_WARNING "CIFS: invalid path to network resource\n"); return 1; /* needs_arg; */ } if ((temp_len = strnlen(value, 300)) < 300) { vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); if(vol->UNC == NULL) return 1; strcpy(vol->UNC,value); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; vol->UNC[1] = '\\'; } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n"); return 1; } } else { printk(KERN_WARNING "CIFS: UNC name too long\n"); return 1; } } else if ((strnicmp(data, "domain", 3) == 0) || (strnicmp(data, "workgroup", 5) == 0)) { if (!value || !*value) { printk(KERN_WARNING "CIFS: invalid domain name\n"); return 1; /* needs_arg; */ } /* BB are there cases in which a comma can be valid in a domain name and need special handling? */ if (strnlen(value, 65) < 65) { vol->domainname = value; cFYI(1, ("Domain name set")); } else { printk(KERN_WARNING "CIFS: domain name too long\n"); return 1; } } else if (strnicmp(data, "iocharset", 9) == 0) { if (!value || !*value) { printk(KERN_WARNING "CIFS: invalid iocharset specified\n"); return 1; /* needs_arg; */ } if (strnlen(value, 65) < 65) { if(strnicmp(value,"default",7)) vol->iocharset = value; /* if iocharset not set load_nls_default used by caller */ cFYI(1, ("iocharset set to %s",value)); } else { printk(KERN_WARNING "CIFS: iocharset name too long.\n"); return 1; } } else if (strnicmp(data, "uid", 3) == 0) { if (value && *value) { vol->linux_uid = simple_strtoul(value, &value, 0); } } else if (strnicmp(data, "gid", 3) == 0) { if (value && *value) { vol->linux_gid = simple_strtoul(value, &value, 0); } } else if (strnicmp(data, "file_mode", 4) == 0) { if (value && *value) { vol->file_mode = simple_strtoul(value, &value, 0); } } else if (strnicmp(data, "dir_mode", 3) == 0) { if (value && *value) { vol->dir_mode = simple_strtoul(value, &value, 0); } } else if (strnicmp(data, "port", 4) == 0) { if (value && *value) { vol->port = simple_strtoul(value, &value, 0); } } else if (strnicmp(data, "rsize", 5) == 0) { if (value && *value) { vol->rsize = simple_strtoul(value, &value, 0); } } else if (strnicmp(data, "wsize", 5) == 0) { if (value && *value) { vol->wsize = simple_strtoul(value, &value, 0); } } else if (strnicmp(data, "sockopt", 5) == 0) { if (value && *value) { vol->sockopt = simple_strtoul(value, &value, 0); } } else if (strnicmp(data, "netbiosname", 4) == 0) { if (!value || !*value || (*value == ' ')) { cFYI(1,("invalid (empty) netbiosname specified")); } else { memset(vol->source_rfc1001_name,0x20,15); for(i=0;i<15;i++) { /* BB are there cases in which a comma can be valid in this workstation netbios name (and need special handling)? */ /* We do not uppercase netbiosname for user */ if (value[i]==0) break; else vol->source_rfc1001_name[i] = value[i]; } /* The string has 16th byte zero still from set at top of the function */ if((i==15) && (value[i] != 0)) printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n"); } } else if (strnicmp(data, "credentials", 4) == 0) { /* ignore */ } else if (strnicmp(data, "version", 3) == 0) { /* ignore */ } else if (strnicmp(data, "rw", 2) == 0) { vol->rw = TRUE; } else if ((strnicmp(data, "suid", 4) == 0) || (strnicmp(data, "nosuid", 6) == 0) || (strnicmp(data, "exec", 4) == 0) || (strnicmp(data, "noexec", 6) == 0) || (strnicmp(data, "nodev", 5) == 0) || (strnicmp(data, "noauto", 6) == 0) || (strnicmp(data, "dev", 3) == 0)) { /* The mount tool or mount.cifs helper (if present) uses these opts to set flags, and the flags are read by the kernel vfs layer before we get here (ie before read super) so there is no point trying to parse these options again and set anything and it is ok to just ignore them */ continue; } else if (strnicmp(data, "ro", 2) == 0) { vol->rw = FALSE; } else if (strnicmp(data, "hard", 4) == 0) { vol->retry = 1; } else if (strnicmp(data, "soft", 4) == 0) { vol->retry = 0; } else if (strnicmp(data, "perm", 4) == 0) { vol->noperm = 0; } else if (strnicmp(data, "noperm", 6) == 0) { vol->noperm = 1; } else if (strnicmp(data, "setuids", 7) == 0) { vol->setuids = 1; } else if (strnicmp(data, "nosetuids", 9) == 0) { vol->setuids = 0; } else if (strnicmp(data, "nohard", 6) == 0) { vol->retry = 0; } else if (strnicmp(data, "nosoft", 6) == 0) { vol->retry = 1; } else if (strnicmp(data, "nointr", 6) == 0) { vol->intr = 0; } else if (strnicmp(data, "intr", 4) == 0) { vol->intr = 1; } else if (strnicmp(data, "noac", 4) == 0) { printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); } else printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data); } if (vol->UNC == NULL) { if(devname == NULL) { printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n"); return 1; } if ((temp_len = strnlen(devname, 300)) < 300) { vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); if(vol->UNC == NULL) return 1; strcpy(vol->UNC,devname); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; vol->UNC[1] = '\\'; } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n"); return 1; } } else { printk(KERN_WARNING "CIFS: UNC name too long\n"); return 1; } } if(vol->UNCip == 0) vol->UNCip = &vol->UNC[2]; return 0;}static struct cifsSesInfo *cifs_find_tcp_session(struct in_addr * target_ip_addr, struct in6_addr *target_ip6_addr, char *userName, struct TCP_Server_Info **psrvTcp){ struct list_head *tmp; struct cifsSesInfo *ses; *psrvTcp = NULL; read_lock(&GlobalSMBSeslock); list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); if (ses->server) { if((target_ip_addr && (ses->server->addr.sockAddr.sin_addr.s_addr == target_ip_addr->s_addr)) || (target_ip6_addr && memcmp(&ses->server->addr.sockAddr6.sin6_addr, target_ip6_addr,sizeof(*target_ip6_addr)))){ /* BB lock server and tcp session and increment use count here?? */ *psrvTcp = ses->server; /* found a match on the TCP session */ /* BB check if reconnection needed */ if (strncmp (ses->userName, userName, MAX_USERNAME_SIZE) == 0){ read_unlock(&GlobalSMBSeslock); return ses; /* found exact match on both tcp and SMB sessions */ } } } /* else tcp and smb sessions need reconnection */ } read_unlock(&GlobalSMBSeslock); return NULL;}static struct cifsTconInfo *find_unc(__be32 new_target_ip_addr, char *uncName, char *userName){ struct list_head *tmp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -