Commit 8205ae32 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '5.17-rc-part2-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:

 - multichannel fixes, addressing additional reconnect and DFS scenarios

 - reenabling fscache support (indexing rewrite, metadata caching e.g.)

 - send additional version information during NTLMSSP negotiate to
   improve debugging

 - fix for a mount race

 - DFS fixes

 - fix for a memory leak for stable

* tag '5.17-rc-part2-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: update internal module number
  smb3: send NTLMSSP version information
  cifs: Support fscache indexing rewrite
  cifs: cifs_ses_mark_for_reconnect should also update reconnect bits
  cifs: update tcpStatus during negotiate and sess setup
  cifs: make status checks in version independent callers
  cifs: remove repeated state change in dfs tree connect
  cifs: fix the cifs_reconnect path for DFS
  cifs: remove unused variable ses_selected
  cifs: protect all accesses to chan_* with chan_lock
  cifs: fix the connection state transitions with multichannel
  cifs: check reconnects for channels of active tcons too
  smb3: add new defines from protocol specification
  cifs: serialize all mount attempts
  cifs: quirk for STATUS_OBJECT_NAME_INVALID returned for non-ASCII dfs refs
  cifs: alloc_path_with_tree_prefix: do not append sep. if the path is empty
  cifs: clean up an inconsistent indenting
  cifs: free ntlmsspblob allocated in negotiate
