Commit 892812f0 authored by Vitaly Lipatov's avatar Vitaly Lipatov

update 4.9 up to v4.9.78

parent 5a6c30ec
...@@ -245,7 +245,8 @@ compose_mount_options_err: ...@@ -245,7 +245,8 @@ compose_mount_options_err:
* @fullpath: full path in UNC format * @fullpath: full path in UNC format
* @ref: server's referral * @ref: server's referral
*/ */
static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb, static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,
struct cifs_sb_info *cifs_sb,
const char *fullpath, const struct dfs_info3_param *ref) const char *fullpath, const struct dfs_info3_param *ref)
{ {
struct vfsmount *mnt; struct vfsmount *mnt;
...@@ -259,7 +260,7 @@ static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb, ...@@ -259,7 +260,7 @@ static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb,
if (IS_ERR(mountdata)) if (IS_ERR(mountdata))
return (struct vfsmount *)mountdata; return (struct vfsmount *)mountdata;
mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata); mnt = vfs_submount(mntpt, &cifs_fs_type, devname, mountdata);
kfree(mountdata); kfree(mountdata);
kfree(devname); kfree(devname);
return mnt; return mnt;
...@@ -334,7 +335,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) ...@@ -334,7 +335,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
mnt = ERR_PTR(-EINVAL); mnt = ERR_PTR(-EINVAL);
break; break;
} }
mnt = cifs_dfs_do_refmount(cifs_sb, mnt = cifs_dfs_do_refmount(mntpt, cifs_sb,
full_path, referrals + i); full_path, referrals + i);
cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p\n", cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p\n",
__func__, referrals[i].node_name, mnt); __func__, referrals[i].node_name, mnt);
......
...@@ -83,6 +83,9 @@ convert_sfm_char(const __u16 src_char, char *target) ...@@ -83,6 +83,9 @@ convert_sfm_char(const __u16 src_char, char *target)
case SFM_COLON: case SFM_COLON:
*target = ':'; *target = ':';
break; break;
case SFM_DOUBLEQUOTE:
*target = '"';
break;
case SFM_ASTERISK: case SFM_ASTERISK:
*target = '*'; *target = '*';
break; break;
...@@ -418,6 +421,9 @@ static __le16 convert_to_sfm_char(char src_char, bool end_of_string) ...@@ -418,6 +421,9 @@ static __le16 convert_to_sfm_char(char src_char, bool end_of_string)
case ':': case ':':
dest_char = cpu_to_le16(SFM_COLON); dest_char = cpu_to_le16(SFM_COLON);
break; break;
case '"':
dest_char = cpu_to_le16(SFM_DOUBLEQUOTE);
break;
case '*': case '*':
dest_char = cpu_to_le16(SFM_ASTERISK); dest_char = cpu_to_le16(SFM_ASTERISK);
break; break;
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
* not conflict (although almost does) with the mapping above. * not conflict (although almost does) with the mapping above.
*/ */
#define SFM_DOUBLEQUOTE ((__u16) 0xF020)
#define SFM_ASTERISK ((__u16) 0xF021) #define SFM_ASTERISK ((__u16) 0xF021)
#define SFM_QUESTION ((__u16) 0xF025) #define SFM_QUESTION ((__u16) 0xF025)
#define SFM_COLON ((__u16) 0xF022) #define SFM_COLON ((__u16) 0xF022)
...@@ -64,8 +65,8 @@ ...@@ -64,8 +65,8 @@
#define SFM_LESSTHAN ((__u16) 0xF023) #define SFM_LESSTHAN ((__u16) 0xF023)
#define SFM_PIPE ((__u16) 0xF027) #define SFM_PIPE ((__u16) 0xF027)
#define SFM_SLASH ((__u16) 0xF026) #define SFM_SLASH ((__u16) 0xF026)
#define SFM_PERIOD ((__u16) 0xF028) #define SFM_SPACE ((__u16) 0xF028)
#define SFM_SPACE ((__u16) 0xF029) #define SFM_PERIOD ((__u16) 0xF029)
/* /*
* Mapping mechanism to use when one of the seven reserved characters is * Mapping mechanism to use when one of the seven reserved characters is
......
...@@ -87,6 +87,7 @@ extern mempool_t *cifs_req_poolp; ...@@ -87,6 +87,7 @@ extern mempool_t *cifs_req_poolp;
extern mempool_t *cifs_mid_poolp; extern mempool_t *cifs_mid_poolp;
struct workqueue_struct *cifsiod_wq; struct workqueue_struct *cifsiod_wq;
struct workqueue_struct *cifsoplockd_wq;
__u32 cifs_lock_secret; __u32 cifs_lock_secret;
/* /*
...@@ -1286,9 +1287,16 @@ init_cifs(void) ...@@ -1286,9 +1287,16 @@ init_cifs(void)
goto out_clean_proc; goto out_clean_proc;
} }
cifsoplockd_wq = alloc_workqueue("cifsoplockd",
WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
if (!cifsoplockd_wq) {
rc = -ENOMEM;
goto out_destroy_cifsiod_wq;
}
rc = cifs_fscache_register(); rc = cifs_fscache_register();
if (rc) if (rc)
goto out_destroy_wq; goto out_destroy_cifsoplockd_wq;
rc = cifs_init_inodecache(); rc = cifs_init_inodecache();
if (rc) if (rc)
...@@ -1336,7 +1344,9 @@ out_destroy_inodecache: ...@@ -1336,7 +1344,9 @@ out_destroy_inodecache:
cifs_destroy_inodecache(); cifs_destroy_inodecache();
out_unreg_fscache: out_unreg_fscache:
cifs_fscache_unregister(); cifs_fscache_unregister();
out_destroy_wq: out_destroy_cifsoplockd_wq:
destroy_workqueue(cifsoplockd_wq);
out_destroy_cifsiod_wq:
destroy_workqueue(cifsiod_wq); destroy_workqueue(cifsiod_wq);
out_clean_proc: out_clean_proc:
cifs_proc_clean(); cifs_proc_clean();
...@@ -1353,12 +1363,13 @@ exit_cifs(void) ...@@ -1353,12 +1363,13 @@ exit_cifs(void)
exit_cifs_idmap(); exit_cifs_idmap();
#endif #endif
#ifdef CONFIG_CIFS_UPCALL #ifdef CONFIG_CIFS_UPCALL
unregister_key_type(&cifs_spnego_key_type); exit_cifs_spnego();
#endif #endif
cifs_destroy_request_bufs(); cifs_destroy_request_bufs();
cifs_destroy_mids(); cifs_destroy_mids();
cifs_destroy_inodecache(); cifs_destroy_inodecache();
cifs_fscache_unregister(); cifs_fscache_unregister();
destroy_workqueue(cifsoplockd_wq);
destroy_workqueue(cifsiod_wq); destroy_workqueue(cifsiod_wq);
cifs_proc_clean(); cifs_proc_clean();
} }
......
...@@ -241,6 +241,7 @@ struct smb_version_operations { ...@@ -241,6 +241,7 @@ struct smb_version_operations {
/* verify the message */ /* verify the message */
int (*check_message)(char *, unsigned int, struct TCP_Server_Info *); int (*check_message)(char *, unsigned int, struct TCP_Server_Info *);
bool (*is_oplock_break)(char *, struct TCP_Server_Info *); bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
int (*handle_cancelled_mid)(char *, struct TCP_Server_Info *);
void (*downgrade_oplock)(struct TCP_Server_Info *, void (*downgrade_oplock)(struct TCP_Server_Info *,
struct cifsInodeInfo *, bool); struct cifsInodeInfo *, bool);
/* process transaction2 response */ /* process transaction2 response */
...@@ -364,6 +365,8 @@ struct smb_version_operations { ...@@ -364,6 +365,8 @@ struct smb_version_operations {
unsigned int (*calc_smb_size)(void *); unsigned int (*calc_smb_size)(void *);
/* check for STATUS_PENDING and process it in a positive case */ /* check for STATUS_PENDING and process it in a positive case */
bool (*is_status_pending)(char *, struct TCP_Server_Info *, int); bool (*is_status_pending)(char *, struct TCP_Server_Info *, int);
/* check for STATUS_NETWORK_SESSION_EXPIRED */
bool (*is_session_expired)(char *);
/* send oplock break response */ /* send oplock break response */
int (*oplock_response)(struct cifs_tcon *, struct cifs_fid *, int (*oplock_response)(struct cifs_tcon *, struct cifs_fid *,
struct cifsInodeInfo *); struct cifsInodeInfo *);
...@@ -646,6 +649,8 @@ struct TCP_Server_Info { ...@@ -646,6 +649,8 @@ struct TCP_Server_Info {
unsigned int max_read; unsigned int max_read;
unsigned int max_write; unsigned int max_write;
__u8 preauth_hash[512]; __u8 preauth_hash[512];
struct delayed_work reconnect; /* reconnect workqueue job */
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
#endif /* CONFIG_CIFS_SMB2 */ #endif /* CONFIG_CIFS_SMB2 */
unsigned long echo_interval; unsigned long echo_interval;
}; };
...@@ -849,6 +854,7 @@ cap_unix(struct cifs_ses *ses) ...@@ -849,6 +854,7 @@ cap_unix(struct cifs_ses *ses)
struct cifs_tcon { struct cifs_tcon {
struct list_head tcon_list; struct list_head tcon_list;
int tc_count; int tc_count;
struct list_head rlist; /* reconnect list */
struct list_head openFileList; struct list_head openFileList;
spinlock_t open_file_lock; /* protects list above */ spinlock_t open_file_lock; /* protects list above */
struct cifs_ses *ses; /* pointer to session associated with */ struct cifs_ses *ses; /* pointer to session associated with */
...@@ -922,11 +928,11 @@ struct cifs_tcon { ...@@ -922,11 +928,11 @@ struct cifs_tcon {
bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
bool broken_sparse_sup; /* if server or share does not support sparse */ bool broken_sparse_sup; /* if server or share does not support sparse */
bool need_reconnect:1; /* connection reset, tid now invalid */ bool need_reconnect:1; /* connection reset, tid now invalid */
bool need_reopen_files:1; /* need to reopen tcon file handles */
bool use_resilient:1; /* use resilient instead of durable handles */ bool use_resilient:1; /* use resilient instead of durable handles */
bool use_persistent:1; /* use persistent instead of durable handles */ bool use_persistent:1; /* use persistent instead of durable handles */
#ifdef CONFIG_CIFS_SMB2 #ifdef CONFIG_CIFS_SMB2
bool print:1; /* set if connection to printer share */ bool print:1; /* set if connection to printer share */
bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */
__le32 capabilities; __le32 capabilities;
__u32 share_flags; __u32 share_flags;
__u32 maximal_access; __u32 maximal_access;
...@@ -1319,12 +1325,19 @@ struct mid_q_entry { ...@@ -1319,12 +1325,19 @@ struct mid_q_entry {
void *callback_data; /* general purpose pointer for callback */ void *callback_data; /* general purpose pointer for callback */
void *resp_buf; /* pointer to received SMB header */ void *resp_buf; /* pointer to received SMB header */
int mid_state; /* wish this were enum but can not pass to wait_event */ int mid_state; /* wish this were enum but can not pass to wait_event */
unsigned int mid_flags;
__le16 command; /* smb command code */ __le16 command; /* smb command code */
bool large_buf:1; /* if valid response, is pointer to large buf */ bool large_buf:1; /* if valid response, is pointer to large buf */
bool multiRsp:1; /* multiple trans2 responses for one request */ bool multiRsp:1; /* multiple trans2 responses for one request */
bool multiEnd:1; /* both received */ bool multiEnd:1; /* both received */
}; };
struct close_cancelled_open {
struct cifs_fid fid;
struct cifs_tcon *tcon;
struct work_struct work;
};
/* Make code in transport.c a little cleaner by moving /* Make code in transport.c a little cleaner by moving
update of optional stats into function below */ update of optional stats into function below */
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
...@@ -1456,6 +1469,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, ...@@ -1456,6 +1469,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
#define MID_RESPONSE_MALFORMED 0x10 #define MID_RESPONSE_MALFORMED 0x10
#define MID_SHUTDOWN 0x20 #define MID_SHUTDOWN 0x20
/* Flags */
#define MID_WAIT_CANCELLED 1 /* Cancelled while waiting for response */
/* Types of response buffer returned from SendReceive2 */ /* Types of response buffer returned from SendReceive2 */
#define CIFS_NO_BUFFER 0 /* Response buffer not returned */ #define CIFS_NO_BUFFER 0 /* Response buffer not returned */
#define CIFS_SMALL_BUFFER 1 #define CIFS_SMALL_BUFFER 1
...@@ -1645,6 +1661,7 @@ void cifs_oplock_break(struct work_struct *work); ...@@ -1645,6 +1661,7 @@ void cifs_oplock_break(struct work_struct *work);
extern const struct slow_work_ops cifs_oplock_break_ops; extern const struct slow_work_ops cifs_oplock_break_ops;
extern struct workqueue_struct *cifsiod_wq; extern struct workqueue_struct *cifsiod_wq;
extern struct workqueue_struct *cifsoplockd_wq;
extern __u32 cifs_lock_secret; extern __u32 cifs_lock_secret;
extern mempool_t *cifs_mid_poolp; extern mempool_t *cifs_mid_poolp;
......
...@@ -206,6 +206,9 @@ extern void cifs_add_pending_open_locked(struct cifs_fid *fid, ...@@ -206,6 +206,9 @@ extern void cifs_add_pending_open_locked(struct cifs_fid *fid,
struct tcon_link *tlink, struct tcon_link *tlink,
struct cifs_pending_open *open); struct cifs_pending_open *open);
extern void cifs_del_pending_open(struct cifs_pending_open *open); extern void cifs_del_pending_open(struct cifs_pending_open *open);
extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
int from_reconnect);
extern void cifs_put_tcon(struct cifs_tcon *tcon);
#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
extern void cifs_dfs_release_automount_timer(void); extern void cifs_dfs_release_automount_timer(void);
......
...@@ -717,6 +717,9 @@ CIFSSMBEcho(struct TCP_Server_Info *server) ...@@ -717,6 +717,9 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
if (rc) if (rc)
return rc; return rc;
if (server->capabilities & CAP_UNICODE)
smb->hdr.Flags2 |= SMBFLG2_UNICODE;
/* set up echo request */ /* set up echo request */
smb->hdr.Tid = 0xffff; smb->hdr.Tid = 0xffff;
smb->hdr.WordCount = 1; smb->hdr.WordCount = 1;
...@@ -1430,6 +1433,8 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -1430,6 +1433,8 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
length = discard_remaining_data(server); length = discard_remaining_data(server);
dequeue_mid(mid, rdata->result); dequeue_mid(mid, rdata->result);
mid->resp_buf = server->smallbuf;
server->smallbuf = NULL;
return length; return length;
} }
...@@ -1459,6 +1464,13 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -1459,6 +1464,13 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
return length; return length;
server->total_read += length; server->total_read += length;
if (server->ops->is_session_expired &&
server->ops->is_session_expired(buf)) {
cifs_reconnect(server);
wake_up(&server->response_q);
return -1;
}
if (server->ops->is_status_pending && if (server->ops->is_status_pending &&
server->ops->is_status_pending(buf, server, 0)) { server->ops->is_status_pending(buf, server, 0)) {
discard_remaining_data(server); discard_remaining_data(server);
...@@ -1541,6 +1553,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -1541,6 +1553,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
return cifs_readv_discard(server, mid); return cifs_readv_discard(server, mid);
dequeue_mid(mid, false); dequeue_mid(mid, false);
mid->resp_buf = server->smallbuf;
server->smallbuf = NULL;
return length; return length;
} }
......
...@@ -52,6 +52,9 @@ ...@@ -52,6 +52,9 @@
#include "nterr.h" #include "nterr.h"
#include "rfc1002pdu.h" #include "rfc1002pdu.h"
#include "fscache.h" #include "fscache.h"
#ifdef CONFIG_CIFS_SMB2
#include "smb2proto.h"
#endif
#define CIFS_PORT 445 #define CIFS_PORT 445
#define RFC1001_PORT 139 #define RFC1001_PORT 139
...@@ -794,6 +797,13 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -794,6 +797,13 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
cifs_dump_mem("Bad SMB: ", buf, cifs_dump_mem("Bad SMB: ", buf,
min_t(unsigned int, server->total_read, 48)); min_t(unsigned int, server->total_read, 48));
if (server->ops->is_session_expired &&
server->ops->is_session_expired(buf)) {
cifs_reconnect(server);
wake_up(&server->response_q);
return -1;
}
if (server->ops->is_status_pending && if (server->ops->is_status_pending &&
server->ops->is_status_pending(buf, server, length)) server->ops->is_status_pending(buf, server, length))
return -1; return -1;
...@@ -880,10 +890,19 @@ cifs_demultiplex_thread(void *p) ...@@ -880,10 +890,19 @@ cifs_demultiplex_thread(void *p)
server->lstrp = jiffies; server->lstrp = jiffies;
if (mid_entry != NULL) { if (mid_entry != NULL) {
if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) &&
mid_entry->mid_state == MID_RESPONSE_RECEIVED &&
server->ops->handle_cancelled_mid)
server->ops->handle_cancelled_mid(
mid_entry->resp_buf,
server);
if (!mid_entry->multiRsp || mid_entry->multiEnd) if (!mid_entry->multiRsp || mid_entry->multiEnd)
mid_entry->callback(mid_entry); mid_entry->callback(mid_entry);
} else if (!server->ops->is_oplock_break || } else if (server->ops->is_oplock_break &&
!server->ops->is_oplock_break(buf, server)) { server->ops->is_oplock_break(buf, server)) {
cifs_dbg(FYI, "Received oplock break\n");
} else {
cifs_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", cifs_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n",
atomic_read(&midCount)); atomic_read(&midCount));
cifs_dump_mem("Received Data is: ", buf, cifs_dump_mem("Received Data is: ", buf,
...@@ -2105,8 +2124,8 @@ cifs_find_tcp_session(struct smb_vol *vol) ...@@ -2105,8 +2124,8 @@ cifs_find_tcp_session(struct smb_vol *vol)
return NULL; return NULL;
} }
static void void
cifs_put_tcp_session(struct TCP_Server_Info *server) cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
{ {
struct task_struct *task; struct task_struct *task;
...@@ -2123,6 +2142,19 @@ cifs_put_tcp_session(struct TCP_Server_Info *server) ...@@ -2123,6 +2142,19 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
cancel_delayed_work_sync(&server->echo); cancel_delayed_work_sync(&server->echo);
#ifdef CONFIG_CIFS_SMB2
if (from_reconnect)
/*
* Avoid deadlock here: reconnect work calls
* cifs_put_tcp_session() at its end. Need to be sure
* that reconnect work does nothing with server pointer after
* that step.
*/
cancel_delayed_work(&server->reconnect);
else
cancel_delayed_work_sync(&server->reconnect);
#endif
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
server->tcpStatus = CifsExiting; server->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
...@@ -2187,6 +2219,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info) ...@@ -2187,6 +2219,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
INIT_LIST_HEAD(&tcp_ses->smb_ses_list); INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
#ifdef CONFIG_CIFS_SMB2
INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server);
mutex_init(&tcp_ses->reconnect_mutex);
#endif
memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr, memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr,
sizeof(tcp_ses->srcaddr)); sizeof(tcp_ses->srcaddr));
memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr, memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr,
...@@ -2345,7 +2381,7 @@ cifs_put_smb_ses(struct cifs_ses *ses) ...@@ -2345,7 +2381,7 @@ cifs_put_smb_ses(struct cifs_ses *ses)
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
sesInfoFree(ses); sesInfoFree(ses);
cifs_put_tcp_session(server); cifs_put_tcp_session(server, 0);
} }
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
...@@ -2519,7 +2555,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) ...@@ -2519,7 +2555,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
mutex_unlock(&ses->session_mutex); mutex_unlock(&ses->session_mutex);
/* existing SMB ses has a server reference already */ /* existing SMB ses has a server reference already */
cifs_put_tcp_session(server); cifs_put_tcp_session(server, 0);
free_xid(xid); free_xid(xid);
return ses; return ses;
} }
...@@ -2609,7 +2645,7 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc) ...@@ -2609,7 +2645,7 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc)
return NULL; return NULL;
} }
static void void
cifs_put_tcon(struct cifs_tcon *tcon) cifs_put_tcon(struct cifs_tcon *tcon)
{ {
unsigned int xid; unsigned int xid;
...@@ -2815,16 +2851,14 @@ match_prepath(struct super_block *sb, struct cifs_mnt_data *mnt_data) ...@@ -2815,16 +2851,14 @@ match_prepath(struct super_block *sb, struct cifs_mnt_data *mnt_data)
{ {
struct cifs_sb_info *old = CIFS_SB(sb); struct cifs_sb_info *old = CIFS_SB(sb);
struct cifs_sb_info *new = mnt_data->cifs_sb; struct cifs_sb_info *new = mnt_data->cifs_sb;
bool old_set = old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH;
bool new_set = new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH;
if (old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) { if (old_set && new_set && !strcmp(new->prepath, old->prepath))
if (!(new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH))
return 0;
/* The prepath should be null terminated strings */
if (strcmp(new->prepath, old->prepath))
return 0;
return 1; return 1;
} else if (!old_set && !new_set)
return 1;
return 0; return 0;
} }
...@@ -3797,7 +3831,7 @@ mount_fail_check: ...@@ -3797,7 +3831,7 @@ mount_fail_check:
else if (ses) else if (ses)
cifs_put_smb_ses(ses); cifs_put_smb_ses(ses);
else else
cifs_put_tcp_session(server); cifs_put_tcp_session(server, 0);
bdi_destroy(&cifs_sb->bdi); bdi_destroy(&cifs_sb->bdi);
} }
...@@ -4049,6 +4083,14 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, ...@@ -4049,6 +4083,14 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n", cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n",
server->sec_mode, server->capabilities, server->timeAdj); server->sec_mode, server->capabilities, server->timeAdj);
if (ses->auth_key.response) {
cifs_dbg(VFS, "Free previous auth_key.response = %p\n",
ses->auth_key.response);
kfree(ses->auth_key.response);
ses->auth_key.response = NULL;
ses->auth_key.len = 0;
}
if (server->ops->sess_setup) if (server->ops->sess_setup)
rc = server->ops->sess_setup(xid, ses, nls_info); rc = server->ops->sess_setup(xid, ses, nls_info);
...@@ -4108,7 +4150,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) ...@@ -4108,7 +4150,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info); ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
if (IS_ERR(ses)) { if (IS_ERR(ses)) {
tcon = (struct cifs_tcon *)ses; tcon = (struct cifs_tcon *)ses;
cifs_put_tcp_session(master_tcon->ses->server); cifs_put_tcp_session(master_tcon->ses->server, 0);
goto out; goto out;
} }
......
...@@ -183,15 +183,21 @@ cifs_bp_rename_retry: ...@@ -183,15 +183,21 @@ cifs_bp_rename_retry:
} }
/* /*
* Don't allow path components longer than the server max.
* Don't allow the separator character in a path component. * Don't allow the separator character in a path component.
* The VFS will not allow "/", but "\" is allowed by posix. * The VFS will not allow "/", but "\" is allowed by posix.
*/ */
static int static int
check_name(struct dentry *direntry) check_name(struct dentry *direntry, struct cifs_tcon *tcon)
{ {
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
int i; int i;
if (unlikely(tcon->fsAttrInfo.MaxPathNameComponentLength &&
direntry->d_name.len >
le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength)))
return -ENAMETOOLONG;
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) { if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
for (i = 0; i < direntry->d_name.len; i++) { for (i = 0; i < direntry->d_name.len; i++) {
if (direntry->d_name.name[i] == '\\') { if (direntry->d_name.name[i] == '\\') {
...@@ -494,10 +500,6 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, ...@@ -494,10 +500,6 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
return finish_no_open(file, res); return finish_no_open(file, res);
} }
rc = check_name(direntry);
if (rc)
return rc;
xid = get_xid(); xid = get_xid();
cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n", cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
...@@ -510,6 +512,11 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, ...@@ -510,6 +512,11 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
} }
tcon = tlink_tcon(tlink); tcon = tlink_tcon(tlink);
rc = check_name(direntry, tcon);
if (rc)
goto out;
server = tcon->ses->server; server = tcon->ses->server;
if (server->ops->new_lease_key) if (server->ops->new_lease_key)
...@@ -770,7 +777,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, ...@@ -770,7 +777,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
} }
pTcon = tlink_tcon(tlink); pTcon = tlink_tcon(tlink);
rc = check_name(direntry); rc = check_name(direntry, pTcon);
if (rc) if (rc)
goto lookup_out; goto lookup_out;
......
...@@ -226,6 +226,13 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, ...@@ -226,6 +226,13 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
if (backup_cred(cifs_sb)) if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT; create_options |= CREATE_OPEN_BACKUP_INTENT;
/* O_SYNC also has bit for O_DSYNC so following check picks up either */
if (f_flags & O_SYNC)
create_options |= CREATE_WRITE_THROUGH;
if (f_flags & O_DIRECT)
create_options |= CREATE_NO_BUFFER;
oparms.tcon = tcon; oparms.tcon = tcon;
oparms.cifs_sb = cifs_sb; oparms.cifs_sb = cifs_sb;
oparms.desired_access = desired_access; oparms.desired_access = desired_access;
...@@ -785,6 +792,11 @@ cifs_reopen_persistent_handles(struct cifs_tcon *tcon) ...@@ -785,6 +792,11 @@ cifs_reopen_persistent_handles(struct cifs_tcon *tcon)
struct list_head *tmp1; struct list_head *tmp1;
struct list_head tmp_list; struct list_head tmp_list;
if (!tcon->use_persistent || !tcon->need_reopen_files)
return;
tcon->need_reopen_files = false;
cifs_dbg(FYI, "Reopen persistent handles"); cifs_dbg(FYI, "Reopen persistent handles");
INIT_LIST_HEAD(&tmp_list); INIT_LIST_HEAD(&tmp_list);
...@@ -801,7 +813,8 @@ cifs_reopen_persistent_handles(struct cifs_tcon *tcon) ...@@ -801,7 +813,8 @@ cifs_reopen_persistent_handles(struct cifs_tcon *tcon)
list_for_each_safe(tmp, tmp1, &tmp_list) { list_for_each_safe(tmp, tmp1, &tmp_list) {
open_file = list_entry(tmp, struct cifsFileInfo, rlist); open_file = list_entry(tmp, struct cifsFileInfo, rlist);
cifs_reopen_file(open_file, false /* do not flush */); if (cifs_reopen_file(open_file, false /* do not flush */))
tcon->need_reopen_files = true;
list_del_init(&open_file->rlist); list_del_init(&open_file->rlist);
cifsFileInfo_put(open_file); cifsFileInfo_put(open_file);
} }
...@@ -2599,7 +2612,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, ...@@ -2599,7 +2612,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
wdata->credits = credits; wdata->credits = credits;
if (!wdata->cfile->invalidHandle || if (!wdata->cfile->invalidHandle ||
!cifs_reopen_file(wdata->cfile, false)) !(rc = cifs_reopen_file(wdata->cfile, false)))
rc = server->ops->async_writev(wdata, rc = server->ops->async_writev(wdata,
cifs_uncached_writedata_release); cifs_uncached_writedata_release);
if (rc) { if (rc) {
...@@ -2886,7 +2899,15 @@ cifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter) ...@@ -2886,7 +2899,15 @@ cifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter)
for (i = 0; i < rdata->nr_pages; i++) { for (i = 0; i < rdata->nr_pages; i++) {
struct page *page = rdata->pages[i]; struct page *page = rdata->pages[i];
size_t copy = min_t(size_t, remaining, PAGE_SIZE); size_t copy = min_t(size_t, remaining, PAGE_SIZE);
size_t written = copy_page_to_iter(page, 0, copy, iter); size_t written;
if (unlikely(iter->type & ITER_PIPE)) {
void *addr = kmap_atomic(page);
written = copy_to_iter(addr, copy, iter);
kunmap_atomic(addr);
} else
written = copy_page_to_iter(page, 0, copy, iter);
remaining -= written; remaining -= written;
if (written < copy && iov_iter_count(iter) > 0) if (written < copy && iov_iter_count(iter) > 0)
break; break;
...@@ -2996,7 +3017,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, ...@@ -2996,7 +3017,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
rdata->credits = credits; rdata->credits = credits;
if (!rdata->cfile->invalidHandle || if (!rdata->cfile->invalidHandle ||
!cifs_reopen_file(rdata->cfile, true)) !(rc = cifs_reopen_file(rdata->cfile, true)))
rc = server->ops->async_readv(rdata); rc = server->ops->async_readv(rdata);
error: error:
if (rc) { if (rc) {
...@@ -3571,7 +3592,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -3571,7 +3592,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
} }
if (!rdata->cfile->invalidHandle || if (!rdata->cfile->invalidHandle ||
!cifs_reopen_file(rdata->cfile, true)) !(rc = cifs_reopen_file(rdata->cfile, true)))
rc = server->ops->async_readv(rdata); rc = server->ops->async_readv(rdata);
if (rc) { if (rc) {
add_credits_and_wake_if(server, rdata->credits, 0); add_credits_and_wake_if(server, rdata->credits, 0);
......
...@@ -189,7 +189,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) ...@@ -189,7 +189,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
xid = get_xid(); xid = get_xid();
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
cifs_dbg(VFS, "cifs ioctl 0x%x\n", command); cifs_dbg(FYI, "cifs ioctl 0x%x\n", command);
switch (command) { switch (command) {
case FS_IOC_GETFLAGS: case FS_IOC_GETFLAGS:
if (pSMBFile == NULL) if (pSMBFile == NULL)
...@@ -264,10 +264,14 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) ...@@ -264,10 +264,14 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
break; break;
case CIFS_IOC_GET_MNT_INFO: case CIFS_IOC_GET_MNT_INFO:
if (pSMBFile == NULL)
break;
tcon = tlink_tcon(pSMBFile->tlink); tcon = tlink_tcon(pSMBFile->tlink);
rc = smb_mnt_get_fsinfo(xid, tcon, (void __user *)arg); rc = smb_mnt_get_fsinfo(xid, tcon, (void __user *)arg);
break; break;
case CIFS_ENUMERATE_SNAPSHOTS: case CIFS_ENUMERATE_SNAPSHOTS:
if (pSMBFile == NULL)
break;
if (arg == 0) { if (arg == 0) {
rc = -EINVAL; rc = -EINVAL;
goto cifs_ioc_exit; goto cifs_ioc_exit;
......
...@@ -492,7 +492,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) ...@@ -492,7 +492,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
&pCifsInode->flags); &pCifsInode->flags);
queue_work(cifsiod_wq, queue_work(cifsoplockd_wq,
&netfile->oplock_break); &netfile->oplock_break);
netfile->oplock_break_cancelled = false; netfile->oplock_break_cancelled = false;
......
...@@ -285,6 +285,7 @@ initiate_cifs_search(const unsigned int xid, struct file *file) ...@@ -285,6 +285,7 @@ initiate_cifs_search(const unsigned int xid, struct file *file)
rc = -ENOMEM; rc = -ENOMEM;
goto error_exit; goto error_exit;
} }
spin_lock_init(&cifsFile->file_info_lock);
file->private_data = cifsFile; file->private_data = cifsFile;
cifsFile->tlink = cifs_get_tlink(tlink); cifsFile->tlink = cifs_get_tlink(tlink);
tcon = tlink_tcon(tlink); tcon = tlink_tcon(tlink);
......
...@@ -851,8 +851,13 @@ cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -851,8 +851,13 @@ cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_fid *fid, __u16 search_flags, struct cifs_fid *fid, __u16 search_flags,
struct cifs_search_info *srch_inf) struct cifs_search_info *srch_inf)
{ {
return CIFSFindFirst(xid, tcon, path, cifs_sb, int rc;
&fid->netfid, search_flags, srch_inf, true);
rc = CIFSFindFirst(xid, tcon, path, cifs_sb,
&fid->netfid, search_flags, srch_inf, true);
if (rc)
cifs_dbg(FYI, "find first failed=%d\n", rc);
return rc;
} }
static int static int
...@@ -1018,6 +1023,15 @@ cifs_dir_needs_close(struct cifsFileInfo *cfile) ...@@ -1018,6 +1023,15 @@ cifs_dir_needs_close(struct cifsFileInfo *cfile)
return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle; return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle;
} }
static bool
cifs_can_echo(struct TCP_Server_Info *server)
{
if (server->tcpStatus == CifsGood)
return true;
return false;
}
struct smb_version_operations smb1_operations = { struct smb_version_operations smb1_operations = {
.send_cancel = send_nt_cancel, .send_cancel = send_nt_cancel,
.compare_fids = cifs_compare_fids, .compare_fids = cifs_compare_fids,
...@@ -1052,6 +1066,7 @@ struct smb_version_operations smb1_operations = { ...@@ -1052,6 +1066,7 @@ struct smb_version_operations smb1_operations = {
.get_dfs_refer = CIFSGetDFSRefer, .get_dfs_refer = CIFSGetDFSRefer,
.qfs_tcon = cifs_qfs_tcon, .qfs_tcon = cifs_qfs_tcon,
.is_path_accessible = cifs_is_path_accessible, .is_path_accessible = cifs_is_path_accessible,
.can_echo = cifs_can_echo,
.query_path_info = cifs_query_path_info, .query_path_info = cifs_query_path_info,
.query_file_info = cifs_query_file_info, .query_file_info = cifs_query_file_info,
.get_srv_inum = cifs_get_srv_inum, .get_srv_inum = cifs_get_srv_inum,
......
...@@ -260,7 +260,7 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile) ...@@ -260,7 +260,7 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
* and check it for zero before using. * and check it for zero before using.
*/ */
max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf; max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf;
if (!max_buf) { if (max_buf < sizeof(struct smb2_lock_element)) {
free_xid(xid); free_xid(xid);
return -EINVAL; return -EINVAL;
} }
......
...@@ -494,7 +494,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, ...@@ -494,7 +494,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
else else
cfile->oplock_break_cancelled = true; cfile->oplock_break_cancelled = true;
queue_work(cifsiod_wq, &cfile->oplock_break); queue_work(cifsoplockd_wq, &cfile->oplock_break);
kfree(lw); kfree(lw);
return true; return true;
} }
...@@ -638,7 +638,8 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) ...@@ -638,7 +638,8 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
&cinode->flags); &cinode->flags);
spin_unlock(&cfile->file_info_lock); spin_unlock(&cfile->file_info_lock);
queue_work(cifsiod_wq, &cfile->oplock_break); queue_work(cifsoplockd_wq,
&cfile->oplock_break);
spin_unlock(&tcon->open_file_lock); spin_unlock(&tcon->open_file_lock);
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
...@@ -654,3 +655,47 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) ...@@ -654,3 +655,47 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n"); cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n");
return false; return false;
} }
void
smb2_cancelled_close_fid(struct work_struct *work)
{
struct close_cancelled_open *cancelled = container_of(work,
struct close_cancelled_open, work);
cifs_dbg(VFS, "Close unmatched open\n");
SMB2_close(0, cancelled->tcon, cancelled->fid.persistent_fid,
cancelled->fid.volatile_fid);
cifs_put_tcon(cancelled->tcon);
kfree(cancelled);
}
int
smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server)
{
struct smb2_hdr *hdr = (struct smb2_hdr *)buffer;
struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)buffer;
struct cifs_tcon *tcon;
struct close_cancelled_open *cancelled;
if (hdr->Command != SMB2_CREATE || hdr->Status != STATUS_SUCCESS)
return 0;
cancelled = kzalloc(sizeof(*cancelled), GFP_KERNEL);
if (!cancelled)
return -ENOMEM;
tcon = smb2_find_smb_tcon(server, hdr->SessionId, hdr->TreeId);
if (!tcon) {
kfree(cancelled);
return -ENOENT;
}
cancelled->fid.persistent_fid = rsp->PersistentFileId;
cancelled->fid.volatile_fid = rsp->VolatileFileId;
cancelled->tcon = tcon;
INIT_WORK(&cancelled->work, smb2_cancelled_close_fid);
queue_work(cifsiod_wq, &cancelled->work);
return 0;
}
...@@ -927,6 +927,7 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -927,6 +927,7 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon,
} }
if (snapshot_in.snapshot_array_size < sizeof(struct smb_snapshot_array)) { if (snapshot_in.snapshot_array_size < sizeof(struct smb_snapshot_array)) {
rc = -ERANGE; rc = -ERANGE;
kfree(retbuf);
return rc; return rc;
} }
...@@ -967,7 +968,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -967,7 +968,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
kfree(utf16_path); kfree(utf16_path);
if (rc) { if (rc) {
cifs_dbg(VFS, "open dir failed\n"); cifs_dbg(FYI, "open dir failed rc=%d\n", rc);
return rc; return rc;
} }
...@@ -977,7 +978,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -977,7 +978,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
rc = SMB2_query_directory(xid, tcon, fid->persistent_fid, rc = SMB2_query_directory(xid, tcon, fid->persistent_fid,
fid->volatile_fid, 0, srch_inf); fid->volatile_fid, 0, srch_inf);
if (rc) { if (rc) {
cifs_dbg(VFS, "query directory failed\n"); cifs_dbg(FYI, "query directory failed rc=%d\n", rc);
SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid); SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
} }
return rc; return rc;
...@@ -1021,6 +1022,18 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length) ...@@ -1021,6 +1022,18 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
return true; return true;
} }
static bool
smb2_is_session_expired(char *buf)
{
struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
if (hdr->Status != STATUS_NETWORK_SESSION_EXPIRED)
return false;
cifs_dbg(FYI, "Session expired\n");
return true;
}
static int static int
smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid, smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
struct cifsInodeInfo *cinode) struct cifsInodeInfo *cinode)
...@@ -1571,6 +1584,7 @@ struct smb_version_operations smb20_operations = { ...@@ -1571,6 +1584,7 @@ struct smb_version_operations smb20_operations = {
.clear_stats = smb2_clear_stats, .clear_stats = smb2_clear_stats,
.print_stats = smb2_print_stats, .print_stats = smb2_print_stats,
.is_oplock_break = smb2_is_valid_oplock_break, .is_oplock_break = smb2_is_valid_oplock_break,
.handle_cancelled_mid = smb2_handle_cancelled_mid,
.downgrade_oplock = smb2_downgrade_oplock, .downgrade_oplock = smb2_downgrade_oplock,
.need_neg = smb2_need_neg, .need_neg = smb2_need_neg,
.negotiate = smb2_negotiate, .negotiate = smb2_negotiate,
...@@ -1613,6 +1627,7 @@ struct smb_version_operations smb20_operations = { ...@@ -1613,6 +1627,7 @@ struct smb_version_operations smb20_operations = {
.close_dir = smb2_close_dir, .close_dir = smb2_close_dir,
.calc_smb_size = smb2_calc_size, .calc_smb_size = smb2_calc_size,
.is_status_pending = smb2_is_status_pending, .is_status_pending = smb2_is_status_pending,
.is_session_expired = smb2_is_session_expired,
.oplock_response = smb2_oplock_response, .oplock_response = smb2_oplock_response,
.queryfs = smb2_queryfs, .queryfs = smb2_queryfs,
.mand_lock = smb2_mand_lock, .mand_lock = smb2_mand_lock,
...@@ -1651,6 +1666,7 @@ struct smb_version_operations smb21_operations = { ...@@ -1651,6 +1666,7 @@ struct smb_version_operations smb21_operations = {
.clear_stats = smb2_clear_stats, .clear_stats = smb2_clear_stats,
.print_stats = smb2_print_stats, .print_stats = smb2_print_stats,
.is_oplock_break = smb2_is_valid_oplock_break, .is_oplock_break = smb2_is_valid_oplock_break,
.handle_cancelled_mid = smb2_handle_cancelled_mid,
.downgrade_oplock = smb2_downgrade_oplock, .downgrade_oplock = smb2_downgrade_oplock,
.need_neg = smb2_need_neg, .need_neg = smb2_need_neg,
.negotiate = smb2_negotiate, .negotiate = smb2_negotiate,
...@@ -1693,6 +1709,7 @@ struct smb_version_operations smb21_operations = { ...@@ -1693,6 +1709,7 @@ struct smb_version_operations smb21_operations = {
.close_dir = smb2_close_dir, .close_dir = smb2_close_dir,
.calc_smb_size = smb2_calc_size, .calc_smb_size = smb2_calc_size,
.is_status_pending = smb2_is_status_pending, .is_status_pending = smb2_is_status_pending,
.is_session_expired = smb2_is_session_expired,
.oplock_response = smb2_oplock_response, .oplock_response = smb2_oplock_response,
.queryfs = smb2_queryfs, .queryfs = smb2_queryfs,
.mand_lock = smb2_mand_lock, .mand_lock = smb2_mand_lock,
...@@ -1733,6 +1750,7 @@ struct smb_version_operations smb30_operations = { ...@@ -1733,6 +1750,7 @@ struct smb_version_operations smb30_operations = {
.print_stats = smb2_print_stats, .print_stats = smb2_print_stats,
.dump_share_caps = smb2_dump_share_caps, .dump_share_caps = smb2_dump_share_caps,
.is_oplock_break = smb2_is_valid_oplock_break, .is_oplock_break = smb2_is_valid_oplock_break,
.handle_cancelled_mid = smb2_handle_cancelled_mid,
.downgrade_oplock = smb2_downgrade_oplock, .downgrade_oplock = smb2_downgrade_oplock,
.need_neg = smb2_need_neg, .need_neg = smb2_need_neg,
.negotiate = smb2_negotiate, .negotiate = smb2_negotiate,
...@@ -1775,6 +1793,7 @@ struct smb_version_operations smb30_operations = { ...@@ -1775,6 +1793,7 @@ struct smb_version_operations smb30_operations = {
.close_dir = smb2_close_dir, .close_dir = smb2_close_dir,
.calc_smb_size = smb2_calc_size, .calc_smb_size = smb2_calc_size,
.is_status_pending = smb2_is_status_pending, .is_status_pending = smb2_is_status_pending,
.is_session_expired = smb2_is_session_expired,
.oplock_response = smb2_oplock_response, .oplock_response = smb2_oplock_response,
.queryfs = smb2_queryfs, .queryfs = smb2_queryfs,
.mand_lock = smb2_mand_lock, .mand_lock = smb2_mand_lock,
...@@ -1821,6 +1840,7 @@ struct smb_version_operations smb311_operations = { ...@@ -1821,6 +1840,7 @@ struct smb_version_operations smb311_operations = {
.print_stats = smb2_print_stats, .print_stats = smb2_print_stats,
.dump_share_caps = smb2_dump_share_caps, .dump_share_caps = smb2_dump_share_caps,
.is_oplock_break = smb2_is_valid_oplock_break, .is_oplock_break = smb2_is_valid_oplock_break,
.handle_cancelled_mid = smb2_handle_cancelled_mid,
.downgrade_oplock = smb2_downgrade_oplock, .downgrade_oplock = smb2_downgrade_oplock,
.need_neg = smb2_need_neg, .need_neg = smb2_need_neg,
.negotiate = smb2_negotiate, .negotiate = smb2_negotiate,
...@@ -1863,6 +1883,7 @@ struct smb_version_operations smb311_operations = { ...@@ -1863,6 +1883,7 @@ struct smb_version_operations smb311_operations = {
.close_dir = smb2_close_dir, .close_dir = smb2_close_dir,
.calc_smb_size = smb2_calc_size, .calc_smb_size = smb2_calc_size,
.is_status_pending = smb2_is_status_pending, .is_status_pending = smb2_is_status_pending,
.is_session_expired = smb2_is_session_expired,
.oplock_response = smb2_oplock_response, .oplock_response = smb2_oplock_response,
.queryfs = smb2_queryfs, .queryfs = smb2_queryfs,
.mand_lock = smb2_mand_lock, .mand_lock = smb2_mand_lock,
......
...@@ -250,16 +250,19 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) ...@@ -250,16 +250,19 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
} }
cifs_mark_open_files_invalid(tcon); cifs_mark_open_files_invalid(tcon);
if (tcon->use_persistent)
tcon->need_reopen_files = true;
rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage);
mutex_unlock(&tcon->ses->session_mutex); mutex_unlock(&tcon->ses->session_mutex);
if (tcon->use_persistent)
cifs_reopen_persistent_handles(tcon);
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc); cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
if (rc) if (rc)
goto out; goto out;
if (smb2_command != SMB2_INTERNAL_CMD)
queue_delayed_work(cifsiod_wq, &server->reconnect, 0);
atomic_inc(&tconInfoReconnectCount); atomic_inc(&tconInfoReconnectCount);
out: out:
/* /*
...@@ -280,7 +283,7 @@ out: ...@@ -280,7 +283,7 @@ out:
case SMB2_CHANGE_NOTIFY: case SMB2_CHANGE_NOTIFY:
case SMB2_QUERY_INFO: case SMB2_QUERY_INFO:
case SMB2_SET_INFO: case SMB2_SET_INFO:
return -EAGAIN; rc = -EAGAIN;
} }
unload_nls(nls_codepage); unload_nls(nls_codepage);
return rc; return rc;
...@@ -363,7 +366,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req) ...@@ -363,7 +366,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req)
build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt); build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt);
req->NegotiateContextOffset = cpu_to_le32(OFFSET_OF_NEG_CONTEXT); req->NegotiateContextOffset = cpu_to_le32(OFFSET_OF_NEG_CONTEXT);
req->NegotiateContextCount = cpu_to_le16(2); req->NegotiateContextCount = cpu_to_le16(2);
inc_rfc1001_len(req, 4 + sizeof(struct smb2_preauth_neg_context) + 2 inc_rfc1001_len(req, 4 + sizeof(struct smb2_preauth_neg_context)
+ sizeof(struct smb2_encryption_neg_context)); /* calculate hash */ + sizeof(struct smb2_encryption_neg_context)); /* calculate hash */
} }
#else #else
...@@ -528,15 +531,22 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) ...@@ -528,15 +531,22 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
/* /*
* validation ioctl must be signed, so no point sending this if we * validation ioctl must be signed, so no point sending this if we
* can not sign it. We could eventually change this to selectively * can not sign it (ie are not known user). Even if signing is not
* required (enabled but not negotiated), in those cases we selectively
* sign just this, the first and only signed request on a connection. * sign just this, the first and only signed request on a connection.
* This is good enough for now since a user who wants better security * Having validation of negotiate info helps reduce attack vectors.
* would also enable signing on the mount. Having validation of
* negotiate info for signed connections helps reduce attack vectors
*/ */
if (tcon->ses->server->sign == false) if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST)
return 0; /* validation requires signing */ return 0; /* validation requires signing */
if (tcon->ses->user_name == NULL) {
cifs_dbg(FYI, "Can't validate negotiate: null user mount\n");
return 0; /* validation requires signing */
}
if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
cifs_dbg(VFS, "Unexpected null user (anonymous) auth flag sent by server\n");
vneg_inbuf.Capabilities = vneg_inbuf.Capabilities =
cpu_to_le32(tcon->ses->server->vals->req_capabilities); cpu_to_le32(tcon->ses->server->vals->req_capabilities);
memcpy(vneg_inbuf.Guid, tcon->ses->server->client_guid, memcpy(vneg_inbuf.Guid, tcon->ses->server->client_guid,
...@@ -566,8 +576,12 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) ...@@ -566,8 +576,12 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
} }
if (rsplen != sizeof(struct validate_negotiate_info_rsp)) { if (rsplen != sizeof(struct validate_negotiate_info_rsp)) {
cifs_dbg(VFS, "invalid size of protocol negotiate response\n"); cifs_dbg(VFS, "invalid protocol negotiate response size: %d\n",
return -EIO; rsplen);
/* relax check since Mac returns max bufsize allowed on ioctl */
if (rsplen > CIFSMaxBufSize)
return -EIO;
} }
/* check validate negotiate info response matches what we got earlier */ /* check validate negotiate info response matches what we got earlier */
...@@ -1003,6 +1017,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -1003,6 +1017,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
while (sess_data->func) while (sess_data->func)
sess_data->func(sess_data); sess_data->func(sess_data);
if ((ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST) && (ses->sign))
cifs_dbg(VFS, "signing requested but authenticated as guest\n");
rc = sess_data->result; rc = sess_data->result;
out: out:
kfree(sess_data); kfree(sess_data);
...@@ -1081,9 +1097,6 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ...@@ -1081,9 +1097,6 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
else else
return -EIO; return -EIO;
if (tcon && tcon->bad_network_name)
return -ENOENT;
if ((tcon && tcon->seal) && if ((tcon && tcon->seal) &&
((ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) == 0)) { ((ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) == 0)) {
cifs_dbg(VFS, "encryption requested but no server support"); cifs_dbg(VFS, "encryption requested but no server support");
...@@ -1101,6 +1114,10 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ...@@ -1101,6 +1114,10 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
return -EINVAL; return -EINVAL;
} }
/* SMB2 TREE_CONNECT request must be called with TreeId == 0 */
if (tcon)
tcon->tid = 0;
rc = small_smb2_init(SMB2_TREE_CONNECT, tcon, (void **) &req); rc = small_smb2_init(SMB2_TREE_CONNECT, tcon, (void **) &req);
if (rc) { if (rc) {
kfree(unc_path); kfree(unc_path);
...@@ -1181,8 +1198,6 @@ tcon_exit: ...@@ -1181,8 +1198,6 @@ tcon_exit:
tcon_error_exit: tcon_error_exit:
if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) { if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) {
cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree); cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
if (tcon)
tcon->bad_network_name = true;
} }
goto tcon_exit; goto tcon_exit;
} }
...@@ -1668,8 +1683,12 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, ...@@ -1668,8 +1683,12 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
* than one credit. Windows typically sets this smaller, but for some * than one credit. Windows typically sets this smaller, but for some
* ioctls it may be useful to allow server to send more. No point * ioctls it may be useful to allow server to send more. No point
* limiting what the server can send as long as fits in one credit * limiting what the server can send as long as fits in one credit
* Unfortunately - we can not handle more than CIFS_MAX_MSG_SIZE
* (by default, note that it can be overridden to make max larger)
* in responses (except for read responses which can be bigger.
* We may want to bump this limit up
*/ */
req->MaxOutputResponse = cpu_to_le32(0xFF00); /* < 64K uses 1 credit */ req->MaxOutputResponse = cpu_to_le32(CIFSMaxBufSize);
if (is_fsctl) if (is_fsctl)
req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL); req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL);
...@@ -1972,6 +1991,63 @@ smb2_echo_callback(struct mid_q_entry *mid) ...@@ -1972,6 +1991,63 @@ smb2_echo_callback(struct mid_q_entry *mid)
add_credits(server, credits_received, CIFS_ECHO_OP); add_credits(server, credits_received, CIFS_ECHO_OP);
} }
void smb2_reconnect_server(struct work_struct *work)
{
struct TCP_Server_Info *server = container_of(work,
struct TCP_Server_Info, reconnect.work);
struct cifs_ses *ses;
struct cifs_tcon *tcon, *tcon2;
struct list_head tmp_list;
int tcon_exist = false;
int rc;
int resched = false;
/* Prevent simultaneous reconnects that can corrupt tcon->rlist list */
mutex_lock(&server->reconnect_mutex);
INIT_LIST_HEAD(&tmp_list);
cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n");
spin_lock(&cifs_tcp_ses_lock);
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
if (tcon->need_reconnect || tcon->need_reopen_files) {
tcon->tc_count++;
list_add_tail(&tcon->rlist, &tmp_list);
tcon_exist = true;
}
}
}
/*
* 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.
*/
if (tcon_exist)
server->srv_count++;
spin_unlock(&cifs_tcp_ses_lock);
list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) {
rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon);
if (!rc)
cifs_reopen_persistent_handles(tcon);
else
resched = true;
list_del_init(&tcon->rlist);
cifs_put_tcon(tcon);
}
cifs_dbg(FYI, "Reconnecting tcons finished\n");
if (resched)
queue_delayed_work(cifsiod_wq, &server->reconnect, 2 * HZ);
mutex_unlock(&server->reconnect_mutex);
/* now we can safely release srv struct */
if (tcon_exist)
cifs_put_tcp_session(server, 1);
}
int int
SMB2_echo(struct TCP_Server_Info *server) SMB2_echo(struct TCP_Server_Info *server)
{ {
...@@ -1984,32 +2060,11 @@ SMB2_echo(struct TCP_Server_Info *server) ...@@ -1984,32 +2060,11 @@ SMB2_echo(struct TCP_Server_Info *server)
cifs_dbg(FYI, "In echo request\n"); cifs_dbg(FYI, "In echo request\n");
if (server->tcpStatus == CifsNeedNegotiate) { if (server->tcpStatus == CifsNeedNegotiate) {
struct list_head *tmp, *tmp2; /* No need to send echo on newly established connections */
struct cifs_ses *ses; queue_delayed_work(cifsiod_wq, &server->reconnect, 0);
struct cifs_tcon *tcon; return rc;
cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n");
spin_lock(&cifs_tcp_ses_lock);
list_for_each(tmp, &server->smb_ses_list) {
ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
list_for_each(tmp2, &ses->tcon_list) {
tcon = list_entry(tmp2, struct cifs_tcon,
tcon_list);
/* add check for persistent handle reconnect */
if (tcon && tcon->need_reconnect) {
spin_unlock(&cifs_tcp_ses_lock);
rc = smb2_reconnect(SMB2_ECHO, tcon);
spin_lock(&cifs_tcp_ses_lock);
}
}
}
spin_unlock(&cifs_tcp_ses_lock);
} }
/* if no session, renegotiate failed above */
if (server->tcpStatus == CifsNeedNegotiate)
return -EIO;
rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req); rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req);
if (rc) if (rc)
return rc; return rc;
...@@ -2884,8 +2939,8 @@ copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, ...@@ -2884,8 +2939,8 @@ copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf,
kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) * kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) *
le32_to_cpu(pfs_inf->SectorsPerAllocationUnit); le32_to_cpu(pfs_inf->SectorsPerAllocationUnit);
kst->f_blocks = le64_to_cpu(pfs_inf->TotalAllocationUnits); kst->f_blocks = le64_to_cpu(pfs_inf->TotalAllocationUnits);
kst->f_bfree = le64_to_cpu(pfs_inf->ActualAvailableAllocationUnits); kst->f_bfree = kst->f_bavail =
kst->f_bavail = le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits); le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits);
return; return;
} }
......
...@@ -80,10 +80,12 @@ ...@@ -80,10 +80,12 @@
#define SMB2_SET_INFO cpu_to_le16(SMB2_SET_INFO_HE) #define SMB2_SET_INFO cpu_to_le16(SMB2_SET_INFO_HE)
#define SMB2_OPLOCK_BREAK cpu_to_le16(SMB2_OPLOCK_BREAK_HE) #define SMB2_OPLOCK_BREAK cpu_to_le16(SMB2_OPLOCK_BREAK_HE)
#define SMB2_INTERNAL_CMD cpu_to_le16(0xFFFF)
#define NUMBER_OF_SMB2_COMMANDS 0x0013 #define NUMBER_OF_SMB2_COMMANDS 0x0013
/* BB FIXME - analyze following length BB */ /* 4 len + 52 transform hdr + 64 hdr + 56 create rsp */
#define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */ #define MAX_SMB2_HDR_SIZE 0x00b0
#define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe) #define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe)
#define SMB2_TRANSFORM_PROTO_NUM cpu_to_le32(0x424d53fd) #define SMB2_TRANSFORM_PROTO_NUM cpu_to_le32(0x424d53fd)
......
...@@ -48,6 +48,10 @@ extern struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses, ...@@ -48,6 +48,10 @@ extern struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses,
struct smb_rqst *rqst); struct smb_rqst *rqst);
extern struct mid_q_entry *smb2_setup_async_request( extern struct mid_q_entry *smb2_setup_async_request(
struct TCP_Server_Info *server, struct smb_rqst *rqst); struct TCP_Server_Info *server, struct smb_rqst *rqst);
extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server,
__u64 ses_id);
extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server,
__u64 ses_id, __u32 tid);
extern int smb2_calc_signature(struct smb_rqst *rqst, extern int smb2_calc_signature(struct smb_rqst *rqst,
struct TCP_Server_Info *server); struct TCP_Server_Info *server);
extern int smb3_calc_signature(struct smb_rqst *rqst, extern int smb3_calc_signature(struct smb_rqst *rqst,
...@@ -96,6 +100,7 @@ extern int smb2_open_file(const unsigned int xid, ...@@ -96,6 +100,7 @@ extern int smb2_open_file(const unsigned int xid,
extern int smb2_unlock_range(struct cifsFileInfo *cfile, extern int smb2_unlock_range(struct cifsFileInfo *cfile,
struct file_lock *flock, const unsigned int xid); struct file_lock *flock, const unsigned int xid);
extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile); extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
extern void smb2_reconnect_server(struct work_struct *work);
/* /*
* SMB2 Worker functions - most of protocol specific implementation details * SMB2 Worker functions - most of protocol specific implementation details
...@@ -157,6 +162,9 @@ extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -157,6 +162,9 @@ extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
const u64 persistent_fid, const u64 volatile_fid, const u64 persistent_fid, const u64 volatile_fid,
const __u8 oplock_level); const __u8 oplock_level);
extern int smb2_handle_cancelled_mid(char *buffer,
struct TCP_Server_Info *server);
void smb2_cancelled_close_fid(struct work_struct *work);
extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id, u64 persistent_file_id, u64 volatile_file_id,
struct kstatfs *FSData); struct kstatfs *FSData);
......
...@@ -115,22 +115,68 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server) ...@@ -115,22 +115,68 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
} }
static struct cifs_ses * static struct cifs_ses *
smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server) smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
{ {
struct cifs_ses *ses; struct cifs_ses *ses;
spin_lock(&cifs_tcp_ses_lock);
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
if (ses->Suid != smb2hdr->SessionId) if (ses->Suid != ses_id)
continue; continue;
spin_unlock(&cifs_tcp_ses_lock);
return ses; return ses;
} }
return NULL;
}
struct cifs_ses *
smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id)
{
struct cifs_ses *ses;
spin_lock(&cifs_tcp_ses_lock);
ses = smb2_find_smb_ses_unlocked(server, ses_id);
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
return ses;
}
static struct cifs_tcon *
smb2_find_smb_sess_tcon_unlocked(struct cifs_ses *ses, __u32 tid)
{
struct cifs_tcon *tcon;
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
if (tcon->tid != tid)
continue;
++tcon->tc_count;
return tcon;
}
return NULL; return NULL;
} }
/*
* Obtain tcon corresponding to the tid in the given
* cifs_ses
*/
struct cifs_tcon *
smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid)
{
struct cifs_ses *ses;
struct cifs_tcon *tcon;
spin_lock(&cifs_tcp_ses_lock);
ses = smb2_find_smb_ses_unlocked(server, ses_id);
if (!ses) {
spin_unlock(&cifs_tcp_ses_lock);
return NULL;
}
tcon = smb2_find_smb_sess_tcon_unlocked(ses, tid);
spin_unlock(&cifs_tcp_ses_lock);
return tcon;
}
int int
smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
...@@ -142,7 +188,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -142,7 +188,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
struct cifs_ses *ses; struct cifs_ses *ses;
ses = smb2_find_smb_ses(smb2_pdu, server); ses = smb2_find_smb_ses(server, smb2_pdu->SessionId);
if (!ses) { if (!ses) {
cifs_dbg(VFS, "%s: Could not find session\n", __func__); cifs_dbg(VFS, "%s: Could not find session\n", __func__);
return 0; return 0;
...@@ -359,7 +405,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -359,7 +405,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
struct cifs_ses *ses; struct cifs_ses *ses;
ses = smb2_find_smb_ses(smb2_pdu, server); ses = smb2_find_smb_ses(server, smb2_pdu->SessionId);
if (!ses) { if (!ses) {
cifs_dbg(VFS, "%s: Could not find session\n", __func__); cifs_dbg(VFS, "%s: Could not find session\n", __func__);
return 0; return 0;
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <crypto/skcipher.h> #include <linux/crypto.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/fs.h> #include <linux/fs.h>
...@@ -69,46 +69,22 @@ str_to_key(unsigned char *str, unsigned char *key) ...@@ -69,46 +69,22 @@ str_to_key(unsigned char *str, unsigned char *key)
static int static int
smbhash(unsigned char *out, const unsigned char *in, unsigned char *key) smbhash(unsigned char *out, const unsigned char *in, unsigned char *key)
{ {
int rc;
unsigned char key2[8]; unsigned char key2[8];
struct crypto_skcipher *tfm_des; struct crypto_cipher *tfm_des;
struct scatterlist sgin, sgout;
struct skcipher_request *req;
str_to_key(key, key2); str_to_key(key, key2);
tfm_des = crypto_alloc_skcipher("ecb(des)", 0, CRYPTO_ALG_ASYNC); tfm_des = crypto_alloc_cipher("des", 0, 0);
if (IS_ERR(tfm_des)) { if (IS_ERR(tfm_des)) {
rc = PTR_ERR(tfm_des);
cifs_dbg(VFS, "could not allocate des crypto API\n");
goto smbhash_err;
}
req = skcipher_request_alloc(tfm_des, GFP_KERNEL);
if (!req) {
rc = -ENOMEM;
cifs_dbg(VFS, "could not allocate des crypto API\n"); cifs_dbg(VFS, "could not allocate des crypto API\n");
goto smbhash_free_skcipher; return PTR_ERR(tfm_des);
} }
crypto_skcipher_setkey(tfm_des, key2, 8); crypto_cipher_setkey(tfm_des, key2, 8);
crypto_cipher_encrypt_one(tfm_des, out, in);
sg_init_one(&sgin, in, 8); crypto_free_cipher(tfm_des);
sg_init_one(&sgout, out, 8);
skcipher_request_set_callback(req, 0, NULL, NULL); return 0;
skcipher_request_set_crypt(req, &sgin, &sgout, 8, NULL);
rc = crypto_skcipher_encrypt(req);
if (rc)
cifs_dbg(VFS, "could not encrypt crypt key rc: %d\n", rc);
skcipher_request_free(req);
smbhash_free_skcipher:
crypto_free_skcipher(tfm_des);
smbhash_err:
return rc;
} }
static int static int
......
...@@ -727,9 +727,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, ...@@ -727,9 +727,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
rc = wait_for_response(ses->server, midQ); rc = wait_for_response(ses->server, midQ);
if (rc != 0) { if (rc != 0) {
cifs_dbg(FYI, "Cancelling wait for mid %llu\n", midQ->mid);
send_cancel(ses->server, buf, midQ); send_cancel(ses->server, buf, midQ);
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
if (midQ->mid_state == MID_REQUEST_SUBMITTED) { if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
midQ->mid_flags |= MID_WAIT_CANCELLED;
midQ->callback = DeleteMidQEntry; midQ->callback = DeleteMidQEntry;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
cifs_small_buf_release(buf); cifs_small_buf_release(buf);
......
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