Commit b35deed4 authored by Pavel Shilovsky's avatar Pavel Shilovsky

Update 3.10 sources from stable (v3.10.18)

parent b0966a09
...@@ -327,14 +327,14 @@ UniToupper(register wchar_t uc) ...@@ -327,14 +327,14 @@ UniToupper(register wchar_t uc)
/* /*
* UniStrupr: Upper case a unicode string * UniStrupr: Upper case a unicode string
*/ */
static inline wchar_t * static inline __le16 *
UniStrupr(register wchar_t *upin) UniStrupr(register __le16 *upin)
{ {
register wchar_t *up; register __le16 *up;
up = upin; up = upin;
while (*up) { /* For all characters */ while (*up) { /* For all characters */
*up = UniToupper(*up); *up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
up++; up++;
} }
return upin; /* Return input pointer */ return upin; /* Return input pointer */
......
...@@ -389,7 +389,7 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -389,7 +389,7 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp)
if (blobptr + attrsize > blobend) if (blobptr + attrsize > blobend)
break; break;
if (type == NTLMSSP_AV_NB_DOMAIN_NAME) { if (type == NTLMSSP_AV_NB_DOMAIN_NAME) {
if (!attrsize) if (!attrsize || attrsize >= CIFS_MAX_DOMAINNAME_LEN)
break; break;
if (!ses->domainName) { if (!ses->domainName) {
ses->domainName = ses->domainName =
...@@ -414,7 +414,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, ...@@ -414,7 +414,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
int rc = 0; int rc = 0;
int len; int len;
char nt_hash[CIFS_NTHASH_SIZE]; char nt_hash[CIFS_NTHASH_SIZE];
wchar_t *user; __le16 *user;
wchar_t *domain; wchar_t *domain;
wchar_t *server; wchar_t *server;
...@@ -439,7 +439,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, ...@@ -439,7 +439,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
return rc; return rc;
} }
/* convert ses->user_name to unicode and uppercase */ /* convert ses->user_name to unicode */
len = ses->user_name ? strlen(ses->user_name) : 0; len = ses->user_name ? strlen(ses->user_name) : 0;
user = kmalloc(2 + (len * 2), GFP_KERNEL); user = kmalloc(2 + (len * 2), GFP_KERNEL);
if (user == NULL) { if (user == NULL) {
...@@ -448,7 +448,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, ...@@ -448,7 +448,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
} }
if (len) { if (len) {
len = cifs_strtoUTF16((__le16 *)user, ses->user_name, len, nls_cp); len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
UniStrupr(user); UniStrupr(user);
} else { } else {
memset(user, '\0', 2); memset(user, '\0', 2);
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1) #define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1)
#define MAX_SERVER_SIZE 15 #define MAX_SERVER_SIZE 15
#define MAX_SHARE_SIZE 80 #define MAX_SHARE_SIZE 80
#define CIFS_MAX_DOMAINNAME_LEN 256 /* max domain name length */
#define MAX_USERNAME_SIZE 256 /* reasonable maximum for current servers */ #define MAX_USERNAME_SIZE 256 /* reasonable maximum for current servers */
#define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */ #define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */
......
...@@ -378,6 +378,7 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -378,6 +378,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
try_to_freeze(); try_to_freeze();
/* we should try only the port we connected to before */ /* we should try only the port we connected to before */
mutex_lock(&server->srv_mutex);
rc = generic_ip_connect(server); rc = generic_ip_connect(server);
if (rc) { if (rc) {
cifs_dbg(FYI, "reconnect error %d\n", rc); cifs_dbg(FYI, "reconnect error %d\n", rc);
...@@ -389,6 +390,7 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -389,6 +390,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
server->tcpStatus = CifsNeedNegotiate; server->tcpStatus = CifsNeedNegotiate;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
} }
mutex_unlock(&server->srv_mutex);
} while (server->tcpStatus == CifsNeedReconnect); } while (server->tcpStatus == CifsNeedReconnect);
return rc; return rc;
...@@ -1667,7 +1669,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, ...@@ -1667,7 +1669,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
if (string == NULL) if (string == NULL)
goto out_nomem; goto out_nomem;
if (strnlen(string, 256) == 256) { if (strnlen(string, CIFS_MAX_DOMAINNAME_LEN)
== CIFS_MAX_DOMAINNAME_LEN) {
printk(KERN_WARNING "CIFS: domain name too" printk(KERN_WARNING "CIFS: domain name too"
" long\n"); " long\n");
goto cifs_parse_mount_err; goto cifs_parse_mount_err;
...@@ -2293,8 +2296,8 @@ cifs_put_smb_ses(struct cifs_ses *ses) ...@@ -2293,8 +2296,8 @@ cifs_put_smb_ses(struct cifs_ses *ses)
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
/* strlen("cifs:a:") + INET6_ADDRSTRLEN + 1 */ /* strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1 */
#define CIFSCREDS_DESC_SIZE (7 + INET6_ADDRSTRLEN + 1) #define CIFSCREDS_DESC_SIZE (7 + CIFS_MAX_DOMAINNAME_LEN + 1)
/* Populate username and pw fields from keyring if possible */ /* Populate username and pw fields from keyring if possible */
static int static int
......
...@@ -495,6 +495,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, ...@@ -495,6 +495,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
if (server->ops->close) if (server->ops->close)
server->ops->close(xid, tcon, &fid); server->ops->close(xid, tcon, &fid);
cifs_del_pending_open(&open); cifs_del_pending_open(&open);
fput(file);
rc = -ENOMEM; rc = -ENOMEM;
} }
......
...@@ -556,11 +556,10 @@ cifs_relock_file(struct cifsFileInfo *cfile) ...@@ -556,11 +556,10 @@ cifs_relock_file(struct cifsFileInfo *cfile)
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
int rc = 0; int rc = 0;
/* we are going to update can_cache_brlcks here - need a write access */ down_read(&cinode->lock_sem);
down_write(&cinode->lock_sem);
if (cinode->can_cache_brlcks) { if (cinode->can_cache_brlcks) {
/* can cache locks - no need to push them */ /* can cache locks - no need to relock */
up_write(&cinode->lock_sem); up_read(&cinode->lock_sem);
return rc; return rc;
} }
...@@ -571,7 +570,7 @@ cifs_relock_file(struct cifsFileInfo *cfile) ...@@ -571,7 +570,7 @@ cifs_relock_file(struct cifsFileInfo *cfile)
else else
rc = tcon->ses->server->ops->push_mand_locks(cfile); rc = tcon->ses->server->ops->push_mand_locks(cfile);
up_write(&cinode->lock_sem); up_read(&cinode->lock_sem);
return rc; return rc;
} }
......
...@@ -558,6 +558,11 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, ...@@ -558,6 +558,11 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
fattr->cf_mode &= ~(S_IWUGO); fattr->cf_mode &= ~(S_IWUGO);
fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
if (fattr->cf_nlink < 1) {
cifs_dbg(1, "replacing bogus file nlink value %u\n",
fattr->cf_nlink);
fattr->cf_nlink = 1;
}
} }
fattr->cf_uid = cifs_sb->mnt_uid; fattr->cf_uid = cifs_sb->mnt_uid;
......
...@@ -111,6 +111,14 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, ...@@ -111,6 +111,14 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
return; return;
} }
/*
* If we know that the inode will need to be revalidated immediately,
* then don't create a new dentry for it. We'll end up doing an on
* the wire call either way and this spares us an invalidation.
*/
if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
return;
dentry = d_alloc(parent, name); dentry = d_alloc(parent, name);
if (!dentry) if (!dentry)
return; return;
......
...@@ -198,7 +198,7 @@ static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses, ...@@ -198,7 +198,7 @@ static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses,
bytes_ret = 0; bytes_ret = 0;
} else } else
bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->domainName, bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->domainName,
256, nls_cp); CIFS_MAX_DOMAINNAME_LEN, nls_cp);
bcc_ptr += 2 * bytes_ret; bcc_ptr += 2 * bytes_ret;
bcc_ptr += 2; /* account for null terminator */ bcc_ptr += 2; /* account for null terminator */
...@@ -256,8 +256,8 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, ...@@ -256,8 +256,8 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
/* copy domain */ /* copy domain */
if (ses->domainName != NULL) { if (ses->domainName != NULL) {
strncpy(bcc_ptr, ses->domainName, 256); strncpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
bcc_ptr += strnlen(ses->domainName, 256); bcc_ptr += strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
} /* else we will send a null domain name } /* else we will send a null domain name
so the server will default to its own domain */ so the server will default to its own domain */
*bcc_ptr = 0; *bcc_ptr = 0;
......
...@@ -413,96 +413,108 @@ cifs_ses_oplock_break(struct work_struct *work) ...@@ -413,96 +413,108 @@ cifs_ses_oplock_break(struct work_struct *work)
} }
static bool static bool
smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server) smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
struct smb2_lease_break_work *lw)
{ {
struct smb2_lease_break *rsp = (struct smb2_lease_break *)buffer; bool found;
struct list_head *tmp, *tmp1, *tmp2; __u8 lease_state;
struct cifs_ses *ses; struct list_head *tmp;
struct cifs_tcon *tcon;
struct cifsInodeInfo *cinode;
struct cifsFileInfo *cfile; struct cifsFileInfo *cfile;
struct cifs_pending_open *open; struct cifs_pending_open *open;
struct smb2_lease_break_work *lw; struct cifsInodeInfo *cinode;
bool found;
int ack_req = le32_to_cpu(rsp->Flags & int ack_req = le32_to_cpu(rsp->Flags &
SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED); SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL); lease_state = smb2_map_lease_to_oplock(rsp->NewLeaseState);
if (!lw)
return false;
INIT_WORK(&lw->lease_break, cifs_ses_oplock_break); list_for_each(tmp, &tcon->openFileList) {
lw->lease_state = rsp->NewLeaseState; cfile = list_entry(tmp, struct cifsFileInfo, tlist);
cinode = CIFS_I(cfile->dentry->d_inode);
cifs_dbg(FYI, "Checking for lease break\n"); if (memcmp(cinode->lease_key, rsp->LeaseKey,
SMB2_LEASE_KEY_SIZE))
continue;
/* look up tcon based on tid & uid */ cifs_dbg(FYI, "found in the open list\n");
spin_lock(&cifs_tcp_ses_lock); cifs_dbg(FYI, "lease key match, lease break 0x%d\n",
list_for_each(tmp, &server->smb_ses_list) { le32_to_cpu(rsp->NewLeaseState));
ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
spin_lock(&cifs_file_list_lock); smb2_set_oplock_level(cinode, lease_state);
list_for_each(tmp1, &ses->tcon_list) {
tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks); if (ack_req)
list_for_each(tmp2, &tcon->openFileList) { cfile->oplock_break_cancelled = false;
cfile = list_entry(tmp2, struct cifsFileInfo, else
tlist); cfile->oplock_break_cancelled = true;
cinode = CIFS_I(cfile->dentry->d_inode);
if (memcmp(cinode->lease_key, rsp->LeaseKey, queue_work(cifsiod_wq, &cfile->oplock_break);
SMB2_LEASE_KEY_SIZE)) kfree(lw);
continue; return true;
}
cifs_dbg(FYI, "found in the open list\n"); found = false;
cifs_dbg(FYI, "lease key match, lease break 0x%d\n", list_for_each_entry(open, &tcon->pending_opens, olist) {
le32_to_cpu(rsp->NewLeaseState)); if (memcmp(open->lease_key, rsp->LeaseKey,
SMB2_LEASE_KEY_SIZE))
continue;
if (!found && ack_req) {
found = true;
memcpy(lw->lease_key, open->lease_key,
SMB2_LEASE_KEY_SIZE);
lw->tlink = cifs_get_tlink(open->tlink);
queue_work(cifsiod_wq, &lw->lease_break);
}
smb2_set_oplock_level(cinode, cifs_dbg(FYI, "found in the pending open list\n");
smb2_map_lease_to_oplock(rsp->NewLeaseState)); cifs_dbg(FYI, "lease key match, lease break 0x%d\n",
le32_to_cpu(rsp->NewLeaseState));
if (ack_req) open->oplock = lease_state;
cfile->oplock_break_cancelled = false; }
else return found;
cfile->oplock_break_cancelled = true; }
queue_work(cifsiod_wq, &cfile->oplock_break); static bool
smb2_is_valid_lease_break(char *buffer)
{
struct smb2_lease_break *rsp = (struct smb2_lease_break *)buffer;
struct list_head *tmp, *tmp1, *tmp2;
struct TCP_Server_Info *server;
struct cifs_ses *ses;
struct cifs_tcon *tcon;
struct smb2_lease_break_work *lw;
spin_unlock(&cifs_file_list_lock); lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
spin_unlock(&cifs_tcp_ses_lock); if (!lw)
return true; return false;
}
found = false; INIT_WORK(&lw->lease_break, cifs_ses_oplock_break);
list_for_each_entry(open, &tcon->pending_opens, olist) { lw->lease_state = rsp->NewLeaseState;
if (memcmp(open->lease_key, rsp->LeaseKey,
SMB2_LEASE_KEY_SIZE))
continue;
if (!found && ack_req) { cifs_dbg(FYI, "Checking for lease break\n");
found = true;
memcpy(lw->lease_key, open->lease_key, /* look up tcon based on tid & uid */
SMB2_LEASE_KEY_SIZE); spin_lock(&cifs_tcp_ses_lock);
lw->tlink = cifs_get_tlink(open->tlink); list_for_each(tmp, &cifs_tcp_ses_list) {
queue_work(cifsiod_wq, server = list_entry(tmp, struct TCP_Server_Info, tcp_ses_list);
&lw->lease_break);
}
cifs_dbg(FYI, "found in the pending open list\n"); list_for_each(tmp1, &server->smb_ses_list) {
cifs_dbg(FYI, "lease key match, lease break 0x%d\n", ses = list_entry(tmp1, struct cifs_ses, smb_ses_list);
le32_to_cpu(rsp->NewLeaseState));
open->oplock = spin_lock(&cifs_file_list_lock);
smb2_map_lease_to_oplock(rsp->NewLeaseState); list_for_each(tmp2, &ses->tcon_list) {
} tcon = list_entry(tmp2, struct cifs_tcon,
if (found) { tcon_list);
spin_unlock(&cifs_file_list_lock); cifs_stats_inc(
spin_unlock(&cifs_tcp_ses_lock); &tcon->stats.cifs_stats.num_oplock_brks);
return true; if (smb2_tcon_has_lease(tcon, rsp, lw)) {
spin_unlock(&cifs_file_list_lock);
spin_unlock(&cifs_tcp_ses_lock);
return true;
}
} }
spin_unlock(&cifs_file_list_lock);
} }
spin_unlock(&cifs_file_list_lock);
} }
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
kfree(lw); kfree(lw);
...@@ -528,7 +540,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) ...@@ -528,7 +540,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
if (rsp->StructureSize != if (rsp->StructureSize !=
smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) { smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) {
if (le16_to_cpu(rsp->StructureSize) == 44) if (le16_to_cpu(rsp->StructureSize) == 44)
return smb2_is_valid_lease_break(buffer, server); return smb2_is_valid_lease_break(buffer);
else else
return false; return false;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment