📄 connect.c
字号:
cFYI(1, ("negotiate posix pathnames")); if (sb) CIFS_SB(sb)->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; } /* We might be setting the path sep back to a different form if we are reconnecting and the server switched its posix path capability for this share */ if (sb && (CIFS_SB(sb)->prepathlen > 0)) CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb)); if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) { if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) { CIFS_SB(sb)->rsize = 127 * 1024;#ifdef CONFIG_CIFS_DEBUG2 cFYI(1, ("larger reads not supported by srv"));#endif } } cFYI(1, ("Negotiate caps 0x%x", (int)cap));#ifdef CONFIG_CIFS_DEBUG2 if (cap & CIFS_UNIX_FCNTL_CAP) cFYI(1, ("FCNTL cap")); if (cap & CIFS_UNIX_EXTATTR_CAP) cFYI(1, ("EXTATTR cap")); if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) cFYI(1, ("POSIX path cap")); if (cap & CIFS_UNIX_XATTR_CAP) cFYI(1, ("XATTR cap")); if (cap & CIFS_UNIX_POSIX_ACL_CAP) cFYI(1, ("POSIX ACL cap")); if (cap & CIFS_UNIX_LARGE_READ_CAP) cFYI(1, ("very large read cap")); if (cap & CIFS_UNIX_LARGE_WRITE_CAP) cFYI(1, ("very large write cap"));#endif /* CIFS_DEBUG2 */ if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { if (vol_info == NULL) { cFYI(1, ("resetting capabilities failed")); } else cERROR(1, ("Negotiating Unix capabilities " "with the server failed. Consider " "mounting with the Unix Extensions\n" "disabled, if problems are found, " "by specifying the nounix mount " "option.")); } }}intcifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, char *mount_data, const char *devname){ int rc = 0; int xid; int address_type = AF_INET; struct socket *csocket = NULL; struct sockaddr_in sin_server; struct sockaddr_in6 sin_server6; struct smb_vol volume_info; struct cifsSesInfo *pSesInfo = NULL; struct cifsSesInfo *existingCifsSes = NULL; struct cifsTconInfo *tcon = NULL; struct TCP_Server_Info *srvTcp = NULL; xid = GetXid();/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ memset(&volume_info, 0, sizeof(struct smb_vol)); if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { rc = -EINVAL; goto out; } if (volume_info.nullauth) { cFYI(1, ("null user")); volume_info.username = ""; } else if (volume_info.username) { /* BB fixme parse for domain name here */ cFYI(1, ("Username: %s", volume_info.username)); } else { cifserror("No username specified"); /* In userspace mount helper we can get user name from alternate locations such as env variables and files on disk */ rc = -EINVAL; goto out; } if (volume_info.UNCip && volume_info.UNC) { rc = cifs_inet_pton(AF_INET, volume_info.UNCip, &sin_server.sin_addr.s_addr); if (rc <= 0) { /* not ipv4 address, try ipv6 */ rc = cifs_inet_pton(AF_INET6, volume_info.UNCip, &sin_server6.sin6_addr.in6_u); if (rc > 0) address_type = AF_INET6; } else { address_type = AF_INET; } if (rc <= 0) { /* we failed translating address */ rc = -EINVAL; goto out; } cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip)); /* success */ rc = 0; } else if (volume_info.UNCip) { /* BB using ip addr as server name to connect to the DFS root below */ cERROR(1, ("Connecting to DFS root not implemented yet")); rc = -EINVAL; goto out; } else /* which servers DFS root would we conect to */ { cERROR(1, ("CIFS mount error: No UNC path (e.g. -o " "unc=//192.168.1.100/public) specified")); rc = -EINVAL; goto out; } /* this is needed for ASCII cp to Unicode converts */ if (volume_info.iocharset == NULL) { cifs_sb->local_nls = load_nls_default(); /* load_nls_default can not return null */ } else { cifs_sb->local_nls = load_nls(volume_info.iocharset); if (cifs_sb->local_nls == NULL) { cERROR(1, ("CIFS mount error: iocharset %s not found", volume_info.iocharset)); rc = -ELIBACC; goto out; } } if (address_type == AF_INET) existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr, NULL /* no ipv6 addr */, volume_info.username, &srvTcp); else if (address_type == AF_INET6) { cFYI(1, ("looking for ipv6 address")); existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */, &sin_server6.sin6_addr, volume_info.username, &srvTcp); } else { rc = -EINVAL; goto out; } if (srvTcp) { cFYI(1, ("Existing tcp session with server found")); } else { /* create socket */ if (volume_info.port) sin_server.sin_port = htons(volume_info.port); else sin_server.sin_port = 0; if (address_type == AF_INET6) { cFYI(1, ("attempting ipv6 connect")); /* BB should we allow ipv6 on port 139? */ /* other OS never observed in Wild doing 139 with v6 */ rc = ipv6_connect(&sin_server6, &csocket); } else rc = ipv4_connect(&sin_server, &csocket, volume_info.source_rfc1001_name, volume_info.target_rfc1001_name); if (rc < 0) { cERROR(1, ("Error connecting to IPv4 socket. " "Aborting operation")); if (csocket != NULL) sock_release(csocket); goto out; } srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL); if (!srvTcp) { rc = -ENOMEM; sock_release(csocket); goto out; } else { memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof(struct sockaddr_in)); atomic_set(&srvTcp->inFlight, 0); /* BB Add code for ipv6 case too */ srvTcp->ssocket = csocket; srvTcp->protocolType = IPV4; srvTcp->hostname = extract_hostname(volume_info.UNC); if (IS_ERR(srvTcp->hostname)) { rc = PTR_ERR(srvTcp->hostname); sock_release(csocket); goto out; } init_waitqueue_head(&srvTcp->response_q); init_waitqueue_head(&srvTcp->request_q); INIT_LIST_HEAD(&srvTcp->pending_mid_q); /* at this point we are the only ones with the pointer to the struct since the kernel thread not created yet so no need to spinlock this init of tcpStatus */ srvTcp->tcpStatus = CifsNew; init_MUTEX(&srvTcp->tcpSem); srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd"); if (IS_ERR(srvTcp->tsk)) { rc = PTR_ERR(srvTcp->tsk); cERROR(1, ("error %d create cifsd thread", rc)); srvTcp->tsk = NULL; sock_release(csocket); kfree(srvTcp->hostname); goto out; } wait_for_completion(&cifsd_complete); rc = 0; memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name, 16); memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name, 16); srvTcp->sequence_number = 0; } } if (existingCifsSes) { pSesInfo = existingCifsSes; cFYI(1, ("Existing smb sess found")); } else if (!rc) { cFYI(1, ("Existing smb sess not found")); pSesInfo = sesInfoAlloc(); if (pSesInfo == NULL) rc = -ENOMEM; else { pSesInfo->server = srvTcp; sprintf(pSesInfo->serverName, "%u.%u.%u.%u", NIPQUAD(sin_server.sin_addr.s_addr)); } if (!rc) { /* volume_info.password freed at unmount */ if (volume_info.password) { pSesInfo->password = volume_info.password; /* set to NULL to prevent freeing on exit */ volume_info.password = NULL; } if (volume_info.username) strncpy(pSesInfo->userName, volume_info.username, MAX_USERNAME_SIZE); if (volume_info.domainname) { int len = strlen(volume_info.domainname); pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL); if (pSesInfo->domainName) strcpy(pSesInfo->domainName, volume_info.domainname); } pSesInfo->linux_uid = volume_info.linux_uid; pSesInfo->overrideSecFlg = volume_info.secFlg; down(&pSesInfo->sesSem); /* BB FIXME need to pass vol->secFlgs BB */ rc = cifs_setup_session(xid, pSesInfo, cifs_sb->local_nls); up(&pSesInfo->sesSem); if (!rc) atomic_inc(&srvTcp->socketUseCount); } } /* search for existing tcon to this server share */ if (!rc) { if (volume_info.rsize > CIFSMaxBufSize) { cERROR(1, ("rsize %d too large, using MaxBufSize", volume_info.rsize)); cifs_sb->rsize = CIFSMaxBufSize; } else if ((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize)) cifs_sb->rsize = volume_info.rsize; else /* default */ cifs_sb->rsize = CIFSMaxBufSize; if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) { cERROR(1, ("wsize %d too large, using 4096 instead", volume_info.wsize)); cifs_sb->wsize = 4096; } else if (volume_info.wsize) cifs_sb->wsize = volume_info.wsize; else cifs_sb->wsize = min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE, 127*1024); /* old default of CIFSMaxBufSize was too small now that SMB Write2 can send multiple pages in kvec. RFC1001 does not describe what happens when frame bigger than 128K is sent so use that as max in conjunction with 52K kvec constraint on arch with 4K page size */ if (cifs_sb->rsize < 2048) { cifs_sb->rsize = 2048; /* Windows ME may prefer this */ cFYI(1, ("readsize set to minimum: 2048")); } /* calculate prepath */ cifs_sb->prepath = volume_info.prepath; if (cifs_sb->prepath) { cifs_sb->prepathlen = strlen(cifs_sb->prepath); cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb); volume_info.prepath = NULL; } else cifs_sb->prepathlen = 0; cifs_sb->mnt_uid = volume_info.linux_uid; cifs_sb->mnt_gid = volume_info.linux_gid; cifs_sb->mnt_file_mode = volume_info.file_mode; cifs_sb->mnt_dir_mode = volume_info.dir_mode; cFYI(1, ("file mode: 0x%x dir mode: 0x%x", cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode)); if (volume_info.noperm) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; if (volume_info.setuids) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; if (volume_info.server_ino) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; if (volume_info.remap) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; if (volume_info.no_xattr) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; if (volume_info.sfu_emul) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; if (volume_info.nobrl) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; if (volume_info.cifs_acl) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; if (volume_info.override_uid) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; if (volume_info.override_gid) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; if (volume_info.direct_io) { cFYI(1, ("mounting share using direct i/o")); cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; } tcon = find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, volume_info.username); if (tcon) { cFYI(1, ("Found match on UNC path")); /* we can have only one retry value for a connection to a share so for resources mounted more than once to the same server share the last value passed in for the retry flag is used */ tcon->retry = volume_info.retry; tcon->nocase = volume_info.nocase; } else { tcon = tconInfoAlloc(); if (tcon == NULL) rc = -ENOMEM; else { /* check for null share name ie connecting to * dfs root */ /* BB check if this works for exactly length * three strings */ if ((strchr(volume_info.UNC + 3, '\\') == NULL) && (strchr(volume_info.UNC + 3, '/') == NULL)) { rc = connect_to_dfs_path(xid, pSesInfo, "", cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); rc = -ENODEV; goto out; } else { /* BB Do we need to wrap sesSem around * this TCon call and Unix SetFS as * we do on SessSetup and reconnect? */ rc = CIFSTCon(xid, pSesInfo, volume_info.UNC, tcon, cifs_sb->local_nls); cFYI(1, ("CIFS Tcon rc = %d", rc)); } if (!rc) { atomic_inc(&pSesInfo->inUse); tcon->retry = volume_info.retry; tcon->nocase = volume_info.nocase; } } } } if (pSesInfo) { if (pSesInfo->capabilities & CAP_LARGE_FILES) { sb->s_maxbytes = (u64) 1 << 63; } else sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */ } /* BB FIXME fix time_gran to be larger for LANMAN sessions */ sb->s_time_gran = 100;/* on error free sesinfo and tcon struct if needed */ if (rc) { /* if session setup failed, use count is zero but we still need to free cifsd thread */ if (atomic_read(&srvTcp->socketUseCount) == 0) { spin_lock(&GlobalMid_Lock); srvTcp->tcpStatus = CifsExiting; spin_unlock(&GlobalMid_Lock); if (srvTcp->tsk) { struct task_struct *tsk; /* If we could verify that kthread_stop would always wake up processes blocked in tcp in recv_mesg then we could remove the send_sig call */ force_sig(SIGKILL, srvTcp->tsk); tsk = srvTcp->tsk; if (tsk) kthread_stop(tsk); } } /* If find_unc succeeded then rc == 0 so we can not end */ if (tcon) /* up accidently freeing someone elses tcon struct */ tconInfoFree(tcon); if (existingCifsSes == NULL) { if (pSesInfo) { if ((pSesInfo->server) && (pSesInfo->status == CifsGood)) { int temp_rc; temp_rc = CIFSSMBLogoff(xid,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -