mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 14:41:39 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: prevent cifs_writepages() from skipping unwritten pages Fixed parsing of mount options when doing DFS submount [CIFS] Fix check for tcon seal setting and fix oops on failed mount from earlier patch [CIFS] Fix build break cifs: reinstate sharing of tree connections [CIFS] minor cleanup to cifs_mount cifs: reinstate sharing of SMB sessions sans races cifs: disable sharing session and tcon and add new TCP sharing code [CIFS] clean up server protocol handling [CIFS] remove unused list, add new cifs sock list to prepare for mount/umount fix [CIFS] Fix cifs reconnection flags [CIFS] Can't rely on iov length and base when kernel_recvmsg returns error
This commit is contained in:
commit
4e14e833ac
@ -107,12 +107,13 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct list_head *tmp1;
|
||||
struct list_head *tmp1, *tmp2, *tmp3;
|
||||
struct mid_q_entry *mid_entry;
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifsSesInfo *ses;
|
||||
struct cifsTconInfo *tcon;
|
||||
int i;
|
||||
int i, j;
|
||||
__u32 dev_type;
|
||||
|
||||
seq_puts(m,
|
||||
"Display Internal CIFS Data Structures for Debugging\n"
|
||||
@ -122,46 +123,78 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
||||
seq_printf(m, "Servers:");
|
||||
|
||||
i = 0;
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
list_for_each(tmp, &GlobalSMBSessionList) {
|
||||
read_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each(tmp1, &cifs_tcp_ses_list) {
|
||||
server = list_entry(tmp1, struct TCP_Server_Info,
|
||||
tcp_ses_list);
|
||||
i++;
|
||||
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
|
||||
if ((ses->serverDomain == NULL) || (ses->serverOS == NULL) ||
|
||||
(ses->serverNOS == NULL)) {
|
||||
seq_printf(m, "\nentry for %s not fully "
|
||||
"displayed\n\t", ses->serverName);
|
||||
} else {
|
||||
seq_printf(m,
|
||||
"\n%d) Name: %s Domain: %s Mounts: %d OS:"
|
||||
" %s \n\tNOS: %s\tCapability: 0x%x\n\tSMB"
|
||||
list_for_each(tmp2, &server->smb_ses_list) {
|
||||
ses = list_entry(tmp2, struct cifsSesInfo,
|
||||
smb_ses_list);
|
||||
if ((ses->serverDomain == NULL) ||
|
||||
(ses->serverOS == NULL) ||
|
||||
(ses->serverNOS == NULL)) {
|
||||
seq_printf(m, "\n%d) entry for %s not fully "
|
||||
"displayed\n\t", i, ses->serverName);
|
||||
} else {
|
||||
seq_printf(m,
|
||||
"\n%d) Name: %s Domain: %s Uses: %d OS:"
|
||||
" %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB"
|
||||
" session status: %d\t",
|
||||
i, ses->serverName, ses->serverDomain,
|
||||
atomic_read(&ses->inUse),
|
||||
ses->serverOS, ses->serverNOS,
|
||||
ses->ses_count, ses->serverOS, ses->serverNOS,
|
||||
ses->capabilities, ses->status);
|
||||
}
|
||||
if (ses->server) {
|
||||
}
|
||||
seq_printf(m, "TCP status: %d\n\tLocal Users To "
|
||||
"Server: %d SecMode: 0x%x Req On Wire: %d",
|
||||
ses->server->tcpStatus,
|
||||
atomic_read(&ses->server->socketUseCount),
|
||||
ses->server->secMode,
|
||||
atomic_read(&ses->server->inFlight));
|
||||
"Server: %d SecMode: 0x%x Req On Wire: %d",
|
||||
server->tcpStatus, server->srv_count,
|
||||
server->secMode,
|
||||
atomic_read(&server->inFlight));
|
||||
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
seq_printf(m, " In Send: %d In MaxReq Wait: %d",
|
||||
atomic_read(&ses->server->inSend),
|
||||
atomic_read(&ses->server->num_waiters));
|
||||
atomic_read(&server->inSend),
|
||||
atomic_read(&server->num_waiters));
|
||||
#endif
|
||||
|
||||
seq_puts(m, "\nMIDs:\n");
|
||||
seq_puts(m, "\n\tShares:");
|
||||
j = 0;
|
||||
list_for_each(tmp3, &ses->tcon_list) {
|
||||
tcon = list_entry(tmp3, struct cifsTconInfo,
|
||||
tcon_list);
|
||||
++j;
|
||||
dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
|
||||
seq_printf(m, "\n\t%d) %s Mounts: %d ", j,
|
||||
tcon->treeName, tcon->tc_count);
|
||||
if (tcon->nativeFileSystem) {
|
||||
seq_printf(m, "Type: %s ",
|
||||
tcon->nativeFileSystem);
|
||||
}
|
||||
seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
|
||||
"\nPathComponentMax: %d Status: 0x%d",
|
||||
le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
|
||||
le32_to_cpu(tcon->fsAttrInfo.Attributes),
|
||||
le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
|
||||
tcon->tidStatus);
|
||||
if (dev_type == FILE_DEVICE_DISK)
|
||||
seq_puts(m, " type: DISK ");
|
||||
else if (dev_type == FILE_DEVICE_CD_ROM)
|
||||
seq_puts(m, " type: CDROM ");
|
||||
else
|
||||
seq_printf(m, " type: %d ", dev_type);
|
||||
|
||||
if (tcon->need_reconnect)
|
||||
seq_puts(m, "\tDISCONNECTED ");
|
||||
seq_putc(m, '\n');
|
||||
}
|
||||
|
||||
seq_puts(m, "\n\tMIDs:\n");
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
list_for_each(tmp1, &ses->server->pending_mid_q) {
|
||||
mid_entry = list_entry(tmp1, struct
|
||||
mid_q_entry,
|
||||
list_for_each(tmp3, &server->pending_mid_q) {
|
||||
mid_entry = list_entry(tmp3, struct mid_q_entry,
|
||||
qhead);
|
||||
seq_printf(m, "State: %d com: %d pid:"
|
||||
seq_printf(m, "\tState: %d com: %d pid:"
|
||||
" %d tsk: %p mid %d\n",
|
||||
mid_entry->midState,
|
||||
(int)mid_entry->command,
|
||||
@ -171,44 +204,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
}
|
||||
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
seq_putc(m, '\n');
|
||||
|
||||
seq_puts(m, "Shares:");
|
||||
|
||||
i = 0;
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
list_for_each(tmp, &GlobalTreeConnectionList) {
|
||||
__u32 dev_type;
|
||||
i++;
|
||||
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
|
||||
dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
|
||||
seq_printf(m, "\n%d) %s Uses: %d ", i,
|
||||
tcon->treeName, atomic_read(&tcon->useCount));
|
||||
if (tcon->nativeFileSystem) {
|
||||
seq_printf(m, "Type: %s ",
|
||||
tcon->nativeFileSystem);
|
||||
}
|
||||
seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
|
||||
"\nPathComponentMax: %d Status: %d",
|
||||
le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
|
||||
le32_to_cpu(tcon->fsAttrInfo.Attributes),
|
||||
le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
|
||||
tcon->tidStatus);
|
||||
if (dev_type == FILE_DEVICE_DISK)
|
||||
seq_puts(m, " type: DISK ");
|
||||
else if (dev_type == FILE_DEVICE_CD_ROM)
|
||||
seq_puts(m, " type: CDROM ");
|
||||
else
|
||||
seq_printf(m, " type: %d ", dev_type);
|
||||
|
||||
if (tcon->tidStatus == CifsNeedReconnect)
|
||||
seq_puts(m, "\tDISCONNECTED ");
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
|
||||
read_unlock(&cifs_tcp_ses_lock);
|
||||
seq_putc(m, '\n');
|
||||
|
||||
/* BB add code to dump additional info such as TCP session info now */
|
||||
@ -234,7 +231,9 @@ static ssize_t cifs_stats_proc_write(struct file *file,
|
||||
{
|
||||
char c;
|
||||
int rc;
|
||||
struct list_head *tmp;
|
||||
struct list_head *tmp1, *tmp2, *tmp3;
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifsSesInfo *ses;
|
||||
struct cifsTconInfo *tcon;
|
||||
|
||||
rc = get_user(c, buffer);
|
||||
@ -242,33 +241,42 @@ static ssize_t cifs_stats_proc_write(struct file *file,
|
||||
return rc;
|
||||
|
||||
if (c == '1' || c == 'y' || c == 'Y' || c == '0') {
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_set(&totBufAllocCount, 0);
|
||||
atomic_set(&totSmBufAllocCount, 0);
|
||||
#endif /* CONFIG_CIFS_STATS2 */
|
||||
list_for_each(tmp, &GlobalTreeConnectionList) {
|
||||
tcon = list_entry(tmp, struct cifsTconInfo,
|
||||
cifsConnectionList);
|
||||
atomic_set(&tcon->num_smbs_sent, 0);
|
||||
atomic_set(&tcon->num_writes, 0);
|
||||
atomic_set(&tcon->num_reads, 0);
|
||||
atomic_set(&tcon->num_oplock_brks, 0);
|
||||
atomic_set(&tcon->num_opens, 0);
|
||||
atomic_set(&tcon->num_closes, 0);
|
||||
atomic_set(&tcon->num_deletes, 0);
|
||||
atomic_set(&tcon->num_mkdirs, 0);
|
||||
atomic_set(&tcon->num_rmdirs, 0);
|
||||
atomic_set(&tcon->num_renames, 0);
|
||||
atomic_set(&tcon->num_t2renames, 0);
|
||||
atomic_set(&tcon->num_ffirst, 0);
|
||||
atomic_set(&tcon->num_fnext, 0);
|
||||
atomic_set(&tcon->num_fclose, 0);
|
||||
atomic_set(&tcon->num_hardlinks, 0);
|
||||
atomic_set(&tcon->num_symlinks, 0);
|
||||
atomic_set(&tcon->num_locks, 0);
|
||||
read_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each(tmp1, &cifs_tcp_ses_list) {
|
||||
server = list_entry(tmp1, struct TCP_Server_Info,
|
||||
tcp_ses_list);
|
||||
list_for_each(tmp2, &server->smb_ses_list) {
|
||||
ses = list_entry(tmp2, struct cifsSesInfo,
|
||||
smb_ses_list);
|
||||
list_for_each(tmp3, &ses->tcon_list) {
|
||||
tcon = list_entry(tmp3,
|
||||
struct cifsTconInfo,
|
||||
tcon_list);
|
||||
atomic_set(&tcon->num_smbs_sent, 0);
|
||||
atomic_set(&tcon->num_writes, 0);
|
||||
atomic_set(&tcon->num_reads, 0);
|
||||
atomic_set(&tcon->num_oplock_brks, 0);
|
||||
atomic_set(&tcon->num_opens, 0);
|
||||
atomic_set(&tcon->num_closes, 0);
|
||||
atomic_set(&tcon->num_deletes, 0);
|
||||
atomic_set(&tcon->num_mkdirs, 0);
|
||||
atomic_set(&tcon->num_rmdirs, 0);
|
||||
atomic_set(&tcon->num_renames, 0);
|
||||
atomic_set(&tcon->num_t2renames, 0);
|
||||
atomic_set(&tcon->num_ffirst, 0);
|
||||
atomic_set(&tcon->num_fnext, 0);
|
||||
atomic_set(&tcon->num_fclose, 0);
|
||||
atomic_set(&tcon->num_hardlinks, 0);
|
||||
atomic_set(&tcon->num_symlinks, 0);
|
||||
atomic_set(&tcon->num_locks, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
read_unlock(&cifs_tcp_ses_lock);
|
||||
}
|
||||
|
||||
return count;
|
||||
@ -277,7 +285,9 @@ static ssize_t cifs_stats_proc_write(struct file *file,
|
||||
static int cifs_stats_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
int i;
|
||||
struct list_head *tmp;
|
||||
struct list_head *tmp1, *tmp2, *tmp3;
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifsSesInfo *ses;
|
||||
struct cifsTconInfo *tcon;
|
||||
|
||||
seq_printf(m,
|
||||
@ -306,44 +316,55 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
|
||||
GlobalCurrentXid, GlobalMaxActiveXid);
|
||||
|
||||
i = 0;
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
list_for_each(tmp, &GlobalTreeConnectionList) {
|
||||
i++;
|
||||
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
|
||||
seq_printf(m, "\n%d) %s", i, tcon->treeName);
|
||||
if (tcon->tidStatus == CifsNeedReconnect)
|
||||
seq_puts(m, "\tDISCONNECTED ");
|
||||
seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
|
||||
atomic_read(&tcon->num_smbs_sent),
|
||||
atomic_read(&tcon->num_oplock_brks));
|
||||
seq_printf(m, "\nReads: %d Bytes: %lld",
|
||||
atomic_read(&tcon->num_reads),
|
||||
(long long)(tcon->bytes_read));
|
||||
seq_printf(m, "\nWrites: %d Bytes: %lld",
|
||||
atomic_read(&tcon->num_writes),
|
||||
(long long)(tcon->bytes_written));
|
||||
seq_printf(m,
|
||||
"\nLocks: %d HardLinks: %d Symlinks: %d",
|
||||
atomic_read(&tcon->num_locks),
|
||||
atomic_read(&tcon->num_hardlinks),
|
||||
atomic_read(&tcon->num_symlinks));
|
||||
|
||||
seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d",
|
||||
atomic_read(&tcon->num_opens),
|
||||
atomic_read(&tcon->num_closes),
|
||||
atomic_read(&tcon->num_deletes));
|
||||
seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
|
||||
atomic_read(&tcon->num_mkdirs),
|
||||
atomic_read(&tcon->num_rmdirs));
|
||||
seq_printf(m, "\nRenames: %d T2 Renames %d",
|
||||
atomic_read(&tcon->num_renames),
|
||||
atomic_read(&tcon->num_t2renames));
|
||||
seq_printf(m, "\nFindFirst: %d FNext %d FClose %d",
|
||||
atomic_read(&tcon->num_ffirst),
|
||||
atomic_read(&tcon->num_fnext),
|
||||
atomic_read(&tcon->num_fclose));
|
||||
read_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each(tmp1, &cifs_tcp_ses_list) {
|
||||
server = list_entry(tmp1, struct TCP_Server_Info,
|
||||
tcp_ses_list);
|
||||
list_for_each(tmp2, &server->smb_ses_list) {
|
||||
ses = list_entry(tmp2, struct cifsSesInfo,
|
||||
smb_ses_list);
|
||||
list_for_each(tmp3, &ses->tcon_list) {
|
||||
tcon = list_entry(tmp3,
|
||||
struct cifsTconInfo,
|
||||
tcon_list);
|
||||
i++;
|
||||
seq_printf(m, "\n%d) %s", i, tcon->treeName);
|
||||
if (tcon->need_reconnect)
|
||||
seq_puts(m, "\tDISCONNECTED ");
|
||||
seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
|
||||
atomic_read(&tcon->num_smbs_sent),
|
||||
atomic_read(&tcon->num_oplock_brks));
|
||||
seq_printf(m, "\nReads: %d Bytes: %lld",
|
||||
atomic_read(&tcon->num_reads),
|
||||
(long long)(tcon->bytes_read));
|
||||
seq_printf(m, "\nWrites: %d Bytes: %lld",
|
||||
atomic_read(&tcon->num_writes),
|
||||
(long long)(tcon->bytes_written));
|
||||
seq_printf(m, "\nLocks: %d HardLinks: %d "
|
||||
"Symlinks: %d",
|
||||
atomic_read(&tcon->num_locks),
|
||||
atomic_read(&tcon->num_hardlinks),
|
||||
atomic_read(&tcon->num_symlinks));
|
||||
seq_printf(m, "\nOpens: %d Closes: %d"
|
||||
"Deletes: %d",
|
||||
atomic_read(&tcon->num_opens),
|
||||
atomic_read(&tcon->num_closes),
|
||||
atomic_read(&tcon->num_deletes));
|
||||
seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
|
||||
atomic_read(&tcon->num_mkdirs),
|
||||
atomic_read(&tcon->num_rmdirs));
|
||||
seq_printf(m, "\nRenames: %d T2 Renames %d",
|
||||
atomic_read(&tcon->num_renames),
|
||||
atomic_read(&tcon->num_t2renames));
|
||||
seq_printf(m, "\nFindFirst: %d FNext %d "
|
||||
"FClose %d",
|
||||
atomic_read(&tcon->num_ffirst),
|
||||
atomic_read(&tcon->num_fnext),
|
||||
atomic_read(&tcon->num_fclose));
|
||||
}
|
||||
}
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
read_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
seq_putc(m, '\n');
|
||||
return 0;
|
||||
|
@ -106,7 +106,8 @@ static char *cifs_get_share_name(const char *node_name)
|
||||
/**
|
||||
* compose_mount_options - creates mount options for refferral
|
||||
* @sb_mountdata: parent/root DFS mount options (template)
|
||||
* @ref_unc: refferral server UNC
|
||||
* @dentry: point where we are going to mount
|
||||
* @ref: server's referral
|
||||
* @devname: pointer for saving device name
|
||||
*
|
||||
* creates mount options for submount based on template options sb_mountdata
|
||||
@ -116,7 +117,8 @@ static char *cifs_get_share_name(const char *node_name)
|
||||
* Caller is responcible for freeing retunrned value if it is not error.
|
||||
*/
|
||||
static char *compose_mount_options(const char *sb_mountdata,
|
||||
const char *ref_unc,
|
||||
struct dentry *dentry,
|
||||
const struct dfs_info3_param *ref,
|
||||
char **devname)
|
||||
{
|
||||
int rc;
|
||||
@ -126,11 +128,12 @@ static char *compose_mount_options(const char *sb_mountdata,
|
||||
char *srvIP = NULL;
|
||||
char sep = ',';
|
||||
int off, noff;
|
||||
char *fullpath;
|
||||
|
||||
if (sb_mountdata == NULL)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
*devname = cifs_get_share_name(ref_unc);
|
||||
*devname = cifs_get_share_name(ref->node_name);
|
||||
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
|
||||
if (rc != 0) {
|
||||
cERROR(1, ("%s: Failed to resolve server part of %s to IP",
|
||||
@ -138,7 +141,12 @@ static char *compose_mount_options(const char *sb_mountdata,
|
||||
mountdata = ERR_PTR(rc);
|
||||
goto compose_mount_options_out;
|
||||
}
|
||||
md_len = strlen(sb_mountdata) + strlen(srvIP) + strlen(ref_unc) + 3;
|
||||
/* md_len = strlen(...) + 12 for 'sep+prefixpath='
|
||||
* assuming that we have 'unc=' and 'ip=' in
|
||||
* the original sb_mountdata
|
||||
*/
|
||||
md_len = strlen(sb_mountdata) + strlen(srvIP) +
|
||||
strlen(ref->node_name) + 12;
|
||||
mountdata = kzalloc(md_len+1, GFP_KERNEL);
|
||||
if (mountdata == NULL) {
|
||||
mountdata = ERR_PTR(-ENOMEM);
|
||||
@ -152,41 +160,56 @@ static char *compose_mount_options(const char *sb_mountdata,
|
||||
strncpy(mountdata, sb_mountdata, 5);
|
||||
off += 5;
|
||||
}
|
||||
while ((tkn_e = strchr(sb_mountdata+off, sep))) {
|
||||
noff = (tkn_e - (sb_mountdata+off)) + 1;
|
||||
if (strnicmp(sb_mountdata+off, "unc=", 4) == 0) {
|
||||
|
||||
do {
|
||||
tkn_e = strchr(sb_mountdata + off, sep);
|
||||
if (tkn_e == NULL)
|
||||
noff = strlen(sb_mountdata + off);
|
||||
else
|
||||
noff = tkn_e - (sb_mountdata + off) + 1;
|
||||
|
||||
if (strnicmp(sb_mountdata + off, "unc=", 4) == 0) {
|
||||
off += noff;
|
||||
continue;
|
||||
}
|
||||
if (strnicmp(sb_mountdata+off, "ip=", 3) == 0) {
|
||||
if (strnicmp(sb_mountdata + off, "ip=", 3) == 0) {
|
||||
off += noff;
|
||||
continue;
|
||||
}
|
||||
if (strnicmp(sb_mountdata+off, "prefixpath=", 3) == 0) {
|
||||
if (strnicmp(sb_mountdata + off, "prefixpath=", 11) == 0) {
|
||||
off += noff;
|
||||
continue;
|
||||
}
|
||||
strncat(mountdata, sb_mountdata+off, noff);
|
||||
strncat(mountdata, sb_mountdata + off, noff);
|
||||
off += noff;
|
||||
}
|
||||
strcat(mountdata, sb_mountdata+off);
|
||||
} while (tkn_e);
|
||||
strcat(mountdata, sb_mountdata + off);
|
||||
mountdata[md_len] = '\0';
|
||||
|
||||
/* copy new IP and ref share name */
|
||||
strcat(mountdata, ",ip=");
|
||||
if (mountdata[strlen(mountdata) - 1] != sep)
|
||||
strncat(mountdata, &sep, 1);
|
||||
strcat(mountdata, "ip=");
|
||||
strcat(mountdata, srvIP);
|
||||
strcat(mountdata, ",unc=");
|
||||
strncat(mountdata, &sep, 1);
|
||||
strcat(mountdata, "unc=");
|
||||
strcat(mountdata, *devname);
|
||||
|
||||
/* find & copy prefixpath */
|
||||
tkn_e = strchr(ref_unc+2, '\\');
|
||||
if (tkn_e) {
|
||||
tkn_e = strchr(tkn_e+1, '\\');
|
||||
if (tkn_e) {
|
||||
strcat(mountdata, ",prefixpath=");
|
||||
strcat(mountdata, tkn_e+1);
|
||||
}
|
||||
tkn_e = strchr(ref->node_name + 2, '\\');
|
||||
if (tkn_e == NULL) /* invalid unc, missing share name*/
|
||||
goto compose_mount_options_out;
|
||||
|
||||
fullpath = build_path_from_dentry(dentry);
|
||||
tkn_e = strchr(tkn_e + 1, '\\');
|
||||
if (tkn_e || strlen(fullpath) - (ref->path_consumed)) {
|
||||
strncat(mountdata, &sep, 1);
|
||||
strcat(mountdata, "prefixpath=");
|
||||
if (tkn_e)
|
||||
strcat(mountdata, tkn_e + 1);
|
||||
strcat(mountdata, fullpath + (ref->path_consumed));
|
||||
}
|
||||
kfree(fullpath);
|
||||
|
||||
/*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/
|
||||
/*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/
|
||||
@ -198,7 +221,7 @@ compose_mount_options_out:
|
||||
|
||||
|
||||
static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
|
||||
struct dentry *dentry, char *ref_unc)
|
||||
struct dentry *dentry, const struct dfs_info3_param *ref)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct vfsmount *mnt;
|
||||
@ -207,7 +230,7 @@ static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
|
||||
|
||||
cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
|
||||
mountdata = compose_mount_options(cifs_sb->mountdata,
|
||||
ref_unc, &devname);
|
||||
dentry, ref, &devname);
|
||||
|
||||
if (IS_ERR(mountdata))
|
||||
return (struct vfsmount *)mountdata;
|
||||
@ -310,7 +333,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
|
||||
}
|
||||
mnt = cifs_dfs_do_refmount(nd->path.mnt,
|
||||
nd->path.dentry,
|
||||
referrals[i].node_name);
|
||||
referrals + i);
|
||||
cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
|
||||
__func__,
|
||||
referrals[i].node_name, mnt));
|
||||
|
@ -73,8 +73,8 @@ struct key_type cifs_spnego_key_type = {
|
||||
* strlen(";sec=ntlmsspi") */
|
||||
#define MAX_MECH_STR_LEN 13
|
||||
|
||||
/* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */
|
||||
#define MAX_IPV6_ADDR_LEN 42
|
||||
/* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/128 */
|
||||
#define MAX_IPV6_ADDR_LEN 43
|
||||
|
||||
/* strlen of "host=" */
|
||||
#define HOST_KEY_LEN 5
|
||||
|
@ -514,10 +514,11 @@ static void cifs_umount_begin(struct super_block *sb)
|
||||
tcon = cifs_sb->tcon;
|
||||
if (tcon == NULL)
|
||||
return;
|
||||
down(&tcon->tconSem);
|
||||
if (atomic_read(&tcon->useCount) == 1)
|
||||
|
||||
read_lock(&cifs_tcp_ses_lock);
|
||||
if (tcon->tc_count == 1)
|
||||
tcon->tidStatus = CifsExiting;
|
||||
up(&tcon->tconSem);
|
||||
read_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
|
||||
/* cancel_notify_requests(tcon); */
|
||||
@ -1013,7 +1014,7 @@ static int cifs_oplock_thread(void *dummyarg)
|
||||
not bother sending an oplock release if session
|
||||
to server still is disconnected since oplock
|
||||
already released by the server in that case */
|
||||
if (pTcon->tidStatus != CifsNeedReconnect) {
|
||||
if (!pTcon->need_reconnect) {
|
||||
rc = CIFSSMBLock(0, pTcon, netfid,
|
||||
0 /* len */ , 0 /* offset */, 0,
|
||||
0, LOCKING_ANDX_OPLOCK_RELEASE,
|
||||
@ -1031,24 +1032,24 @@ static int cifs_oplock_thread(void *dummyarg)
|
||||
static int cifs_dnotify_thread(void *dummyarg)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct cifsSesInfo *ses;
|
||||
struct TCP_Server_Info *server;
|
||||
|
||||
do {
|
||||
if (try_to_freeze())
|
||||
continue;
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(15*HZ);
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
/* check if any stuck requests that need
|
||||
to be woken up and wakeq so the
|
||||
thread can wake up and error out */
|
||||
list_for_each(tmp, &GlobalSMBSessionList) {
|
||||
ses = list_entry(tmp, struct cifsSesInfo,
|
||||
cifsSessionList);
|
||||
if (ses->server && atomic_read(&ses->server->inFlight))
|
||||
wake_up_all(&ses->server->response_q);
|
||||
read_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each(tmp, &cifs_tcp_ses_list) {
|
||||
server = list_entry(tmp, struct TCP_Server_Info,
|
||||
tcp_ses_list);
|
||||
if (atomic_read(&server->inFlight))
|
||||
wake_up_all(&server->response_q);
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
read_unlock(&cifs_tcp_ses_lock);
|
||||
} while (!kthread_should_stop());
|
||||
|
||||
return 0;
|
||||
@ -1059,9 +1060,7 @@ init_cifs(void)
|
||||
{
|
||||
int rc = 0;
|
||||
cifs_proc_init();
|
||||
/* INIT_LIST_HEAD(&GlobalServerList);*/ /* BB not implemented yet */
|
||||
INIT_LIST_HEAD(&GlobalSMBSessionList);
|
||||
INIT_LIST_HEAD(&GlobalTreeConnectionList);
|
||||
INIT_LIST_HEAD(&cifs_tcp_ses_list);
|
||||
INIT_LIST_HEAD(&GlobalOplock_Q);
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
INIT_LIST_HEAD(&GlobalDnotifyReqList);
|
||||
@ -1089,6 +1088,7 @@ init_cifs(void)
|
||||
GlobalMaxActiveXid = 0;
|
||||
memset(Local_System_Name, 0, 15);
|
||||
rwlock_init(&GlobalSMBSeslock);
|
||||
rwlock_init(&cifs_tcp_ses_lock);
|
||||
spin_lock_init(&GlobalMid_Lock);
|
||||
|
||||
if (cifs_max_pending < 2) {
|
||||
|
@ -85,8 +85,7 @@ enum securityEnum {
|
||||
};
|
||||
|
||||
enum protocolEnum {
|
||||
IPV4 = 0,
|
||||
IPV6,
|
||||
TCP = 0,
|
||||
SCTP
|
||||
/* Netbios frames protocol not supported at this time */
|
||||
};
|
||||
@ -122,6 +121,9 @@ struct cifs_cred {
|
||||
*/
|
||||
|
||||
struct TCP_Server_Info {
|
||||
struct list_head tcp_ses_list;
|
||||
struct list_head smb_ses_list;
|
||||
int srv_count; /* reference counter */
|
||||
/* 15 character server name + 0x20 16th byte indicating type = srv */
|
||||
char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
|
||||
char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
|
||||
@ -143,7 +145,6 @@ struct TCP_Server_Info {
|
||||
bool svlocal:1; /* local server or remote */
|
||||
bool noblocksnd; /* use blocking sendmsg */
|
||||
bool noautotune; /* do not autotune send buf sizes */
|
||||
atomic_t socketUseCount; /* number of open cifs sessions on socket */
|
||||
atomic_t inFlight; /* number of requests on the wire to server */
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_t inSend; /* requests trying to send */
|
||||
@ -194,13 +195,14 @@ struct cifsUidInfo {
|
||||
* Session structure. One of these for each uid session with a particular host
|
||||
*/
|
||||
struct cifsSesInfo {
|
||||
struct list_head cifsSessionList;
|
||||
struct list_head smb_ses_list;
|
||||
struct list_head tcon_list;
|
||||
struct semaphore sesSem;
|
||||
#if 0
|
||||
struct cifsUidInfo *uidInfo; /* pointer to user info */
|
||||
#endif
|
||||
struct TCP_Server_Info *server; /* pointer to server info */
|
||||
atomic_t inUse; /* # of mounts (tree connections) on this ses */
|
||||
int ses_count; /* reference counter */
|
||||
enum statusEnum status;
|
||||
unsigned overrideSecFlg; /* if non-zero override global sec flags */
|
||||
__u16 ipc_tid; /* special tid for connection to IPC share */
|
||||
@ -216,6 +218,7 @@ struct cifsSesInfo {
|
||||
char userName[MAX_USERNAME_SIZE + 1];
|
||||
char *domainName;
|
||||
char *password;
|
||||
bool need_reconnect:1; /* connection reset, uid now invalid */
|
||||
};
|
||||
/* no more than one of the following three session flags may be set */
|
||||
#define CIFS_SES_NT4 1
|
||||
@ -230,16 +233,15 @@ struct cifsSesInfo {
|
||||
* session
|
||||
*/
|
||||
struct cifsTconInfo {
|
||||
struct list_head cifsConnectionList;
|
||||
struct list_head tcon_list;
|
||||
int tc_count;
|
||||
struct list_head openFileList;
|
||||
struct semaphore tconSem;
|
||||
struct cifsSesInfo *ses; /* pointer to session associated with */
|
||||
char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
|
||||
char *nativeFileSystem;
|
||||
__u16 tid; /* The 2 byte tree id */
|
||||
__u16 Flags; /* optional support bits */
|
||||
enum statusEnum tidStatus;
|
||||
atomic_t useCount; /* how many explicit/implicit mounts to share */
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
atomic_t num_smbs_sent;
|
||||
atomic_t num_writes;
|
||||
@ -288,6 +290,7 @@ struct cifsTconInfo {
|
||||
bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol
|
||||
for this mount even if server would support */
|
||||
bool local_lease:1; /* check leases (only) on local system not remote */
|
||||
bool need_reconnect:1; /* connection reset, tid now invalid */
|
||||
/* BB add field for back pointer to sb struct(s)? */
|
||||
};
|
||||
|
||||
@ -588,21 +591,21 @@ require use of the stronger protocol */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The list of servers that did not respond with NT LM 0.12.
|
||||
* This list helps improve performance and eliminate the messages indicating
|
||||
* that we had a communications error talking to the server in this list.
|
||||
* the list of TCP_Server_Info structures, ie each of the sockets
|
||||
* connecting our client to a distinct server (ip address), is
|
||||
* chained together by cifs_tcp_ses_list. The list of all our SMB
|
||||
* sessions (and from that the tree connections) can be found
|
||||
* by iterating over cifs_tcp_ses_list
|
||||
*/
|
||||
/* Feature not supported */
|
||||
/* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */
|
||||
GLOBAL_EXTERN struct list_head cifs_tcp_ses_list;
|
||||
|
||||
/*
|
||||
* The following is a hash table of all the users we know about.
|
||||
* This lock protects the cifs_tcp_ses_list, the list of smb sessions per
|
||||
* tcp session, and the list of tcon's per smb session. It also protects
|
||||
* the reference counters for the server, smb session, and tcon. Finally,
|
||||
* changes to the tcon->tidStatus should be done while holding this lock.
|
||||
*/
|
||||
GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH];
|
||||
|
||||
/* GLOBAL_EXTERN struct list_head GlobalServerList; BB not implemented yet */
|
||||
GLOBAL_EXTERN struct list_head GlobalSMBSessionList;
|
||||
GLOBAL_EXTERN struct list_head GlobalTreeConnectionList;
|
||||
GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock;
|
||||
GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */
|
||||
|
||||
GLOBAL_EXTERN struct list_head GlobalOplock_Q;
|
||||
|
@ -190,10 +190,10 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
|
||||
/* need to prevent multiple threads trying to
|
||||
simultaneously reconnect the same SMB session */
|
||||
down(&tcon->ses->sesSem);
|
||||
if (tcon->ses->status == CifsNeedReconnect)
|
||||
if (tcon->ses->need_reconnect)
|
||||
rc = cifs_setup_session(0, tcon->ses,
|
||||
nls_codepage);
|
||||
if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
|
||||
if (!rc && (tcon->need_reconnect)) {
|
||||
mark_open_files_invalid(tcon);
|
||||
rc = CIFSTCon(0, tcon->ses, tcon->treeName,
|
||||
tcon, nls_codepage);
|
||||
@ -295,7 +295,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
|
||||
check for tcp and smb session status done differently
|
||||
for those three - in the calling routine */
|
||||
if (tcon) {
|
||||
if (tcon->tidStatus == CifsExiting) {
|
||||
if (tcon->need_reconnect) {
|
||||
/* only tree disconnect, open, and write,
|
||||
(and ulogoff which does not have tcon)
|
||||
are allowed as we start force umount */
|
||||
@ -337,10 +337,10 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
|
||||
/* need to prevent multiple threads trying to
|
||||
simultaneously reconnect the same SMB session */
|
||||
down(&tcon->ses->sesSem);
|
||||
if (tcon->ses->status == CifsNeedReconnect)
|
||||
if (tcon->ses->need_reconnect)
|
||||
rc = cifs_setup_session(0, tcon->ses,
|
||||
nls_codepage);
|
||||
if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
|
||||
if (!rc && (tcon->need_reconnect)) {
|
||||
mark_open_files_invalid(tcon);
|
||||
rc = CIFSTCon(0, tcon->ses, tcon->treeName,
|
||||
tcon, nls_codepage);
|
||||
@ -664,8 +664,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
||||
rc = -EIO;
|
||||
goto neg_err_exit;
|
||||
}
|
||||
|
||||
if (server->socketUseCount.counter > 1) {
|
||||
read_lock(&cifs_tcp_ses_lock);
|
||||
if (server->srv_count > 1) {
|
||||
read_unlock(&cifs_tcp_ses_lock);
|
||||
if (memcmp(server->server_GUID,
|
||||
pSMBr->u.extended_response.
|
||||
GUID, 16) != 0) {
|
||||
@ -674,9 +675,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
||||
pSMBr->u.extended_response.GUID,
|
||||
16);
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
read_unlock(&cifs_tcp_ses_lock);
|
||||
memcpy(server->server_GUID,
|
||||
pSMBr->u.extended_response.GUID, 16);
|
||||
}
|
||||
|
||||
if (count == 16) {
|
||||
server->secType = RawNTLMSSP;
|
||||
@ -739,50 +742,31 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
|
||||
int rc = 0;
|
||||
|
||||
cFYI(1, ("In tree disconnect"));
|
||||
|
||||
/* BB: do we need to check this? These should never be NULL. */
|
||||
if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* If last user of the connection and
|
||||
* connection alive - disconnect it
|
||||
* If this is the last connection on the server session disconnect it
|
||||
* (and inside session disconnect we should check if tcp socket needs
|
||||
* to be freed and kernel thread woken up).
|
||||
* No need to return error on this operation if tid invalidated and
|
||||
* closed on server already e.g. due to tcp session crashing. Also,
|
||||
* the tcon is no longer on the list, so no need to take lock before
|
||||
* checking this.
|
||||
*/
|
||||
if (tcon)
|
||||
down(&tcon->tconSem);
|
||||
else
|
||||
return -EIO;
|
||||
|
||||
atomic_dec(&tcon->useCount);
|
||||
if (atomic_read(&tcon->useCount) > 0) {
|
||||
up(&tcon->tconSem);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* No need to return error on this operation if tid invalidated and
|
||||
closed on server already e.g. due to tcp session crashing */
|
||||
if (tcon->tidStatus == CifsNeedReconnect) {
|
||||
up(&tcon->tconSem);
|
||||
if (tcon->need_reconnect)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
|
||||
up(&tcon->tconSem);
|
||||
return -EIO;
|
||||
}
|
||||
rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
|
||||
(void **)&smb_buffer);
|
||||
if (rc) {
|
||||
up(&tcon->tconSem);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
|
||||
if (rc)
|
||||
cFYI(1, ("Tree disconnect failed %d", rc));
|
||||
|
||||
up(&tcon->tconSem);
|
||||
|
||||
/* No need to return error on this operation if tid invalidated and
|
||||
closed on server already e.g. due to tcp session crashing */
|
||||
closed on server already e.g. due to tcp session crashing */
|
||||
if (rc == -EAGAIN)
|
||||
rc = 0;
|
||||
|
||||
@ -796,43 +780,36 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
|
||||
int rc = 0;
|
||||
|
||||
cFYI(1, ("In SMBLogoff for session disconnect"));
|
||||
if (ses)
|
||||
down(&ses->sesSem);
|
||||
else
|
||||
|
||||
/*
|
||||
* BB: do we need to check validity of ses and server? They should
|
||||
* always be valid since we have an active reference. If not, that
|
||||
* should probably be a BUG()
|
||||
*/
|
||||
if (!ses || !ses->server)
|
||||
return -EIO;
|
||||
|
||||
atomic_dec(&ses->inUse);
|
||||
if (atomic_read(&ses->inUse) > 0) {
|
||||
up(&ses->sesSem);
|
||||
return -EBUSY;
|
||||
}
|
||||
down(&ses->sesSem);
|
||||
if (ses->need_reconnect)
|
||||
goto session_already_dead; /* no need to send SMBlogoff if uid
|
||||
already closed due to reconnect */
|
||||
rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
|
||||
if (rc) {
|
||||
up(&ses->sesSem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (ses->server) {
|
||||
pSMB->hdr.Mid = GetNextMid(ses->server);
|
||||
pSMB->hdr.Mid = GetNextMid(ses->server);
|
||||
|
||||
if (ses->server->secMode &
|
||||
if (ses->server->secMode &
|
||||
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
|
||||
pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
|
||||
}
|
||||
|
||||
pSMB->hdr.Uid = ses->Suid;
|
||||
|
||||
pSMB->AndXCommand = 0xFF;
|
||||
rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
|
||||
if (ses->server) {
|
||||
atomic_dec(&ses->server->socketUseCount);
|
||||
if (atomic_read(&ses->server->socketUseCount) == 0) {
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
ses->server->tcpStatus = CifsExiting;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
rc = -ESHUTDOWN;
|
||||
}
|
||||
}
|
||||
session_already_dead:
|
||||
up(&ses->sesSem);
|
||||
|
||||
/* if session dead then we do not need to do ulogoff,
|
||||
@ -3922,6 +3899,27 @@ GetInodeNumOut:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* computes length of UCS string converted to host codepage
|
||||
* @src: UCS string
|
||||
* @maxlen: length of the input string in UCS characters
|
||||
* (not in bytes)
|
||||
*
|
||||
* return: size of input string in host codepage
|
||||
*/
|
||||
static int hostlen_fromUCS(const __le16 *src, const int maxlen,
|
||||
const struct nls_table *nls_codepage) {
|
||||
int i;
|
||||
int hostlen = 0;
|
||||
char to[4];
|
||||
int charlen;
|
||||
for (i = 0; (i < maxlen) && src[i]; ++i) {
|
||||
charlen = nls_codepage->uni2char(le16_to_cpu(src[i]),
|
||||
to, NLS_MAX_CHARSET_SIZE);
|
||||
hostlen += charlen > 0 ? charlen : 1;
|
||||
}
|
||||
return hostlen;
|
||||
}
|
||||
|
||||
/* parses DFS refferal V3 structure
|
||||
* caller is responsible for freeing target_nodes
|
||||
* returns:
|
||||
@ -3932,7 +3930,8 @@ static int
|
||||
parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
|
||||
unsigned int *num_of_nodes,
|
||||
struct dfs_info3_param **target_nodes,
|
||||
const struct nls_table *nls_codepage)
|
||||
const struct nls_table *nls_codepage, int remap,
|
||||
const char *searchName)
|
||||
{
|
||||
int i, rc = 0;
|
||||
char *data_end;
|
||||
@ -3983,7 +3982,17 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
|
||||
struct dfs_info3_param *node = (*target_nodes)+i;
|
||||
|
||||
node->flags = le16_to_cpu(pSMBr->DFSFlags);
|
||||
node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
|
||||
if (is_unicode) {
|
||||
__le16 *tmp = kmalloc(strlen(searchName)*2, GFP_KERNEL);
|
||||
cifsConvertToUCS((__le16 *) tmp, searchName,
|
||||
PATH_MAX, nls_codepage, remap);
|
||||
node->path_consumed = hostlen_fromUCS(tmp,
|
||||
le16_to_cpu(pSMBr->PathConsumed)/2,
|
||||
nls_codepage);
|
||||
kfree(tmp);
|
||||
} else
|
||||
node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
|
||||
|
||||
node->server_type = le16_to_cpu(ref->ServerType);
|
||||
node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
|
||||
|
||||
@ -4116,7 +4125,8 @@ getDFSRetry:
|
||||
|
||||
/* parse returned result into more usable form */
|
||||
rc = parse_DFS_referrals(pSMBr, num_of_nodes,
|
||||
target_nodes, nls_codepage);
|
||||
target_nodes, nls_codepage, remap,
|
||||
searchName);
|
||||
|
||||
GetDFSRefExit:
|
||||
cifs_buf_release(pSMB);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -493,7 +493,7 @@ int cifs_close(struct inode *inode, struct file *file)
|
||||
if (pTcon) {
|
||||
/* no sense reconnecting to close a file that is
|
||||
already closed */
|
||||
if (pTcon->tidStatus != CifsNeedReconnect) {
|
||||
if (!pTcon->need_reconnect) {
|
||||
timeout = 2;
|
||||
while ((atomic_read(&pSMBFile->wrtPending) != 0)
|
||||
&& (timeout <= 2048)) {
|
||||
@ -1404,7 +1404,10 @@ retry:
|
||||
if ((wbc->nr_to_write -= n_iov) <= 0)
|
||||
done = 1;
|
||||
index = next;
|
||||
}
|
||||
} else
|
||||
/* Need to re-find the pages we skipped */
|
||||
index = pvec.pages[0]->index + 1;
|
||||
|
||||
pagevec_release(&pvec);
|
||||
}
|
||||
if (!scanned && !done) {
|
||||
|
@ -75,12 +75,12 @@ sesInfoAlloc(void)
|
||||
|
||||
ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL);
|
||||
if (ret_buf) {
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
atomic_inc(&sesInfoAllocCount);
|
||||
ret_buf->status = CifsNew;
|
||||
list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList);
|
||||
++ret_buf->ses_count;
|
||||
INIT_LIST_HEAD(&ret_buf->smb_ses_list);
|
||||
INIT_LIST_HEAD(&ret_buf->tcon_list);
|
||||
init_MUTEX(&ret_buf->sesSem);
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
}
|
||||
return ret_buf;
|
||||
}
|
||||
@ -93,10 +93,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
|
||||
return;
|
||||
}
|
||||
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
atomic_dec(&sesInfoAllocCount);
|
||||
list_del(&buf_to_free->cifsSessionList);
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
kfree(buf_to_free->serverOS);
|
||||
kfree(buf_to_free->serverDomain);
|
||||
kfree(buf_to_free->serverNOS);
|
||||
@ -111,17 +108,14 @@ tconInfoAlloc(void)
|
||||
struct cifsTconInfo *ret_buf;
|
||||
ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL);
|
||||
if (ret_buf) {
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
atomic_inc(&tconInfoAllocCount);
|
||||
list_add(&ret_buf->cifsConnectionList,
|
||||
&GlobalTreeConnectionList);
|
||||
ret_buf->tidStatus = CifsNew;
|
||||
++ret_buf->tc_count;
|
||||
INIT_LIST_HEAD(&ret_buf->openFileList);
|
||||
init_MUTEX(&ret_buf->tconSem);
|
||||
INIT_LIST_HEAD(&ret_buf->tcon_list);
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
spin_lock_init(&ret_buf->stat_lock);
|
||||
#endif
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
}
|
||||
return ret_buf;
|
||||
}
|
||||
@ -133,10 +127,7 @@ tconInfoFree(struct cifsTconInfo *buf_to_free)
|
||||
cFYI(1, ("Null buffer passed to tconInfoFree"));
|
||||
return;
|
||||
}
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
atomic_dec(&tconInfoAllocCount);
|
||||
list_del(&buf_to_free->cifsConnectionList);
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
kfree(buf_to_free->nativeFileSystem);
|
||||
kfree(buf_to_free);
|
||||
}
|
||||
@ -350,9 +341,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
|
||||
if (current->fsuid != treeCon->ses->linux_uid) {
|
||||
cFYI(1, ("Multiuser mode and UID "
|
||||
"did not match tcon uid"));
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
list_for_each(temp_item, &GlobalSMBSessionList) {
|
||||
ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList);
|
||||
read_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) {
|
||||
ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list);
|
||||
if (ses->linux_uid == current->fsuid) {
|
||||
if (ses->server == treeCon->ses->server) {
|
||||
cFYI(1, ("found matching uid substitute right smb_uid"));
|
||||
@ -364,7 +355,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
|
||||
}
|
||||
}
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
read_unlock(&cifs_tcp_ses_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -497,9 +488,10 @@ bool
|
||||
is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
|
||||
{
|
||||
struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
|
||||
struct list_head *tmp;
|
||||
struct list_head *tmp1;
|
||||
struct list_head *tmp, *tmp1, *tmp2;
|
||||
struct cifsSesInfo *ses;
|
||||
struct cifsTconInfo *tcon;
|
||||
struct cifsInodeInfo *pCifsInode;
|
||||
struct cifsFileInfo *netfile;
|
||||
|
||||
cFYI(1, ("Checking for oplock break or dnotify response"));
|
||||
@ -554,42 +546,42 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
|
||||
return false;
|
||||
|
||||
/* look up tcon based on tid & uid */
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
list_for_each(tmp, &GlobalTreeConnectionList) {
|
||||
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
|
||||
if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) {
|
||||
read_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each(tmp, &srv->smb_ses_list) {
|
||||
ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
|
||||
list_for_each(tmp1, &ses->tcon_list) {
|
||||
tcon = list_entry(tmp1, struct cifsTconInfo, tcon_list);
|
||||
if (tcon->tid != buf->Tid)
|
||||
continue;
|
||||
|
||||
cifs_stats_inc(&tcon->num_oplock_brks);
|
||||
list_for_each(tmp1, &tcon->openFileList) {
|
||||
netfile = list_entry(tmp1, struct cifsFileInfo,
|
||||
list_for_each(tmp2, &tcon->openFileList) {
|
||||
netfile = list_entry(tmp2, struct cifsFileInfo,
|
||||
tlist);
|
||||
if (pSMB->Fid == netfile->netfid) {
|
||||
struct cifsInodeInfo *pCifsInode;
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
cFYI(1,
|
||||
("file id match, oplock break"));
|
||||
pCifsInode =
|
||||
CIFS_I(netfile->pInode);
|
||||
pCifsInode->clientCanCacheAll = false;
|
||||
if (pSMB->OplockLevel == 0)
|
||||
pCifsInode->clientCanCacheRead
|
||||
= false;
|
||||
pCifsInode->oplockPending = true;
|
||||
AllocOplockQEntry(netfile->pInode,
|
||||
netfile->netfid,
|
||||
tcon);
|
||||
cFYI(1,
|
||||
("about to wake up oplock thread"));
|
||||
if (oplockThread)
|
||||
wake_up_process(oplockThread);
|
||||
return true;
|
||||
}
|
||||
if (pSMB->Fid != netfile->netfid)
|
||||
continue;
|
||||
|
||||
read_unlock(&cifs_tcp_ses_lock);
|
||||
cFYI(1, ("file id match, oplock break"));
|
||||
pCifsInode = CIFS_I(netfile->pInode);
|
||||
pCifsInode->clientCanCacheAll = false;
|
||||
if (pSMB->OplockLevel == 0)
|
||||
pCifsInode->clientCanCacheRead = false;
|
||||
pCifsInode->oplockPending = true;
|
||||
AllocOplockQEntry(netfile->pInode,
|
||||
netfile->netfid, tcon);
|
||||
cFYI(1, ("about to wake up oplock thread"));
|
||||
if (oplockThread)
|
||||
wake_up_process(oplockThread);
|
||||
|
||||
return true;
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
read_unlock(&cifs_tcp_ses_lock);
|
||||
cFYI(1, ("No matching file for oplock break"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
read_unlock(&cifs_tcp_ses_lock);
|
||||
cFYI(1, ("Can not process oplock break for non-existent connection"));
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user