parents 1cb69c80 51620150
...@@ -188,7 +188,7 @@ config CIFS_SMB_DIRECT ...@@ -188,7 +188,7 @@ config CIFS_SMB_DIRECT
config CIFS_FSCACHE config CIFS_FSCACHE
bool "Provide CIFS client caching support" bool "Provide CIFS client caching support"
depends on CIFS=m && FSCACHE_OLD_API || CIFS=y && FSCACHE_OLD_API=y depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y
help help
Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data
to be cached locally on disk through the general filesystem cache to be cached locally on disk through the general filesystem cache
......
...@@ -25,7 +25,7 @@ cifs-$(CONFIG_CIFS_DFS_UPCALL) += cifs_dfs_ref.o dfs_cache.o ...@@ -25,7 +25,7 @@ cifs-$(CONFIG_CIFS_DFS_UPCALL) += cifs_dfs_ref.o dfs_cache.o
cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o
cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o
cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o
......
// SPDX-License-Identifier: LGPL-2.1
/*
* CIFS filesystem cache index structure definitions
*
* Copyright (c) 2010 Novell, Inc.
* Authors(s): Suresh Jayaraman (sjayaraman@suse.de>
*
*/
#include "fscache.h"
#include "cifs_debug.h"
/*
* CIFS filesystem definition for FS-Cache
*/
struct fscache_netfs cifs_fscache_netfs = {
.name = "cifs",
.version = 0,
};
/*
* Register CIFS for caching with FS-Cache
*/
int cifs_fscache_register(void)
{
return fscache_register_netfs(&cifs_fscache_netfs);
}
/*
* Unregister CIFS for caching
*/
void cifs_fscache_unregister(void)
{
fscache_unregister_netfs(&cifs_fscache_netfs);
}
/*
* Server object for FS-Cache
*/
const struct fscache_cookie_def cifs_fscache_server_index_def = {
.name = "CIFS.server",
.type = FSCACHE_COOKIE_TYPE_INDEX,
};
static enum
fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data,
const void *data,
uint16_t datalen,
loff_t object_size)
{
struct cifs_fscache_super_auxdata auxdata;
const struct cifs_tcon *tcon = cookie_netfs_data;
if (datalen != sizeof(auxdata))
return FSCACHE_CHECKAUX_OBSOLETE;
memset(&auxdata, 0, sizeof(auxdata));
auxdata.resource_id = tcon->resource_id;
auxdata.vol_create_time = tcon->vol_create_time;
auxdata.vol_serial_number = tcon->vol_serial_number;
if (memcmp(data, &auxdata, datalen) != 0)
return FSCACHE_CHECKAUX_OBSOLETE;
return FSCACHE_CHECKAUX_OKAY;
}
/*
* Superblock object for FS-Cache
*/
const struct fscache_cookie_def cifs_fscache_super_index_def = {
.name = "CIFS.super",
.type = FSCACHE_COOKIE_TYPE_INDEX,
.check_aux = cifs_fscache_super_check_aux,
};
static enum
fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data,
const void *data,
uint16_t datalen,
loff_t object_size)
{
struct cifs_fscache_inode_auxdata auxdata;
struct cifsInodeInfo *cifsi = cookie_netfs_data;
if (datalen != sizeof(auxdata))
return FSCACHE_CHECKAUX_OBSOLETE;
memset(&auxdata, 0, sizeof(auxdata));
auxdata.eof = cifsi->server_eof;
auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec;
auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec;
auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec;
auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
if (memcmp(data, &auxdata, datalen) != 0)
return FSCACHE_CHECKAUX_OBSOLETE;
return FSCACHE_CHECKAUX_OKAY;
}
const struct fscache_cookie_def cifs_fscache_inode_object_def = {
.name = "CIFS.uniqueid",
.type = FSCACHE_COOKIE_TYPE_DATAFILE,
.check_aux = cifs_fscache_inode_check_aux,
};
...@@ -396,11 +396,11 @@ static int cifs_swn_resource_state_changed(struct cifs_swn_reg *swnreg, const ch ...@@ -396,11 +396,11 @@ static int cifs_swn_resource_state_changed(struct cifs_swn_reg *swnreg, const ch
switch (state) { switch (state) {
case CIFS_SWN_RESOURCE_STATE_UNAVAILABLE: case CIFS_SWN_RESOURCE_STATE_UNAVAILABLE:
cifs_dbg(FYI, "%s: resource name '%s' become unavailable\n", __func__, name); cifs_dbg(FYI, "%s: resource name '%s' become unavailable\n", __func__, name);
cifs_ses_mark_for_reconnect(swnreg->tcon->ses); cifs_reconnect(swnreg->tcon->ses->server, true);
break; break;
case CIFS_SWN_RESOURCE_STATE_AVAILABLE: case CIFS_SWN_RESOURCE_STATE_AVAILABLE:
cifs_dbg(FYI, "%s: resource name '%s' become available\n", __func__, name); cifs_dbg(FYI, "%s: resource name '%s' become available\n", __func__, name);
cifs_ses_mark_for_reconnect(swnreg->tcon->ses); cifs_reconnect(swnreg->tcon->ses->server, true);
break; break;
case CIFS_SWN_RESOURCE_STATE_UNKNOWN: case CIFS_SWN_RESOURCE_STATE_UNKNOWN:
cifs_dbg(FYI, "%s: resource name '%s' changed to unknown state\n", __func__, name); cifs_dbg(FYI, "%s: resource name '%s' changed to unknown state\n", __func__, name);
...@@ -498,10 +498,7 @@ static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *a ...@@ -498,10 +498,7 @@ static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *a
goto unlock; goto unlock;
} }
spin_lock(&cifs_tcp_ses_lock); cifs_reconnect(tcon->ses->server, false);
if (tcon->ses->server->tcpStatus != CifsExiting)
tcon->ses->server->tcpStatus = CifsNeedReconnect;
spin_unlock(&cifs_tcp_ses_lock);
unlock: unlock:
mutex_unlock(&tcon->ses->server->srv_mutex); mutex_unlock(&tcon->ses->server->srv_mutex);
......
...@@ -397,6 +397,9 @@ static void ...@@ -397,6 +397,9 @@ static void
cifs_evict_inode(struct inode *inode) cifs_evict_inode(struct inode *inode)
{ {
truncate_inode_pages_final(&inode->i_data); truncate_inode_pages_final(&inode->i_data);
if (inode->i_state & I_PINNING_FSCACHE_WB)
cifs_fscache_unuse_inode_cookie(inode, true);
cifs_fscache_release_inode_cookie(inode);
clear_inode(inode); clear_inode(inode);
} }
...@@ -721,6 +724,12 @@ static int cifs_show_stats(struct seq_file *s, struct dentry *root) ...@@ -721,6 +724,12 @@ static int cifs_show_stats(struct seq_file *s, struct dentry *root)
} }
#endif #endif
static int cifs_write_inode(struct inode *inode, struct writeback_control *wbc)
{
fscache_unpin_writeback(wbc, cifs_inode_cookie(inode));
return 0;
}
static int cifs_drop_inode(struct inode *inode) static int cifs_drop_inode(struct inode *inode)
{ {
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
...@@ -733,6 +742,7 @@ static int cifs_drop_inode(struct inode *inode) ...@@ -733,6 +742,7 @@ static int cifs_drop_inode(struct inode *inode)
static const struct super_operations cifs_super_ops = { static const struct super_operations cifs_super_ops = {
.statfs = cifs_statfs, .statfs = cifs_statfs,
.alloc_inode = cifs_alloc_inode, .alloc_inode = cifs_alloc_inode,
.write_inode = cifs_write_inode,
.free_inode = cifs_free_inode, .free_inode = cifs_free_inode,
.drop_inode = cifs_drop_inode, .drop_inode = cifs_drop_inode,
.evict_inode = cifs_evict_inode, .evict_inode = cifs_evict_inode,
...@@ -1625,13 +1635,9 @@ init_cifs(void) ...@@ -1625,13 +1635,9 @@ init_cifs(void)
goto out_destroy_cifsoplockd_wq; goto out_destroy_cifsoplockd_wq;
} }
rc = cifs_fscache_register();
if (rc)
goto out_destroy_deferredclose_wq;
rc = cifs_init_inodecache(); rc = cifs_init_inodecache();
if (rc) if (rc)
goto out_unreg_fscache; goto out_destroy_deferredclose_wq;
rc = cifs_init_mids(); rc = cifs_init_mids();
if (rc) if (rc)
...@@ -1693,8 +1699,6 @@ init_cifs(void) ...@@ -1693,8 +1699,6 @@ init_cifs(void)
cifs_destroy_mids(); cifs_destroy_mids();
out_destroy_inodecache: out_destroy_inodecache:
cifs_destroy_inodecache(); cifs_destroy_inodecache();
out_unreg_fscache:
cifs_fscache_unregister();
out_destroy_deferredclose_wq: out_destroy_deferredclose_wq:
destroy_workqueue(deferredclose_wq); destroy_workqueue(deferredclose_wq);
out_destroy_cifsoplockd_wq: out_destroy_cifsoplockd_wq:
...@@ -1730,7 +1734,6 @@ exit_cifs(void) ...@@ -1730,7 +1734,6 @@ exit_cifs(void)
cifs_destroy_request_bufs(); cifs_destroy_request_bufs();
cifs_destroy_mids(); cifs_destroy_mids();
cifs_destroy_inodecache(); cifs_destroy_inodecache();
cifs_fscache_unregister();
destroy_workqueue(deferredclose_wq); destroy_workqueue(deferredclose_wq);
destroy_workqueue(cifsoplockd_wq); destroy_workqueue(cifsoplockd_wq);
destroy_workqueue(decrypt_wq); destroy_workqueue(decrypt_wq);
......
...@@ -152,5 +152,6 @@ extern struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type, ...@@ -152,5 +152,6 @@ extern struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type,
extern const struct export_operations cifs_export_ops; extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */ #endif /* CONFIG_CIFS_NFSD_EXPORT */
#define CIFS_VERSION "2.34" #define SMB3_PRODUCT_BUILD 35
#define CIFS_VERSION "2.35"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -117,6 +117,7 @@ enum statusEnum { ...@@ -117,6 +117,7 @@ enum statusEnum {
CifsInSessSetup, CifsInSessSetup,
CifsNeedTcon, CifsNeedTcon,
CifsInTcon, CifsInTcon,
CifsNeedFilesInvalidate,
CifsInFilesInvalidate CifsInFilesInvalidate
}; };
...@@ -667,9 +668,6 @@ struct TCP_Server_Info { ...@@ -667,9 +668,6 @@ struct TCP_Server_Info {
unsigned int total_read; /* total amount of data read in this pass */ unsigned int total_read; /* total amount of data read in this pass */
atomic_t in_send; /* requests trying to send */ atomic_t in_send; /* requests trying to send */
atomic_t num_waiters; /* blocked waiting to get in sendrecv */ atomic_t num_waiters; /* blocked waiting to get in sendrecv */
#ifdef CONFIG_CIFS_FSCACHE
struct fscache_cookie *fscache; /* client index cache cookie */
#endif
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
atomic_t num_cmds[NUMBER_OF_SMB2_COMMANDS]; /* total requests by cmd */ atomic_t num_cmds[NUMBER_OF_SMB2_COMMANDS]; /* total requests by cmd */
atomic_t smb2slowcmd[NUMBER_OF_SMB2_COMMANDS]; /* count resps > 1 sec */ atomic_t smb2slowcmd[NUMBER_OF_SMB2_COMMANDS]; /* count resps > 1 sec */
...@@ -923,6 +921,7 @@ struct cifs_chan { ...@@ -923,6 +921,7 @@ struct cifs_chan {
*/ */
struct cifs_ses { struct cifs_ses {
struct list_head smb_ses_list; struct list_head smb_ses_list;
struct list_head rlist; /* reconnect list */
struct list_head tcon_list; struct list_head tcon_list;
struct cifs_tcon *tcon_ipc; struct cifs_tcon *tcon_ipc;
struct mutex session_mutex; struct mutex session_mutex;
...@@ -1110,7 +1109,7 @@ struct cifs_tcon { ...@@ -1110,7 +1109,7 @@ struct cifs_tcon {
__u32 max_bytes_copy; __u32 max_bytes_copy;
#ifdef CONFIG_CIFS_FSCACHE #ifdef CONFIG_CIFS_FSCACHE
u64 resource_id; /* server resource id */ u64 resource_id; /* server resource id */
struct fscache_cookie *fscache; /* cookie for share */ struct fscache_volume *fscache; /* cookie for share */
#endif #endif
struct list_head pending_opens; /* list of incomplete opens */ struct list_head pending_opens; /* list of incomplete opens */
struct cached_fid crfid; /* Cached root fid */ struct cached_fid crfid; /* Cached root fid */
......
...@@ -131,6 +131,9 @@ extern int SendReceiveBlockingLock(const unsigned int xid, ...@@ -131,6 +131,9 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
struct smb_hdr *in_buf , struct smb_hdr *in_buf ,
struct smb_hdr *out_buf, struct smb_hdr *out_buf,
int *bytes_returned); int *bytes_returned);
void
cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
bool mark_smb_session);
extern int cifs_reconnect(struct TCP_Server_Info *server, extern int cifs_reconnect(struct TCP_Server_Info *server,
bool mark_smb_session); bool mark_smb_session);
extern int checkSMB(char *buf, unsigned int len, struct TCP_Server_Info *srvr); extern int checkSMB(char *buf, unsigned int len, struct TCP_Server_Info *srvr);
...@@ -647,6 +650,11 @@ static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses, ...@@ -647,6 +650,11 @@ static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
int match_target_ip(struct TCP_Server_Info *server, int match_target_ip(struct TCP_Server_Info *server,
const char *share, size_t share_len, const char *share, size_t share_len,
bool *result); bool *result);
int cifs_dfs_query_info_nonascii_quirk(const unsigned int xid,
struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const char *dfs_link_path);
#endif #endif
static inline int cifs_create_options(struct cifs_sb_info *cifs_sb, int options) static inline int cifs_create_options(struct cifs_sb_info *cifs_sb, int options)
......
This diff is collapsed.
...@@ -1355,7 +1355,7 @@ static void mark_for_reconnect_if_needed(struct cifs_tcon *tcon, struct dfs_cach ...@@ -1355,7 +1355,7 @@ static void mark_for_reconnect_if_needed(struct cifs_tcon *tcon, struct dfs_cach
} }
cifs_dbg(FYI, "%s: no cached or matched targets. mark dfs share for reconnect.\n", __func__); cifs_dbg(FYI, "%s: no cached or matched targets. mark dfs share for reconnect.\n", __func__);
cifs_ses_mark_for_reconnect(tcon->ses); cifs_reconnect(tcon->ses->server, true);
} }
/* Refresh dfs referral of tcon and mark it for reconnect if needed */ /* Refresh dfs referral of tcon and mark it for reconnect if needed */
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "cifs_unicode.h" #include "cifs_unicode.h"
#include "fs_context.h" #include "fs_context.h"
#include "cifs_ioctl.h" #include "cifs_ioctl.h"
#include "fscache.h"
static void static void
renew_parental_timestamps(struct dentry *direntry) renew_parental_timestamps(struct dentry *direntry)
...@@ -507,8 +508,12 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, ...@@ -507,8 +508,12 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
server->ops->close(xid, tcon, &fid); server->ops->close(xid, tcon, &fid);
cifs_del_pending_open(&open); cifs_del_pending_open(&open);
rc = -ENOMEM; rc = -ENOMEM;
goto out;
} }
fscache_use_cookie(cifs_inode_cookie(file_inode(file)),
file->f_mode & FMODE_WRITE);
out: out:
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
out_free_xid: out_free_xid:
......
...@@ -376,8 +376,6 @@ static void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file) ...@@ -376,8 +376,6 @@ static void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file)
struct cifsLockInfo *li, *tmp; struct cifsLockInfo *li, *tmp;
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
cifs_fscache_release_inode_cookie(inode);
/* /*
* Delete any outstanding lock records. We'll lose them when the file * Delete any outstanding lock records. We'll lose them when the file
* is closed anyway. * is closed anyway.
...@@ -570,7 +568,7 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -570,7 +568,7 @@ int cifs_open(struct inode *inode, struct file *file)
spin_lock(&CIFS_I(inode)->deferred_lock); spin_lock(&CIFS_I(inode)->deferred_lock);
cifs_del_deferred_close(cfile); cifs_del_deferred_close(cfile);
spin_unlock(&CIFS_I(inode)->deferred_lock); spin_unlock(&CIFS_I(inode)->deferred_lock);
goto out; goto use_cache;
} else { } else {
_cifsFileInfo_put(cfile, true, false); _cifsFileInfo_put(cfile, true, false);
} }
...@@ -632,8 +630,6 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -632,8 +630,6 @@ int cifs_open(struct inode *inode, struct file *file)
goto out; goto out;
} }
cifs_fscache_set_inode_cookie(inode, file);
if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) { if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
/* /*
* Time to set mode which we can not set earlier due to * Time to set mode which we can not set earlier due to
...@@ -652,6 +648,15 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -652,6 +648,15 @@ int cifs_open(struct inode *inode, struct file *file)
cfile->pid); cfile->pid);
} }
use_cache:
fscache_use_cookie(cifs_inode_cookie(file_inode(file)),
file->f_mode & FMODE_WRITE);
if (file->f_flags & O_DIRECT &&
(!((file->f_flags & O_ACCMODE) != O_RDONLY) ||
file->f_flags & O_APPEND))
cifs_invalidate_cache(file_inode(file),
FSCACHE_INVAL_DIO_WRITE);
out: out:
free_dentry_path(page); free_dentry_path(page);
free_xid(xid); free_xid(xid);
...@@ -876,6 +881,8 @@ int cifs_close(struct inode *inode, struct file *file) ...@@ -876,6 +881,8 @@ int cifs_close(struct inode *inode, struct file *file)
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifs_deferred_close *dclose; struct cifs_deferred_close *dclose;
cifs_fscache_unuse_inode_cookie(inode, file->f_mode & FMODE_WRITE);
if (file->private_data != NULL) { if (file->private_data != NULL) {
cfile = file->private_data; cfile = file->private_data;
file->private_data = NULL; file->private_data = NULL;
...@@ -886,7 +893,6 @@ int cifs_close(struct inode *inode, struct file *file) ...@@ -886,7 +893,6 @@ int cifs_close(struct inode *inode, struct file *file)
dclose) { dclose) {
if (test_and_clear_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) { if (test_and_clear_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) {
inode->i_ctime = inode->i_mtime = current_time(inode); inode->i_ctime = inode->i_mtime = current_time(inode);
cifs_fscache_update_inode_cookie(inode);
} }
spin_lock(&cinode->deferred_lock); spin_lock(&cinode->deferred_lock);
cifs_add_deferred_close(cfile, dclose); cifs_add_deferred_close(cfile, dclose);
...@@ -4198,10 +4204,12 @@ static vm_fault_t ...@@ -4198,10 +4204,12 @@ static vm_fault_t
cifs_page_mkwrite(struct vm_fault *vmf) cifs_page_mkwrite(struct vm_fault *vmf)
{ {
struct page *page = vmf->page; struct page *page = vmf->page;
struct file *file = vmf->vma->vm_file;
struct inode *inode = file_inode(file);
cifs_fscache_wait_on_page_write(inode, page); #ifdef CONFIG_CIFS_FSCACHE
if (PageFsCache(page) &&
wait_on_page_fscache_killable(page) < 0)
return VM_FAULT_RETRY;
#endif
lock_page(page); lock_page(page);
return VM_FAULT_LOCKED; return VM_FAULT_LOCKED;
...@@ -4275,8 +4283,6 @@ cifs_readv_complete(struct work_struct *work) ...@@ -4275,8 +4283,6 @@ cifs_readv_complete(struct work_struct *work)
if (rdata->result == 0 || if (rdata->result == 0 ||
(rdata->result == -EAGAIN && got_bytes)) (rdata->result == -EAGAIN && got_bytes))
cifs_readpage_to_fscache(rdata->mapping->host, page); cifs_readpage_to_fscache(rdata->mapping->host, page);
else
cifs_fscache_uncache_page(rdata->mapping->host, page);
got_bytes -= min_t(unsigned int, PAGE_SIZE, got_bytes); got_bytes -= min_t(unsigned int, PAGE_SIZE, got_bytes);
...@@ -4593,11 +4599,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -4593,11 +4599,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
kref_put(&rdata->refcount, cifs_readdata_release); kref_put(&rdata->refcount, cifs_readdata_release);
} }
/* Any pages that have been shown to fscache but didn't get added to
* the pagecache must be uncached before they get returned to the
* allocator.
*/
cifs_fscache_readpages_cancel(mapping->host, page_list);
free_xid(xid); free_xid(xid);
return rc; return rc;
} }
...@@ -4801,17 +4802,19 @@ static int cifs_release_page(struct page *page, gfp_t gfp) ...@@ -4801,17 +4802,19 @@ static int cifs_release_page(struct page *page, gfp_t gfp)
{ {
if (PagePrivate(page)) if (PagePrivate(page))
return 0; return 0;
if (PageFsCache(page)) {
return cifs_fscache_release_page(page, gfp); if (current_is_kswapd() || !(gfp & __GFP_FS))
return false;
wait_on_page_fscache(page);
}
fscache_note_page_release(cifs_inode_cookie(page->mapping->host));
return true;
} }
static void cifs_invalidate_page(struct page *page, unsigned int offset, static void cifs_invalidate_page(struct page *page, unsigned int offset,
unsigned int length) unsigned int length)
{ {
struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host); wait_on_page_fscache(page);
if (offset == 0 && length == PAGE_SIZE)
cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
} }
static int cifs_launder_page(struct page *page) static int cifs_launder_page(struct page *page)
...@@ -4831,7 +4834,7 @@ static int cifs_launder_page(struct page *page) ...@@ -4831,7 +4834,7 @@ static int cifs_launder_page(struct page *page)
if (clear_page_dirty_for_io(page)) if (clear_page_dirty_for_io(page))
rc = cifs_writepage_locked(page, &wbc); rc = cifs_writepage_locked(page, &wbc);
cifs_fscache_invalidate_page(page, page->mapping->host); wait_on_page_fscache(page);
return rc; return rc;
} }
...@@ -4988,6 +4991,19 @@ static void cifs_swap_deactivate(struct file *file) ...@@ -4988,6 +4991,19 @@ static void cifs_swap_deactivate(struct file *file)
/* do we need to unpin (or unlock) the file */ /* do we need to unpin (or unlock) the file */
} }
/*
* Mark a page as having been made dirty and thus needing writeback. We also
* need to pin the cache object to write back to.
*/
#ifdef CONFIG_CIFS_FSCACHE
static int cifs_set_page_dirty(struct page *page)
{
return fscache_set_page_dirty(page, cifs_inode_cookie(page->mapping->host));
}
#else
#define cifs_set_page_dirty __set_page_dirty_nobuffers
#endif
const struct address_space_operations cifs_addr_ops = { const struct address_space_operations cifs_addr_ops = {
.readpage = cifs_readpage, .readpage = cifs_readpage,
.readpages = cifs_readpages, .readpages = cifs_readpages,
...@@ -4995,7 +5011,7 @@ const struct address_space_operations cifs_addr_ops = { ...@@ -4995,7 +5011,7 @@ const struct address_space_operations cifs_addr_ops = {
.writepages = cifs_writepages, .writepages = cifs_writepages,
.write_begin = cifs_write_begin, .write_begin = cifs_write_begin,
.write_end = cifs_write_end, .write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers, .set_page_dirty = cifs_set_page_dirty,
.releasepage = cifs_release_page, .releasepage = cifs_release_page,
.direct_IO = cifs_direct_io, .direct_IO = cifs_direct_io,
.invalidatepage = cifs_invalidate_page, .invalidatepage = cifs_invalidate_page,
...@@ -5020,7 +5036,7 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { ...@@ -5020,7 +5036,7 @@ const struct address_space_operations cifs_addr_ops_smallbuf = {
.writepages = cifs_writepages, .writepages = cifs_writepages,
.write_begin = cifs_write_begin, .write_begin = cifs_write_begin,
.write_end = cifs_write_end, .write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers, .set_page_dirty = cifs_set_page_dirty,
.releasepage = cifs_release_page, .releasepage = cifs_release_page,
.invalidatepage = cifs_invalidate_page, .invalidatepage = cifs_invalidate_page,
.launder_page = cifs_launder_page, .launder_page = cifs_launder_page,
......
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
#include "rfc1002pdu.h" #include "rfc1002pdu.h"
#include "fs_context.h" #include "fs_context.h"
static DEFINE_MUTEX(cifs_mount_mutex);
static const match_table_t cifs_smb_version_tokens = { static const match_table_t cifs_smb_version_tokens = {
{ Smb_1, SMB1_VERSION_STRING }, { Smb_1, SMB1_VERSION_STRING },
{ Smb_20, SMB20_VERSION_STRING}, { Smb_20, SMB20_VERSION_STRING},
...@@ -707,10 +709,14 @@ static int smb3_get_tree_common(struct fs_context *fc) ...@@ -707,10 +709,14 @@ static int smb3_get_tree_common(struct fs_context *fc)
static int smb3_get_tree(struct fs_context *fc) static int smb3_get_tree(struct fs_context *fc)
{ {
int err = smb3_fs_context_validate(fc); int err = smb3_fs_context_validate(fc);
int ret;
if (err) if (err)
return err; return err;
return smb3_get_tree_common(fc); mutex_lock(&cifs_mount_mutex);
ret = smb3_get_tree_common(fc);
mutex_unlock(&cifs_mount_mutex);
return ret;
} }
static void smb3_fs_context_free(struct fs_context *fc) static void smb3_fs_context_free(struct fs_context *fc)
......
This diff is collapsed.
...@@ -13,84 +13,71 @@ ...@@ -13,84 +13,71 @@
#include "cifsglob.h" #include "cifsglob.h"
#ifdef CONFIG_CIFS_FSCACHE
/* /*
* Auxiliary data attached to CIFS superblock within the cache * Coherency data attached to CIFS volume within the cache
*/ */
struct cifs_fscache_super_auxdata { struct cifs_fscache_volume_coherency_data {
u64 resource_id; /* unique server resource id */ __le64 resource_id; /* unique server resource id */
__le64 vol_create_time; __le64 vol_create_time;
u32 vol_serial_number; __le32 vol_serial_number;
} __packed; } __packed;
/* /*
* Auxiliary data attached to CIFS inode within the cache * Coherency data attached to CIFS inode within the cache.
*/ */
struct cifs_fscache_inode_auxdata { struct cifs_fscache_inode_coherency_data {
u64 last_write_time_sec; __le64 last_write_time_sec;
u64 last_change_time_sec; __le64 last_change_time_sec;
u32 last_write_time_nsec; __le32 last_write_time_nsec;
u32 last_change_time_nsec; __le32 last_change_time_nsec;
u64 eof;
}; };
/* #ifdef CONFIG_CIFS_FSCACHE
* cache.c
*/
extern struct fscache_netfs cifs_fscache_netfs;
extern const struct fscache_cookie_def cifs_fscache_server_index_def;
extern const struct fscache_cookie_def cifs_fscache_super_index_def;
extern const struct fscache_cookie_def cifs_fscache_inode_object_def;
extern int cifs_fscache_register(void);
extern void cifs_fscache_unregister(void);
/* /*
* fscache.c * fscache.c
*/ */
extern void cifs_fscache_get_client_cookie(struct TCP_Server_Info *); extern int cifs_fscache_get_super_cookie(struct cifs_tcon *);
extern void cifs_fscache_release_client_cookie(struct TCP_Server_Info *);
extern void cifs_fscache_get_super_cookie(struct cifs_tcon *);
extern void cifs_fscache_release_super_cookie(struct cifs_tcon *); extern void cifs_fscache_release_super_cookie(struct cifs_tcon *);
extern void cifs_fscache_get_inode_cookie(struct inode *inode);
extern void cifs_fscache_release_inode_cookie(struct inode *); extern void cifs_fscache_release_inode_cookie(struct inode *);
extern void cifs_fscache_update_inode_cookie(struct inode *inode); extern void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update);
extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *);
extern void cifs_fscache_reset_inode_cookie(struct inode *); static inline
void cifs_fscache_fill_coherency(struct inode *inode,
struct cifs_fscache_inode_coherency_data *cd)
{
struct cifsInodeInfo *cifsi = CIFS_I(inode);
memset(cd, 0, sizeof(*cd));
cd->last_write_time_sec = cpu_to_le64(cifsi->vfs_inode.i_mtime.tv_sec);
cd->last_write_time_nsec = cpu_to_le32(cifsi->vfs_inode.i_mtime.tv_nsec);
cd->last_change_time_sec = cpu_to_le64(cifsi->vfs_inode.i_ctime.tv_sec);
cd->last_change_time_nsec = cpu_to_le32(cifsi->vfs_inode.i_ctime.tv_nsec);
}
extern void __cifs_fscache_invalidate_page(struct page *, struct inode *);
extern void __cifs_fscache_wait_on_page_write(struct inode *inode, struct page *page);
extern void __cifs_fscache_uncache_page(struct inode *inode, struct page *page);
extern int cifs_fscache_release_page(struct page *page, gfp_t gfp); extern int cifs_fscache_release_page(struct page *page, gfp_t gfp);
extern int __cifs_readpage_from_fscache(struct inode *, struct page *); extern int __cifs_readpage_from_fscache(struct inode *, struct page *);
extern int __cifs_readpages_from_fscache(struct inode *, extern int __cifs_readpages_from_fscache(struct inode *,
struct address_space *, struct address_space *,
struct list_head *, struct list_head *,
unsigned *); unsigned *);
extern void __cifs_fscache_readpages_cancel(struct inode *, struct list_head *);
extern void __cifs_readpage_to_fscache(struct inode *, struct page *); extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
static inline void cifs_fscache_invalidate_page(struct page *page, static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode)
struct inode *inode)
{ {
if (PageFsCache(page)) return CIFS_I(inode)->fscache;
__cifs_fscache_invalidate_page(page, inode);
} }
static inline void cifs_fscache_wait_on_page_write(struct inode *inode, static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags)
struct page *page)
{ {
if (PageFsCache(page)) struct cifs_fscache_inode_coherency_data cd;
__cifs_fscache_wait_on_page_write(inode, page);
}
static inline void cifs_fscache_uncache_page(struct inode *inode, cifs_fscache_fill_coherency(inode, &cd);
struct page *page) fscache_invalidate(cifs_inode_cookie(inode), &cd,
{ i_size_read(inode), flags);
if (PageFsCache(page))
__cifs_fscache_uncache_page(inode, page);
} }
static inline int cifs_readpage_from_fscache(struct inode *inode, static inline int cifs_readpage_from_fscache(struct inode *inode,
...@@ -120,41 +107,21 @@ static inline void cifs_readpage_to_fscache(struct inode *inode, ...@@ -120,41 +107,21 @@ static inline void cifs_readpage_to_fscache(struct inode *inode,
__cifs_readpage_to_fscache(inode, page); __cifs_readpage_to_fscache(inode, page);
} }
static inline void cifs_fscache_readpages_cancel(struct inode *inode, #else /* CONFIG_CIFS_FSCACHE */
struct list_head *pages) static inline
void cifs_fscache_fill_coherency(struct inode *inode,
struct cifs_fscache_inode_coherency_data *cd)
{ {
if (CIFS_I(inode)->fscache)
return __cifs_fscache_readpages_cancel(inode, pages);
} }
#else /* CONFIG_CIFS_FSCACHE */ static inline int cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) { return 0; }
static inline int cifs_fscache_register(void) { return 0; } static inline void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) {}
static inline void cifs_fscache_unregister(void) {}
static inline void
cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) {}
static inline void
cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) {}
static inline void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) {}
static inline void
cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) {}
static inline void cifs_fscache_get_inode_cookie(struct inode *inode) {}
static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {} static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {}
static inline void cifs_fscache_update_inode_cookie(struct inode *inode) {} static inline void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update) {}
static inline void cifs_fscache_set_inode_cookie(struct inode *inode, static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) { return NULL; }
struct file *filp) {} static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags) {}
static inline void cifs_fscache_reset_inode_cookie(struct inode *inode) {}
static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp)
{
return 1; /* May release page */
}
static inline void cifs_fscache_invalidate_page(struct page *page,
struct inode *inode) {}
static inline void cifs_fscache_wait_on_page_write(struct inode *inode,
struct page *page) {}
static inline void cifs_fscache_uncache_page(struct inode *inode,
struct page *page) {}
static inline int static inline int
cifs_readpage_from_fscache(struct inode *inode, struct page *page) cifs_readpage_from_fscache(struct inode *inode, struct page *page)
...@@ -173,11 +140,6 @@ static inline int cifs_readpages_from_fscache(struct inode *inode, ...@@ -173,11 +140,6 @@ static inline int cifs_readpages_from_fscache(struct inode *inode,
static inline void cifs_readpage_to_fscache(struct inode *inode, static inline void cifs_readpage_to_fscache(struct inode *inode,
struct page *page) {} struct page *page) {}
static inline void cifs_fscache_readpages_cancel(struct inode *inode,
struct list_head *pages)
{
}
#endif /* CONFIG_CIFS_FSCACHE */ #endif /* CONFIG_CIFS_FSCACHE */
#endif /* _CIFS_FSCACHE_H */ #endif /* _CIFS_FSCACHE_H */
...@@ -952,6 +952,12 @@ cifs_get_inode_info(struct inode **inode, ...@@ -952,6 +952,12 @@ cifs_get_inode_info(struct inode **inode,
rc = server->ops->query_path_info(xid, tcon, cifs_sb, rc = server->ops->query_path_info(xid, tcon, cifs_sb,
full_path, tmp_data, full_path, tmp_data,
&adjust_tz, &is_reparse_point); &adjust_tz, &is_reparse_point);
#ifdef CONFIG_CIFS_DFS_UPCALL
if (rc == -ENOENT && is_tcon_dfs(tcon))
rc = cifs_dfs_query_info_nonascii_quirk(xid, tcon,
cifs_sb,
full_path);
#endif
data = tmp_data; data = tmp_data;
} }
...@@ -1298,10 +1304,7 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) ...@@ -1298,10 +1304,7 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
inode->i_flags |= S_NOATIME | S_NOCMTIME; inode->i_flags |= S_NOATIME | S_NOCMTIME;
if (inode->i_state & I_NEW) { if (inode->i_state & I_NEW) {
inode->i_ino = hash; inode->i_ino = hash;
#ifdef CONFIG_CIFS_FSCACHE cifs_fscache_get_inode_cookie(inode);
/* initialize per-inode cache cookie pointer */
CIFS_I(inode)->fscache = NULL;
#endif
unlock_new_inode(inode); unlock_new_inode(inode);
} }
} }
...@@ -1370,6 +1373,7 @@ struct inode *cifs_root_iget(struct super_block *sb) ...@@ -1370,6 +1373,7 @@ struct inode *cifs_root_iget(struct super_block *sb)
iget_failed(inode); iget_failed(inode);
inode = ERR_PTR(rc); inode = ERR_PTR(rc);
} }
out: out:
kfree(path); kfree(path);
free_xid(xid); free_xid(xid);
...@@ -2257,6 +2261,8 @@ cifs_dentry_needs_reval(struct dentry *dentry) ...@@ -2257,6 +2261,8 @@ cifs_dentry_needs_reval(struct dentry *dentry)
int int
cifs_invalidate_mapping(struct inode *inode) cifs_invalidate_mapping(struct inode *inode)
{ {
struct cifs_fscache_inode_coherency_data cd;
struct cifsInodeInfo *cifsi = CIFS_I(inode);
int rc = 0; int rc = 0;
if (inode->i_mapping && inode->i_mapping->nrpages != 0) { if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
...@@ -2266,7 +2272,8 @@ cifs_invalidate_mapping(struct inode *inode) ...@@ -2266,7 +2272,8 @@ cifs_invalidate_mapping(struct inode *inode)
__func__, inode); __func__, inode);
} }
cifs_fscache_reset_inode_cookie(inode); cifs_fscache_fill_coherency(&cifsi->vfs_inode, &cd);
fscache_invalidate(cifs_inode_cookie(inode), &cd, i_size_read(inode), 0);
return rc; return rc;
} }
...@@ -2771,8 +2778,10 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) ...@@ -2771,8 +2778,10 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
goto out; goto out;
if ((attrs->ia_valid & ATTR_SIZE) && if ((attrs->ia_valid & ATTR_SIZE) &&
attrs->ia_size != i_size_read(inode)) attrs->ia_size != i_size_read(inode)) {
truncate_setsize(inode, attrs->ia_size); truncate_setsize(inode, attrs->ia_size);
fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
}
setattr_copy(&init_user_ns, inode, attrs); setattr_copy(&init_user_ns, inode, attrs);
mark_inode_dirty(inode); mark_inode_dirty(inode);
...@@ -2967,8 +2976,10 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) ...@@ -2967,8 +2976,10 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
goto cifs_setattr_exit; goto cifs_setattr_exit;
if ((attrs->ia_valid & ATTR_SIZE) && if ((attrs->ia_valid & ATTR_SIZE) &&
attrs->ia_size != i_size_read(inode)) attrs->ia_size != i_size_read(inode)) {
truncate_setsize(inode, attrs->ia_size); truncate_setsize(inode, attrs->ia_size);
fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
}
setattr_copy(&init_user_ns, inode, attrs); setattr_copy(&init_user_ns, inode, attrs);
mark_inode_dirty(inode); mark_inode_dirty(inode);
......
...@@ -1302,4 +1302,53 @@ int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix) ...@@ -1302,4 +1302,53 @@ int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
return 0; return 0;
} }
/** cifs_dfs_query_info_nonascii_quirk
* Handle weird Windows SMB server behaviour. It responds with
* STATUS_OBJECT_NAME_INVALID code to SMB2 QUERY_INFO request
* for "\<server>\<dfsname>\<linkpath>" DFS reference,
* where <dfsname> contains non-ASCII unicode symbols.
*
* Check such DFS reference and emulate -ENOENT if it is actual.
*/
int cifs_dfs_query_info_nonascii_quirk(const unsigned int xid,
struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const char *linkpath)
{
char *treename, *dfspath, sep;
int treenamelen, linkpathlen, rc;
treename = tcon->treeName;
/* MS-DFSC: All paths in REQ_GET_DFS_REFERRAL and RESP_GET_DFS_REFERRAL
* messages MUST be encoded with exactly one leading backslash, not two
* leading backslashes.
*/
sep = CIFS_DIR_SEP(cifs_sb);
if (treename[0] == sep && treename[1] == sep)
treename++;
linkpathlen = strlen(linkpath);
treenamelen = strnlen(treename, MAX_TREE_SIZE + 1);
dfspath = kzalloc(treenamelen + linkpathlen + 1, GFP_KERNEL);
if (!dfspath)
return -ENOMEM;
if (treenamelen)
memcpy(dfspath, treename, treenamelen);
memcpy(dfspath + treenamelen, linkpath, linkpathlen);
rc = dfs_cache_find(xid, tcon->ses, cifs_sb->local_nls,
cifs_remap(cifs_sb), dfspath, NULL, NULL);
if (rc == 0) {
cifs_dbg(FYI, "DFS ref '%s' is found, emulate -EREMOTE\n",
dfspath);
rc = -EREMOTE;
} else if (rc == -EEXIST) {
cifs_dbg(FYI, "DFS ref '%s' is not found, emulate -ENOENT\n",
dfspath);
rc = -ENOENT;
} else {
cifs_dbg(FYI, "%s: dfs_cache_find returned %d\n", __func__, rc);
}
kfree(dfspath);
return rc;
}
#endif #endif
...@@ -896,10 +896,7 @@ map_and_check_smb_error(struct mid_q_entry *mid, bool logErr) ...@@ -896,10 +896,7 @@ map_and_check_smb_error(struct mid_q_entry *mid, bool logErr)
if (class == ERRSRV && code == ERRbaduid) { if (class == ERRSRV && code == ERRbaduid) {
cifs_dbg(FYI, "Server returned 0x%x, reconnecting session...\n", cifs_dbg(FYI, "Server returned 0x%x, reconnecting session...\n",
code); code);
spin_lock(&cifs_tcp_ses_lock); cifs_reconnect(mid->server, false);
if (mid->server->tcpStatus != CifsExiting)
mid->server->tcpStatus = CifsNeedReconnect;
spin_unlock(&cifs_tcp_ses_lock);
} }
} }
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#define NTLMSSP_REQUEST_NON_NT_KEY 0x400000 #define NTLMSSP_REQUEST_NON_NT_KEY 0x400000
#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000
/* #define reserved4 0x1000000 */ /* #define reserved4 0x1000000 */
#define NTLMSSP_NEGOTIATE_VERSION 0x2000000 /* we do not set */ #define NTLMSSP_NEGOTIATE_VERSION 0x2000000 /* we only set for SMB2+ */
/* #define reserved3 0x4000000 */ /* #define reserved3 0x4000000 */
/* #define reserved2 0x8000000 */ /* #define reserved2 0x8000000 */
/* #define reserved1 0x10000000 */ /* #define reserved1 0x10000000 */
...@@ -87,6 +87,30 @@ typedef struct _NEGOTIATE_MESSAGE { ...@@ -87,6 +87,30 @@ typedef struct _NEGOTIATE_MESSAGE {
/* followed by WorkstationString */ /* followed by WorkstationString */
} __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; } __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
#define NTLMSSP_REVISION_W2K3 0x0F
/* See MS-NLMP section 2.2.2.10 */
struct ntlmssp_version {
__u8 ProductMajorVersion;
__u8 ProductMinorVersion;
__le16 ProductBuild; /* we send the cifs.ko module version here */
__u8 Reserved[3];
__u8 NTLMRevisionCurrent; /* currently 0x0F */
} __packed;
/* see MS-NLMP section 2.2.1.1 */
struct negotiate_message {
__u8 Signature[sizeof(NTLMSSP_SIGNATURE)];
__le32 MessageType; /* NtLmNegotiate = 1 */
__le32 NegotiateFlags;
SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */
SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */
struct ntlmssp_version Version;
/* SECURITY_BUFFER */
char DomainString[0];
/* followed by WorkstationString */
} __packed;
typedef struct _CHALLENGE_MESSAGE { typedef struct _CHALLENGE_MESSAGE {
__u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; __u8 Signature[sizeof(NTLMSSP_SIGNATURE)];
__le32 MessageType; /* NtLmChallenge = 2 */ __le32 MessageType; /* NtLmChallenge = 2 */
...@@ -123,6 +147,10 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, u16 *buflen, ...@@ -123,6 +147,10 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, u16 *buflen,
struct cifs_ses *ses, struct cifs_ses *ses,
struct TCP_Server_Info *server, struct TCP_Server_Info *server,
const struct nls_table *nls_cp); const struct nls_table *nls_cp);
int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, u16 *buflen,
struct cifs_ses *ses,
struct TCP_Server_Info *server,
const struct nls_table *nls_cp);
int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen,
struct cifs_ses *ses, struct cifs_ses *ses,
struct TCP_Server_Info *server, struct TCP_Server_Info *server,
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include "nterr.h" #include "nterr.h"
#include <linux/utsname.h> #include <linux/utsname.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/version.h>
#include "cifsfs.h"
#include "cifs_spnego.h" #include "cifs_spnego.h"
#include "smb2proto.h" #include "smb2proto.h"
#include "fs_context.h" #include "fs_context.h"
...@@ -65,6 +67,8 @@ bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface) ...@@ -65,6 +67,8 @@ bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface)
return false; return false;
} }
/* channel helper functions. assumed that chan_lock is held by caller. */
unsigned int unsigned int
cifs_ses_get_chan_index(struct cifs_ses *ses, cifs_ses_get_chan_index(struct cifs_ses *ses,
struct TCP_Server_Info *server) struct TCP_Server_Info *server)
...@@ -134,10 +138,10 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) ...@@ -134,10 +138,10 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
left = ses->chan_max - ses->chan_count; left = ses->chan_max - ses->chan_count;
if (left <= 0) { if (left <= 0) {
spin_unlock(&ses->chan_lock);
cifs_dbg(FYI, cifs_dbg(FYI,
"ses already at max_channels (%zu), nothing to open\n", "ses already at max_channels (%zu), nothing to open\n",
ses->chan_max); ses->chan_max);
spin_unlock(&ses->chan_lock);
return 0; return 0;
} }
...@@ -364,19 +368,6 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, ...@@ -364,19 +368,6 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
return rc; return rc;
} }
/* Mark all session channels for reconnect */
void cifs_ses_mark_for_reconnect(struct cifs_ses *ses)
{
int i;
for (i = 0; i < ses->chan_count; i++) {
spin_lock(&cifs_tcp_ses_lock);
if (ses->chans[i].server->tcpStatus != CifsExiting)
ses->chans[i].server->tcpStatus = CifsNeedReconnect;
spin_unlock(&cifs_tcp_ses_lock);
}
}
static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, static __u32 cifs_ssetup_hdr(struct cifs_ses *ses,
struct TCP_Server_Info *server, struct TCP_Server_Info *server,
SESSION_SETUP_ANDX *pSMB) SESSION_SETUP_ANDX *pSMB)
...@@ -820,6 +811,74 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, ...@@ -820,6 +811,74 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffer,
return rc; return rc;
} }
/*
* Build ntlmssp blob with additional fields, such as version,
* supported by modern servers. For safety limit to SMB3 or later
* See notes in MS-NLMP Section 2.2.2.1 e.g.
*/
int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer,
u16 *buflen,
struct cifs_ses *ses,
struct TCP_Server_Info *server,
const struct nls_table *nls_cp)
{
int rc = 0;
struct negotiate_message *sec_blob;
__u32 flags;
unsigned char *tmp;
int len;
len = size_of_ntlmssp_blob(ses, sizeof(struct negotiate_message));
*pbuffer = kmalloc(len, GFP_KERNEL);
if (!*pbuffer) {
rc = -ENOMEM;
cifs_dbg(VFS, "Error %d during NTLMSSP allocation\n", rc);
*buflen = 0;
goto setup_ntlm_smb3_neg_ret;
}
sec_blob = (struct negotiate_message *)*pbuffer;
memset(*pbuffer, 0, sizeof(struct negotiate_message));
memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
sec_blob->MessageType = NtLmNegotiate;
/* BB is NTLMV2 session security format easier to use here? */
flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET |
NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_SEAL |
NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_VERSION;
if (!server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
sec_blob->Version.ProductMajorVersion = LINUX_VERSION_MAJOR;
sec_blob->Version.ProductMinorVersion = LINUX_VERSION_PATCHLEVEL;
sec_blob->Version.ProductBuild = cpu_to_le16(SMB3_PRODUCT_BUILD);
sec_blob->Version.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3;
tmp = *pbuffer + sizeof(struct negotiate_message);
ses->ntlmssp->client_flags = flags;
sec_blob->NegotiateFlags = cpu_to_le32(flags);
/* these fields should be null in negotiate phase MS-NLMP 3.1.5.1.1 */
cifs_security_buffer_from_str(&sec_blob->DomainName,
NULL,
CIFS_MAX_DOMAINNAME_LEN,
*pbuffer, &tmp,
nls_cp);
cifs_security_buffer_from_str(&sec_blob->WorkstationName,
NULL,
CIFS_MAX_WORKSTATION_LEN,
*pbuffer, &tmp,
nls_cp);
*buflen = tmp - *pbuffer;
setup_ntlm_smb3_neg_ret:
return rc;
}
int build_ntlmssp_auth_blob(unsigned char **pbuffer, int build_ntlmssp_auth_blob(unsigned char **pbuffer,
u16 *buflen, u16 *buflen,
struct cifs_ses *ses, struct cifs_ses *ses,
...@@ -1048,16 +1107,6 @@ sess_establish_session(struct sess_data *sess_data) ...@@ -1048,16 +1107,6 @@ sess_establish_session(struct sess_data *sess_data)
mutex_unlock(&server->srv_mutex); mutex_unlock(&server->srv_mutex);
cifs_dbg(FYI, "CIFS session established successfully\n"); cifs_dbg(FYI, "CIFS session established successfully\n");
spin_lock(&ses->chan_lock);
cifs_chan_clear_need_reconnect(ses, server);
spin_unlock(&ses->chan_lock);
/* Even if one channel is active, session is in good state */
spin_lock(&cifs_tcp_ses_lock);
server->tcpStatus = CifsGood;
ses->status = CifsGood;
spin_unlock(&cifs_tcp_ses_lock);
return 0; return 0;
} }
...@@ -1413,7 +1462,7 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data) ...@@ -1413,7 +1462,7 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
&blob_len, ses, server, &blob_len, ses, server,
sess_data->nls_cp); sess_data->nls_cp);
if (rc) if (rc)
goto out; goto out_free_ntlmsspblob;
sess_data->iov[1].iov_len = blob_len; sess_data->iov[1].iov_len = blob_len;
sess_data->iov[1].iov_base = ntlmsspblob; sess_data->iov[1].iov_base = ntlmsspblob;
...@@ -1421,7 +1470,7 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data) ...@@ -1421,7 +1470,7 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
rc = _sess_auth_rawntlmssp_assemble_req(sess_data); rc = _sess_auth_rawntlmssp_assemble_req(sess_data);
if (rc) if (rc)
goto out; goto out_free_ntlmsspblob;
rc = sess_sendreceive(sess_data); rc = sess_sendreceive(sess_data);
...@@ -1435,14 +1484,14 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data) ...@@ -1435,14 +1484,14 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
rc = 0; rc = 0;
if (rc) if (rc)
goto out; goto out_free_ntlmsspblob;
cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n"); cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
if (smb_buf->WordCount != 4) { if (smb_buf->WordCount != 4) {
rc = -EIO; rc = -EIO;
cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
goto out; goto out_free_ntlmsspblob;
} }
ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */
...@@ -1456,10 +1505,13 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data) ...@@ -1456,10 +1505,13 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
cifs_dbg(VFS, "bad security blob length %d\n", cifs_dbg(VFS, "bad security blob length %d\n",
blob_len); blob_len);
rc = -EINVAL; rc = -EINVAL;
goto out; goto out_free_ntlmsspblob;
} }
rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses); rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses);
out_free_ntlmsspblob:
kfree(ntlmsspblob);
out: out:
sess_free_buffer(sess_data); sess_free_buffer(sess_data);
...@@ -1574,7 +1626,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data) ...@@ -1574,7 +1626,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
out: out:
sess_free_buffer(sess_data); sess_free_buffer(sess_data);
if (!rc) if (!rc)
rc = sess_establish_session(sess_data); rc = sess_establish_session(sess_data);
/* Cleanup */ /* Cleanup */
......
...@@ -244,10 +244,10 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -244,10 +244,10 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
return 0; return 0;
} }
spin_unlock(&ses->chan_lock);
cifs_dbg(FYI, "sess reconnect mask: 0x%lx, tcon reconnect: %d", cifs_dbg(FYI, "sess reconnect mask: 0x%lx, tcon reconnect: %d",
tcon->ses->chans_need_reconnect, tcon->ses->chans_need_reconnect,
tcon->need_reconnect); tcon->need_reconnect);
spin_unlock(&ses->chan_lock);
nls_codepage = load_nls_default(); nls_codepage = load_nls_default();
...@@ -289,14 +289,18 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -289,14 +289,18 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
rc = -EHOSTDOWN; rc = -EHOSTDOWN;
goto failed; goto failed;
} }
} } else {
if (rc || !tcon->need_reconnect) {
mutex_unlock(&ses->session_mutex); mutex_unlock(&ses->session_mutex);
goto out; goto out;
} }
mutex_unlock(&ses->session_mutex);
skip_sess_setup: skip_sess_setup:
mutex_lock(&ses->session_mutex);
if (!tcon->need_reconnect) {
mutex_unlock(&ses->session_mutex);
goto out;
}
cifs_mark_open_files_invalid(tcon); cifs_mark_open_files_invalid(tcon);
if (tcon->use_persistent) if (tcon->use_persistent)
tcon->need_reopen_files = true; tcon->need_reopen_files = true;
...@@ -1382,17 +1386,6 @@ SMB2_sess_establish_session(struct SMB2_sess_data *sess_data) ...@@ -1382,17 +1386,6 @@ SMB2_sess_establish_session(struct SMB2_sess_data *sess_data)
mutex_unlock(&server->srv_mutex); mutex_unlock(&server->srv_mutex);
cifs_dbg(FYI, "SMB2/3 session established successfully\n"); cifs_dbg(FYI, "SMB2/3 session established successfully\n");
spin_lock(&ses->chan_lock);
cifs_chan_clear_need_reconnect(ses, server);
spin_unlock(&ses->chan_lock);
/* Even if one channel is active, session is in good state */
spin_lock(&cifs_tcp_ses_lock);
server->tcpStatus = CifsGood;
ses->status = CifsGood;
spin_unlock(&cifs_tcp_ses_lock);
return rc; return rc;
} }
...@@ -1513,7 +1506,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data) ...@@ -1513,7 +1506,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
if (rc) if (rc)
goto out_err; goto out_err;
rc = build_ntlmssp_negotiate_blob(&ntlmssp_blob, rc = build_ntlmssp_smb3_negotiate_blob(&ntlmssp_blob,
&blob_length, ses, server, &blob_length, ses, server,
sess_data->nls_cp); sess_data->nls_cp);
if (rc) if (rc)
...@@ -1920,10 +1913,6 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ...@@ -1920,10 +1913,6 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
tcon->share_flags = le32_to_cpu(rsp->ShareFlags); tcon->share_flags = le32_to_cpu(rsp->ShareFlags);
tcon->capabilities = rsp->Capabilities; /* we keep caps little endian */ tcon->capabilities = rsp->Capabilities; /* we keep caps little endian */
tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess); tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess);
spin_lock(&cifs_tcp_ses_lock);
tcon->tidStatus = CifsGood;
spin_unlock(&cifs_tcp_ses_lock);
tcon->need_reconnect = false;
tcon->tid = le32_to_cpu(rsp->hdr.Id.SyncId.TreeId); tcon->tid = le32_to_cpu(rsp->hdr.Id.SyncId.TreeId);
strlcpy(tcon->treeName, tree, sizeof(tcon->treeName)); strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
...@@ -2587,8 +2576,13 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len, ...@@ -2587,8 +2576,13 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
cp = load_nls_default(); cp = load_nls_default();
cifs_strtoUTF16(*out_path, treename, treename_len, cp); cifs_strtoUTF16(*out_path, treename, treename_len, cp);
UniStrcat(*out_path, sep);
UniStrcat(*out_path, path); /* Do not append the separator if the path is empty */
if (path[0] != cpu_to_le16(0x0000)) {
UniStrcat(*out_path, sep);
UniStrcat(*out_path, path);
}
unload_nls(cp); unload_nls(cp);
return 0; return 0;
...@@ -3782,27 +3776,35 @@ void smb2_reconnect_server(struct work_struct *work) ...@@ -3782,27 +3776,35 @@ void smb2_reconnect_server(struct work_struct *work)
{ {
struct TCP_Server_Info *server = container_of(work, struct TCP_Server_Info *server = container_of(work,
struct TCP_Server_Info, reconnect.work); struct TCP_Server_Info, reconnect.work);
struct cifs_ses *ses; struct TCP_Server_Info *pserver;
struct cifs_ses *ses, *ses2;
struct cifs_tcon *tcon, *tcon2; struct cifs_tcon *tcon, *tcon2;
struct list_head tmp_list; struct list_head tmp_list, tmp_ses_list;
int tcon_exist = false; bool tcon_exist = false, ses_exist = false;
bool tcon_selected = false;
int rc; int rc;
int resched = false; bool resched = false;
/* If server is a channel, select the primary channel */
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
/* Prevent simultaneous reconnects that can corrupt tcon->rlist list */ /* Prevent simultaneous reconnects that can corrupt tcon->rlist list */
mutex_lock(&server->reconnect_mutex); mutex_lock(&pserver->reconnect_mutex);
INIT_LIST_HEAD(&tmp_list); INIT_LIST_HEAD(&tmp_list);
cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n"); INIT_LIST_HEAD(&tmp_ses_list);
cifs_dbg(FYI, "Reconnecting tcons and channels\n");
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
tcon_selected = false;
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
if (tcon->need_reconnect || tcon->need_reopen_files) { if (tcon->need_reconnect || tcon->need_reopen_files) {
tcon->tc_count++; tcon->tc_count++;
list_add_tail(&tcon->rlist, &tmp_list); list_add_tail(&tcon->rlist, &tmp_list);
tcon_exist = true; tcon_selected = tcon_exist = true;
} }
} }
/* /*
...@@ -3811,15 +3813,27 @@ void smb2_reconnect_server(struct work_struct *work) ...@@ -3811,15 +3813,27 @@ void smb2_reconnect_server(struct work_struct *work)
*/ */
if (ses->tcon_ipc && ses->tcon_ipc->need_reconnect) { if (ses->tcon_ipc && ses->tcon_ipc->need_reconnect) {
list_add_tail(&ses->tcon_ipc->rlist, &tmp_list); list_add_tail(&ses->tcon_ipc->rlist, &tmp_list);
tcon_exist = true; tcon_selected = tcon_exist = true;
ses->ses_count++; ses->ses_count++;
} }
/*
* handle the case where channel needs to reconnect
* binding session, but tcon is healthy (some other channel
* is active)
*/
spin_lock(&ses->chan_lock);
if (!tcon_selected && cifs_chan_needs_reconnect(ses, server)) {
list_add_tail(&ses->rlist, &tmp_ses_list);
ses_exist = true;
ses->ses_count++;
}
spin_unlock(&ses->chan_lock);
} }
/* /*
* Get the reference to server struct to be sure that the last call of * Get the reference to server struct to be sure that the last call of
* cifs_put_tcon() in the loop below won't release the server pointer. * cifs_put_tcon() in the loop below won't release the server pointer.
*/ */
if (tcon_exist) if (tcon_exist || ses_exist)
server->srv_count++; server->srv_count++;
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
...@@ -3837,13 +3851,41 @@ void smb2_reconnect_server(struct work_struct *work) ...@@ -3837,13 +3851,41 @@ void smb2_reconnect_server(struct work_struct *work)
cifs_put_tcon(tcon); cifs_put_tcon(tcon);
} }
cifs_dbg(FYI, "Reconnecting tcons finished\n"); if (!ses_exist)
goto done;
/* allocate a dummy tcon struct used for reconnect */
tcon = kzalloc(sizeof(struct cifs_tcon), GFP_KERNEL);
if (!tcon) {
resched = true;
list_del_init(&ses->rlist);
cifs_put_smb_ses(ses);
goto done;
}
tcon->tidStatus = CifsGood;
tcon->retry = false;
tcon->need_reconnect = false;
/* now reconnect sessions for necessary channels */
list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) {
tcon->ses = ses;
rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server);
if (rc)
resched = true;
list_del_init(&ses->rlist);
cifs_put_smb_ses(ses);
}
kfree(tcon);
done:
cifs_dbg(FYI, "Reconnecting tcons and channels finished\n");
if (resched) if (resched)
queue_delayed_work(cifsiod_wq, &server->reconnect, 2 * HZ); queue_delayed_work(cifsiod_wq, &server->reconnect, 2 * HZ);
mutex_unlock(&server->reconnect_mutex); mutex_unlock(&pserver->reconnect_mutex);
/* now we can safely release srv struct */ /* now we can safely release srv struct */
if (tcon_exist) if (tcon_exist || ses_exist)
cifs_put_tcp_session(server, 1); cifs_put_tcp_session(server, 1);
} }
......
...@@ -100,6 +100,7 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) ...@@ -100,6 +100,7 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
goto out; goto out;
found: found:
spin_lock(&ses->chan_lock);
if (cifs_chan_needs_reconnect(ses, server) && if (cifs_chan_needs_reconnect(ses, server) &&
!CIFS_ALL_CHANS_NEED_RECONNECT(ses)) { !CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
/* /*
...@@ -108,6 +109,7 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) ...@@ -108,6 +109,7 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
* session key * session key
*/ */
memcpy(key, ses->smb3signingkey, SMB3_SIGN_KEY_SIZE); memcpy(key, ses->smb3signingkey, SMB3_SIGN_KEY_SIZE);
spin_unlock(&ses->chan_lock);
goto out; goto out;
} }
...@@ -119,9 +121,11 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) ...@@ -119,9 +121,11 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
chan = ses->chans + i; chan = ses->chans + i;
if (chan->server == server) { if (chan->server == server) {
memcpy(key, chan->signkey, SMB3_SIGN_KEY_SIZE); memcpy(key, chan->signkey, SMB3_SIGN_KEY_SIZE);
spin_unlock(&ses->chan_lock);
goto out; goto out;
} }
} }
spin_unlock(&ses->chan_lock);
cifs_dbg(VFS, cifs_dbg(VFS,
"%s: Could not find channel signing key for session 0x%llx\n", "%s: Could not find channel signing key for session 0x%llx\n",
...@@ -430,8 +434,10 @@ generate_smb3signingkey(struct cifs_ses *ses, ...@@ -430,8 +434,10 @@ generate_smb3signingkey(struct cifs_ses *ses,
return rc; return rc;
/* safe to access primary channel, since it will never go away */ /* safe to access primary channel, since it will never go away */
spin_lock(&ses->chan_lock);
memcpy(ses->chans[0].signkey, ses->smb3signingkey, memcpy(ses->chans[0].signkey, ses->smb3signingkey,
SMB3_SIGN_KEY_SIZE); SMB3_SIGN_KEY_SIZE);
spin_unlock(&ses->chan_lock);
rc = generate_key(ses, ptriplet->encryption.label, rc = generate_key(ses, ptriplet->encryption.label,
ptriplet->encryption.context, ptriplet->encryption.context,
......
...@@ -431,7 +431,8 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, ...@@ -431,7 +431,8 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
* socket so the server throws away the partial SMB * socket so the server throws away the partial SMB
*/ */
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
server->tcpStatus = CifsNeedReconnect; if (server->tcpStatus != CifsExiting)
server->tcpStatus = CifsNeedReconnect;
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
trace_smb3_partial_send_reconnect(server->CurrentMid, trace_smb3_partial_send_reconnect(server->CurrentMid,
server->conn_id, server->hostname); server->conn_id, server->hostname);
...@@ -729,17 +730,6 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, ...@@ -729,17 +730,6 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
struct mid_q_entry **ppmidQ) struct mid_q_entry **ppmidQ)
{ {
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
if (ses->server->tcpStatus == CifsExiting) {
spin_unlock(&cifs_tcp_ses_lock);
return -ENOENT;
}
if (ses->server->tcpStatus == CifsNeedReconnect) {
spin_unlock(&cifs_tcp_ses_lock);
cifs_dbg(FYI, "tcp session dead - return to caller to retry\n");
return -EAGAIN;
}
if (ses->status == CifsNew) { if (ses->status == CifsNew) {
if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
(in_buf->Command != SMB_COM_NEGOTIATE)) { (in_buf->Command != SMB_COM_NEGOTIATE)) {
...@@ -1059,7 +1049,10 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses) ...@@ -1059,7 +1049,10 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
/* round robin */ /* round robin */
index = (uint)atomic_inc_return(&ses->chan_seq); index = (uint)atomic_inc_return(&ses->chan_seq);
spin_lock(&ses->chan_lock);
index %= ses->chan_count; index %= ses->chan_count;
spin_unlock(&ses->chan_lock);
return ses->chans[index].server; return ses->chans[index].server;
} }
......
...@@ -449,7 +449,7 @@ struct smb2_netname_neg_context { ...@@ -449,7 +449,7 @@ struct smb2_netname_neg_context {
*/ */
/* Flags */ /* Flags */
#define SMB2_ACCEPT_TRANSFORM_LEVEL_SECURITY 0x00000001 #define SMB2_ACCEPT_TRANSPORT_LEVEL_SECURITY 0x00000001
struct smb2_transport_capabilities_context { struct smb2_transport_capabilities_context {
__le16 ContextType; /* 6 */ __le16 ContextType; /* 6 */
......
...@@ -95,8 +95,10 @@ ...@@ -95,8 +95,10 @@
#define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */ #define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */
#define FSCTL_GET_INTEGRITY_INFORMATION 0x0009027C #define FSCTL_GET_INTEGRITY_INFORMATION 0x0009027C
#define FSCTL_GET_REFS_VOLUME_DATA 0x000902D8 /* See MS-FSCC 2.3.24 */ #define FSCTL_GET_REFS_VOLUME_DATA 0x000902D8 /* See MS-FSCC 2.3.24 */
#define FSCTL_SET_INTEGRITY_INFORMATION_EXT 0x00090380
#define FSCTL_GET_RETRIEVAL_POINTERS_AND_REFCOUNT 0x000903d3 #define FSCTL_GET_RETRIEVAL_POINTERS_AND_REFCOUNT 0x000903d3
#define FSCTL_GET_RETRIEVAL_POINTER_COUNT 0x0009042b #define FSCTL_GET_RETRIEVAL_POINTER_COUNT 0x0009042b
#define FSCTL_REFS_STREAM_SNAPSHOT_MANAGEMENT 0x00090440
#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF #define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF
#define FSCTL_SET_DEFECT_MANAGEMENT 0x00098134 /* BB add struct */ #define FSCTL_SET_DEFECT_MANAGEMENT 0x00098134 /* BB add struct */
#define FSCTL_FILE_LEVEL_TRIM 0x00098208 /* BB add struct */ #define FSCTL_FILE_LEVEL_TRIM 0x00098208 /* BB add struct */
......
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