Commit 645c248d authored by Linus Torvalds's avatar Linus Torvalds

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

Pull cifs updates from Steve French:
 "First part of cifs/smb3 changes for merge window (others are still
  being tested). Various RDMA (smbdirect) fixes, addition of SMB3.1.1
  POSIX support in readdir, 3 fixes for stable, and a fix for flock.

  Summary:

  New feature:
   - SMB3.1.1 POSIX support in readdir

  Fixes:
   - various RDMA (smbdirect) fixes
   - fix for flock
   - fallocate fix
   - some improved mount warnings
   - two timestamp related fixes
   - reconnect fix
   - three fixes for stable"

* tag '5.7-rc-smb3-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6: (28 commits)
  cifs: update internal module version number
  cifs: Allocate encryption header through kmalloc
  cifs: smbd: Check and extend sender credits in interrupt context
  cifs: smbd: Calculate the correct maximum packet size for segmented SMBDirect send/receive
  smb3: use SMB2_SIGNATURE_SIZE define
  CIFS: Fix bug which the return value by asynchronous read is error
  CIFS: check new file size when extending file by fallocate
  SMB3: Minor cleanup of protocol definitions
  SMB3: Additional compression structures
  SMB3: Add new compression flags
  cifs: smb2pdu.h: Replace zero-length array with flexible-array member
  cifs: clear PF_MEMALLOC before exiting demultiplex thread
  cifs: cifspdu.h: Replace zero-length array with flexible-array member
  CIFS: Warn less noisily on default mount
  fs/cifs: fix gcc warning in sid_to_id
  cifs: allow unlock flock and OFD lock across fork
  cifs: do d_move in rename
  cifs: add SMB2_open() arg to return POSIX data
  cifs: plumb smb2 POSIX dir enumeration
  cifs: add smb2 POSIX info level
  ...
parents 018d21f5 f460c502
...@@ -342,7 +342,7 @@ static int ...@@ -342,7 +342,7 @@ static int
sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
struct cifs_fattr *fattr, uint sidtype) struct cifs_fattr *fattr, uint sidtype)
{ {
int rc; int rc = 0;
struct key *sidkey; struct key *sidkey;
char *sidstr; char *sidstr;
const struct cred *saved_cred; const struct cred *saved_cred;
...@@ -450,11 +450,12 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, ...@@ -450,11 +450,12 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
* fails then we just fall back to using the mnt_uid/mnt_gid. * fails then we just fall back to using the mnt_uid/mnt_gid.
*/ */
got_valid_id: got_valid_id:
rc = 0;
if (sidtype == SIDOWNER) if (sidtype == SIDOWNER)
fattr->cf_uid = fuid; fattr->cf_uid = fuid;
else else
fattr->cf_gid = fgid; fattr->cf_gid = fgid;
return 0; return rc;
} }
int int
......
...@@ -1018,7 +1018,7 @@ struct file_system_type cifs_fs_type = { ...@@ -1018,7 +1018,7 @@ struct file_system_type cifs_fs_type = {
.name = "cifs", .name = "cifs",
.mount = cifs_do_mount, .mount = cifs_do_mount,
.kill_sb = cifs_kill_sb, .kill_sb = cifs_kill_sb,
/* .fs_flags */ .fs_flags = FS_RENAME_DOES_D_MOVE,
}; };
MODULE_ALIAS_FS("cifs"); MODULE_ALIAS_FS("cifs");
...@@ -1027,7 +1027,7 @@ static struct file_system_type smb3_fs_type = { ...@@ -1027,7 +1027,7 @@ static struct file_system_type smb3_fs_type = {
.name = "smb3", .name = "smb3",
.mount = smb3_do_mount, .mount = smb3_do_mount,
.kill_sb = cifs_kill_sb, .kill_sb = cifs_kill_sb,
/* .fs_flags */ .fs_flags = FS_RENAME_DOES_D_MOVE,
}; };
MODULE_ALIAS_FS("smb3"); MODULE_ALIAS_FS("smb3");
MODULE_ALIAS("smb3"); MODULE_ALIAS("smb3");
......
...@@ -156,5 +156,5 @@ extern int cifs_truncate_page(struct address_space *mapping, loff_t from); ...@@ -156,5 +156,5 @@ extern int cifs_truncate_page(struct address_space *mapping, loff_t from);
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.25" #define CIFS_VERSION "2.26"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -1021,7 +1021,7 @@ typedef struct smb_com_writex_req { ...@@ -1021,7 +1021,7 @@ typedef struct smb_com_writex_req {
__le16 ByteCount; __le16 ByteCount;
__u8 Pad; /* BB check for whether padded to DWORD __u8 Pad; /* BB check for whether padded to DWORD
boundary and optimum performance here */ boundary and optimum performance here */
char Data[0]; char Data[];
} __attribute__((packed)) WRITEX_REQ; } __attribute__((packed)) WRITEX_REQ;
typedef struct smb_com_write_req { typedef struct smb_com_write_req {
...@@ -1041,7 +1041,7 @@ typedef struct smb_com_write_req { ...@@ -1041,7 +1041,7 @@ typedef struct smb_com_write_req {
__le16 ByteCount; __le16 ByteCount;
__u8 Pad; /* BB check for whether padded to DWORD __u8 Pad; /* BB check for whether padded to DWORD
boundary and optimum performance here */ boundary and optimum performance here */
char Data[0]; char Data[];
} __attribute__((packed)) WRITE_REQ; } __attribute__((packed)) WRITE_REQ;
typedef struct smb_com_write_rsp { typedef struct smb_com_write_rsp {
...@@ -1306,7 +1306,7 @@ typedef struct smb_com_ntransact_req { ...@@ -1306,7 +1306,7 @@ typedef struct smb_com_ntransact_req {
/* SetupCount words follow then */ /* SetupCount words follow then */
__le16 ByteCount; __le16 ByteCount;
__u8 Pad[3]; __u8 Pad[3];
__u8 Parms[0]; __u8 Parms[];
} __attribute__((packed)) NTRANSACT_REQ; } __attribute__((packed)) NTRANSACT_REQ;
typedef struct smb_com_ntransact_rsp { typedef struct smb_com_ntransact_rsp {
...@@ -1523,7 +1523,7 @@ struct file_notify_information { ...@@ -1523,7 +1523,7 @@ struct file_notify_information {
__le32 NextEntryOffset; __le32 NextEntryOffset;
__le32 Action; __le32 Action;
__le32 FileNameLength; __le32 FileNameLength;
__u8 FileName[0]; __u8 FileName[];
} __attribute__((packed)); } __attribute__((packed));
/* For IO_REPARSE_TAG_SYMLINK */ /* For IO_REPARSE_TAG_SYMLINK */
...@@ -1536,7 +1536,7 @@ struct reparse_symlink_data { ...@@ -1536,7 +1536,7 @@ struct reparse_symlink_data {
__le16 PrintNameOffset; __le16 PrintNameOffset;
__le16 PrintNameLength; __le16 PrintNameLength;
__le32 Flags; __le32 Flags;
char PathBuffer[0]; char PathBuffer[];
} __attribute__((packed)); } __attribute__((packed));
/* Flag above */ /* Flag above */
...@@ -1553,7 +1553,7 @@ struct reparse_posix_data { ...@@ -1553,7 +1553,7 @@ struct reparse_posix_data {
__le16 ReparseDataLength; __le16 ReparseDataLength;
__u16 Reserved; __u16 Reserved;
__le64 InodeType; /* LNK, FIFO, CHR etc. */ __le64 InodeType; /* LNK, FIFO, CHR etc. */
char PathBuffer[0]; char PathBuffer[];
} __attribute__((packed)); } __attribute__((packed));
struct cifs_quota_data { struct cifs_quota_data {
...@@ -1691,6 +1691,7 @@ struct smb_t2_rsp { ...@@ -1691,6 +1691,7 @@ struct smb_t2_rsp {
#define SMB_FIND_FILE_ID_FULL_DIR_INFO 0x105 #define SMB_FIND_FILE_ID_FULL_DIR_INFO 0x105
#define SMB_FIND_FILE_ID_BOTH_DIR_INFO 0x106 #define SMB_FIND_FILE_ID_BOTH_DIR_INFO 0x106
#define SMB_FIND_FILE_UNIX 0x202 #define SMB_FIND_FILE_UNIX 0x202
#define SMB_FIND_FILE_POSIX_INFO 0x064
typedef struct smb_com_transaction2_qpi_req { typedef struct smb_com_transaction2_qpi_req {
struct smb_hdr hdr; /* wct = 14+ */ struct smb_hdr hdr; /* wct = 14+ */
...@@ -1761,7 +1762,7 @@ struct set_file_rename { ...@@ -1761,7 +1762,7 @@ struct set_file_rename {
__le32 overwrite; /* 1 = overwrite dest */ __le32 overwrite; /* 1 = overwrite dest */
__u32 root_fid; /* zero */ __u32 root_fid; /* zero */
__le32 target_name_len; __le32 target_name_len;
char target_name[0]; /* Must be unicode */ char target_name[]; /* Must be unicode */
} __attribute__((packed)); } __attribute__((packed));
struct smb_com_transaction2_sfi_req { struct smb_com_transaction2_sfi_req {
...@@ -2450,7 +2451,7 @@ struct cifs_posix_acl { /* access conrol list (ACL) */ ...@@ -2450,7 +2451,7 @@ struct cifs_posix_acl { /* access conrol list (ACL) */
__le16 version; __le16 version;
__le16 access_entry_count; /* access ACL - count of entries */ __le16 access_entry_count; /* access ACL - count of entries */
__le16 default_entry_count; /* default ACL - count of entries */ __le16 default_entry_count; /* default ACL - count of entries */
struct cifs_posix_ace ace_array[0]; struct cifs_posix_ace ace_array[];
/* followed by /* followed by
struct cifs_posix_ace default_ace_arraay[] */ struct cifs_posix_ace default_ace_arraay[] */
} __attribute__((packed)); /* level 0x204 */ } __attribute__((packed)); /* level 0x204 */
...@@ -2756,7 +2757,7 @@ typedef struct file_xattr_info { ...@@ -2756,7 +2757,7 @@ typedef struct file_xattr_info {
/* BB do we need another field for flags? BB */ /* BB do we need another field for flags? BB */
__u32 xattr_name_len; __u32 xattr_name_len;
__u32 xattr_value_len; __u32 xattr_value_len;
char xattr_name[0]; char xattr_name[];
/* followed by xattr_value[xattr_value_len], no pad */ /* followed by xattr_value[xattr_value_len], no pad */
} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute info } __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute info
level 0x205 */ level 0x205 */
......
...@@ -602,6 +602,11 @@ int smb2_parse_query_directory(struct cifs_tcon *tcon, struct kvec *rsp_iov, ...@@ -602,6 +602,11 @@ int smb2_parse_query_directory(struct cifs_tcon *tcon, struct kvec *rsp_iov,
int resp_buftype, int resp_buftype,
struct cifs_search_info *srch_inf); struct cifs_search_info *srch_inf);
struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server);
void cifs_put_tcp_super(struct super_block *sb);
int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
size_t prefix_len);
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses, static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
const char *old_path, const char *old_path,
......
...@@ -162,9 +162,18 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc, ...@@ -162,9 +162,18 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc,
for (it = dfs_cache_get_tgt_iterator(&tl); it; for (it = dfs_cache_get_tgt_iterator(&tl); it;
it = dfs_cache_get_next_tgt(&tl, it)) { it = dfs_cache_get_next_tgt(&tl, it)) {
const char *tgt = dfs_cache_get_tgt_name(it); const char *share, *prefix;
size_t share_len, prefix_len;
extract_unc_hostname(tgt, &dfs_host, &dfs_host_len); rc = dfs_cache_get_tgt_share(it, &share, &share_len, &prefix,
&prefix_len);
if (rc) {
cifs_dbg(VFS, "%s: failed to parse target share %d\n",
__func__, rc);
continue;
}
extract_unc_hostname(share, &dfs_host, &dfs_host_len);
if (dfs_host_len != tcp_host_len if (dfs_host_len != tcp_host_len
|| strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) { || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
...@@ -175,11 +184,13 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc, ...@@ -175,11 +184,13 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc,
continue; continue;
} }
scnprintf(tree, MAX_TREE_SIZE, "\\%s", tgt); scnprintf(tree, MAX_TREE_SIZE, "\\%.*s", (int)share_len, share);
rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc); rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
if (!rc) if (!rc) {
rc = update_super_prepath(tcon, prefix, prefix_len);
break; break;
}
if (rc == -EREMOTE) if (rc == -EREMOTE)
break; break;
} }
...@@ -320,7 +331,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) ...@@ -320,7 +331,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
atomic_inc(&tconInfoReconnectCount); atomic_inc(&tconInfoReconnectCount);
/* tell server Unix caps we support */ /* tell server Unix caps we support */
if (ses->capabilities & CAP_UNIX) if (cap_unix(ses))
reset_cifs_unix_caps(0, tcon, NULL, NULL); reset_cifs_unix_caps(0, tcon, NULL, NULL);
/* /*
...@@ -1591,7 +1602,6 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -1591,7 +1602,6 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
if (server->ops->is_session_expired && if (server->ops->is_session_expired &&
server->ops->is_session_expired(buf)) { server->ops->is_session_expired(buf)) {
cifs_reconnect(server); cifs_reconnect(server);
wake_up(&server->response_q);
return -1; return -1;
} }
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/sched/mm.h>
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/wait.h> #include <linux/wait.h>
...@@ -57,7 +58,6 @@ ...@@ -57,7 +58,6 @@
#include "smb2proto.h" #include "smb2proto.h"
#include "smbdirect.h" #include "smbdirect.h"
#include "dns_resolve.h" #include "dns_resolve.h"
#include "cifsfs.h"
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
#include "dfs_cache.h" #include "dfs_cache.h"
#endif #endif
...@@ -389,54 +389,7 @@ static inline int reconn_set_ipaddr(struct TCP_Server_Info *server) ...@@ -389,54 +389,7 @@ static inline int reconn_set_ipaddr(struct TCP_Server_Info *server)
#endif #endif
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
struct super_cb_data {
struct TCP_Server_Info *server;
struct super_block *sb;
};
/* These functions must be called with server->srv_mutex held */ /* These functions must be called with server->srv_mutex held */
static void super_cb(struct super_block *sb, void *arg)
{
struct super_cb_data *d = arg;
struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon;
if (d->sb)
return;
cifs_sb = CIFS_SB(sb);
tcon = cifs_sb_master_tcon(cifs_sb);
if (tcon->ses->server == d->server)
d->sb = sb;
}
static struct super_block *get_tcp_super(struct TCP_Server_Info *server)
{
struct super_cb_data d = {
.server = server,
.sb = NULL,
};
iterate_supers_type(&cifs_fs_type, super_cb, &d);
if (unlikely(!d.sb))
return ERR_PTR(-ENOENT);
/*
* Grab an active reference in order to prevent automounts (DFS links)
* of expiring and then freeing up our cifs superblock pointer while
* we're doing failover.
*/
cifs_sb_active(d.sb);
return d.sb;
}
static inline void put_tcp_super(struct super_block *sb)
{
if (!IS_ERR_OR_NULL(sb))
cifs_sb_deactive(sb);
}
static void reconn_inval_dfs_target(struct TCP_Server_Info *server, static void reconn_inval_dfs_target(struct TCP_Server_Info *server,
struct cifs_sb_info *cifs_sb, struct cifs_sb_info *cifs_sb,
struct dfs_cache_tgt_list *tgt_list, struct dfs_cache_tgt_list *tgt_list,
...@@ -508,7 +461,7 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -508,7 +461,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
server->nr_targets = 1; server->nr_targets = 1;
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
sb = get_tcp_super(server); sb = cifs_get_tcp_super(server);
if (IS_ERR(sb)) { if (IS_ERR(sb)) {
rc = PTR_ERR(sb); rc = PTR_ERR(sb);
cifs_dbg(FYI, "%s: will not do DFS failover: rc = %d\n", cifs_dbg(FYI, "%s: will not do DFS failover: rc = %d\n",
...@@ -535,8 +488,9 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -535,8 +488,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
dfs_cache_free_tgts(&tgt_list); dfs_cache_free_tgts(&tgt_list);
put_tcp_super(sb); cifs_put_tcp_super(sb);
#endif #endif
wake_up(&server->response_q);
return rc; return rc;
} else } else
server->tcpStatus = CifsNeedReconnect; server->tcpStatus = CifsNeedReconnect;
...@@ -666,11 +620,12 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -666,11 +620,12 @@ cifs_reconnect(struct TCP_Server_Info *server)
} }
put_tcp_super(sb); cifs_put_tcp_super(sb);
#endif #endif
if (server->tcpStatus == CifsNeedNegotiate) if (server->tcpStatus == CifsNeedNegotiate)
mod_delayed_work(cifsiod_wq, &server->echo, 0); mod_delayed_work(cifsiod_wq, &server->echo, 0);
wake_up(&server->response_q);
return rc; return rc;
} }
...@@ -765,7 +720,6 @@ server_unresponsive(struct TCP_Server_Info *server) ...@@ -765,7 +720,6 @@ server_unresponsive(struct TCP_Server_Info *server)
cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n", cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n",
(3 * server->echo_interval) / HZ); (3 * server->echo_interval) / HZ);
cifs_reconnect(server); cifs_reconnect(server);
wake_up(&server->response_q);
return true; return true;
} }
...@@ -898,7 +852,6 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type) ...@@ -898,7 +852,6 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
*/ */
cifs_set_port((struct sockaddr *)&server->dstaddr, CIFS_PORT); cifs_set_port((struct sockaddr *)&server->dstaddr, CIFS_PORT);
cifs_reconnect(server); cifs_reconnect(server);
wake_up(&server->response_q);
break; break;
default: default:
cifs_server_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", type); cifs_server_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", type);
...@@ -1070,7 +1023,6 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -1070,7 +1023,6 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
server->vals->header_preamble_size) { server->vals->header_preamble_size) {
cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length); cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
cifs_reconnect(server); cifs_reconnect(server);
wake_up(&server->response_q);
return -ECONNABORTED; return -ECONNABORTED;
} }
...@@ -1118,7 +1070,6 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -1118,7 +1070,6 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
if (server->ops->is_session_expired && if (server->ops->is_session_expired &&
server->ops->is_session_expired(buf)) { server->ops->is_session_expired(buf)) {
cifs_reconnect(server); cifs_reconnect(server);
wake_up(&server->response_q);
return -1; return -1;
} }
...@@ -1164,8 +1115,9 @@ cifs_demultiplex_thread(void *p) ...@@ -1164,8 +1115,9 @@ cifs_demultiplex_thread(void *p)
struct task_struct *task_to_wake = NULL; struct task_struct *task_to_wake = NULL;
struct mid_q_entry *mids[MAX_COMPOUND]; struct mid_q_entry *mids[MAX_COMPOUND];
char *bufs[MAX_COMPOUND]; char *bufs[MAX_COMPOUND];
unsigned int noreclaim_flag;
current->flags |= PF_MEMALLOC; noreclaim_flag = memalloc_noreclaim_save();
cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current)); cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current));
length = atomic_inc_return(&tcpSesAllocCount); length = atomic_inc_return(&tcpSesAllocCount);
...@@ -1212,7 +1164,6 @@ cifs_demultiplex_thread(void *p) ...@@ -1212,7 +1164,6 @@ cifs_demultiplex_thread(void *p)
cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n", cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n",
server->pdu_size); server->pdu_size);
cifs_reconnect(server); cifs_reconnect(server);
wake_up(&server->response_q);
continue; continue;
} }
...@@ -1320,6 +1271,7 @@ cifs_demultiplex_thread(void *p) ...@@ -1320,6 +1271,7 @@ cifs_demultiplex_thread(void *p)
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
} }
memalloc_noreclaim_restore(noreclaim_flag);
module_put_and_exit(0); module_put_and_exit(0);
} }
...@@ -1522,6 +1474,9 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3) ...@@ -1522,6 +1474,9 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3)
cifs_dbg(VFS, "vers=1.0 (cifs) not permitted when mounting with smb3\n"); cifs_dbg(VFS, "vers=1.0 (cifs) not permitted when mounting with smb3\n");
return 1; return 1;
} }
cifs_dbg(VFS, "Use of the less secure dialect vers=1.0 "
"is not recommended unless required for "
"access to very old servers\n");
vol->ops = &smb1_operations; vol->ops = &smb1_operations;
vol->vals = &smb1_values; vol->vals = &smb1_values;
break; break;
...@@ -2517,11 +2472,12 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, ...@@ -2517,11 +2472,12 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
pr_notice("CIFS: ignoring forcegid mount option specified with no gid= option.\n"); pr_notice("CIFS: ignoring forcegid mount option specified with no gid= option.\n");
if (got_version == false) if (got_version == false)
pr_warn("No dialect specified on mount. Default has changed to " pr_warn_once("No dialect specified on mount. Default has changed"
"a more secure dialect, SMB2.1 or later (e.g. SMB3), from CIFS " " to a more secure dialect, SMB2.1 or later (e.g. "
"(SMB1). To use the less secure SMB1 dialect to access " "SMB3.1.1), from CIFS (SMB1). To use the less secure "
"old servers which do not support SMB3 (or SMB2.1) specify vers=1.0" "SMB1 dialect to access old servers which do not "
" on mount.\n"); "support SMB3.1.1 (or even SMB3 or SMB2.1) specify "
"vers=1.0 on mount.\n");
kfree(mountdata_copy); kfree(mountdata_copy);
return 0; return 0;
...@@ -4999,6 +4955,15 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) ...@@ -4999,6 +4955,15 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
* dentry revalidation to think the dentry are stale (ESTALE). * dentry revalidation to think the dentry are stale (ESTALE).
*/ */
cifs_autodisable_serverino(cifs_sb); cifs_autodisable_serverino(cifs_sb);
/*
* Force the use of prefix path to support failover on DFS paths that
* resolve to targets that have different prefix paths.
*/
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
kfree(cifs_sb->prepath);
cifs_sb->prepath = vol->prepath;
vol->prepath = NULL;
out: out:
free_xid(xid); free_xid(xid);
cifs_try_adding_channels(ses); cifs_try_adding_channels(ses);
......
...@@ -1260,6 +1260,44 @@ void dfs_cache_del_vol(const char *fullpath) ...@@ -1260,6 +1260,44 @@ void dfs_cache_del_vol(const char *fullpath)
kref_put(&vi->refcnt, vol_release); kref_put(&vi->refcnt, vol_release);
} }
/**
* dfs_cache_get_tgt_share - parse a DFS target
*
* @it: DFS target iterator.
* @share: tree name.
* @share_len: length of tree name.
* @prefix: prefix path.
* @prefix_len: length of prefix path.
*
* Return zero if target was parsed correctly, otherwise non-zero.
*/
int dfs_cache_get_tgt_share(const struct dfs_cache_tgt_iterator *it,
const char **share, size_t *share_len,
const char **prefix, size_t *prefix_len)
{
char *s, sep;
if (!it || !share || !share_len || !prefix || !prefix_len)
return -EINVAL;
sep = it->it_name[0];
if (sep != '\\' && sep != '/')
return -EINVAL;
s = strchr(it->it_name + 1, sep);
if (!s)
return -EINVAL;
s = strchrnul(s + 1, sep);
*share = it->it_name;
*share_len = s - it->it_name;
*prefix = *s ? s + 1 : s;
*prefix_len = &it->it_name[strlen(it->it_name)] - *prefix;
return 0;
}
/* Get all tcons that are within a DFS namespace and can be refreshed */ /* Get all tcons that are within a DFS namespace and can be refreshed */
static void get_tcons(struct TCP_Server_Info *server, struct list_head *head) static void get_tcons(struct TCP_Server_Info *server, struct list_head *head)
{ {
......
...@@ -49,6 +49,10 @@ extern int dfs_cache_update_vol(const char *fullpath, ...@@ -49,6 +49,10 @@ extern int dfs_cache_update_vol(const char *fullpath,
struct TCP_Server_Info *server); struct TCP_Server_Info *server);
extern void dfs_cache_del_vol(const char *fullpath); extern void dfs_cache_del_vol(const char *fullpath);
extern int dfs_cache_get_tgt_share(const struct dfs_cache_tgt_iterator *it,
const char **share, size_t *share_len,
const char **prefix, size_t *prefix_len);
static inline struct dfs_cache_tgt_iterator * static inline struct dfs_cache_tgt_iterator *
dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl, dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl,
struct dfs_cache_tgt_iterator *it) struct dfs_cache_tgt_iterator *it)
......
...@@ -3841,7 +3841,7 @@ collect_uncached_read_data(struct cifs_aio_ctx *ctx) ...@@ -3841,7 +3841,7 @@ collect_uncached_read_data(struct cifs_aio_ctx *ctx)
if (rc == -ENODATA) if (rc == -ENODATA)
rc = 0; rc = 0;
ctx->rc = (rc == 0) ? ctx->total_len : rc; ctx->rc = (rc == 0) ? (ssize_t)ctx->total_len : rc;
mutex_unlock(&ctx->aio_mutex); mutex_unlock(&ctx->aio_mutex);
......
...@@ -1835,6 +1835,8 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, ...@@ -1835,6 +1835,8 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
CIFSSMBClose(xid, tcon, fid.netfid); CIFSSMBClose(xid, tcon, fid.netfid);
} }
do_rename_exit: do_rename_exit:
if (rc == 0)
d_move(from_dentry, to_dentry);
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
return rc; return rc;
} }
...@@ -2148,8 +2150,9 @@ int cifs_getattr(const struct path *path, struct kstat *stat, ...@@ -2148,8 +2150,9 @@ int cifs_getattr(const struct path *path, struct kstat *stat,
* We need to be sure that all dirty pages are written and the server * We need to be sure that all dirty pages are written and the server
* has actual ctime, mtime and file length. * has actual ctime, mtime and file length.
*/ */
if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping && if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_SIZE)) &&
inode->i_mapping->nrpages != 0) { !CIFS_CACHE_READ(CIFS_I(inode)) &&
inode->i_mapping && inode->i_mapping->nrpages != 0) {
rc = filemap_fdatawait(inode->i_mapping); rc = filemap_fdatawait(inode->i_mapping);
if (rc) { if (rc) {
mapping_set_error(inode->i_mapping, rc); mapping_set_error(inode->i_mapping, rc);
...@@ -2157,9 +2160,20 @@ int cifs_getattr(const struct path *path, struct kstat *stat, ...@@ -2157,9 +2160,20 @@ int cifs_getattr(const struct path *path, struct kstat *stat,
} }
} }
rc = cifs_revalidate_dentry_attr(dentry); if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_FORCE_SYNC)
if (rc) CIFS_I(inode)->time = 0; /* force revalidate */
return rc;
/*
* If the caller doesn't require syncing, only sync if
* necessary (e.g. due to earlier truncate or setattr
* invalidating the cached metadata)
*/
if (((flags & AT_STATX_SYNC_TYPE) != AT_STATX_DONT_SYNC) ||
(CIFS_I(inode)->time == 0)) {
rc = cifs_revalidate_dentry_attr(dentry);
if (rc)
return rc;
}
generic_fillattr(inode, stat); generic_fillattr(inode, stat);
stat->blksize = cifs_sb->bsize; stat->blksize = cifs_sb->bsize;
...@@ -2516,25 +2530,26 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) ...@@ -2516,25 +2530,26 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
/* /*
* Attempt to flush data before changing attributes. We need to do * Attempt to flush data before changing attributes. We need to do
* this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the * this for ATTR_SIZE and ATTR_MTIME. If the flush of the data
* ownership or mode then we may also need to do this. Here, we take * returns error, store it to report later and continue.
* the safe way out and just do the flush on all setattr requests. If
* the flush returns error, store it to report later and continue.
* *
* BB: This should be smarter. Why bother flushing pages that * BB: This should be smarter. Why bother flushing pages that
* will be truncated anyway? Also, should we error out here if * will be truncated anyway? Also, should we error out here if
* the flush returns error? * the flush returns error? Do we need to check for ATTR_MTIME_SET flag?
*/ */
rc = filemap_write_and_wait(inode->i_mapping); if (attrs->ia_valid & (ATTR_MTIME | ATTR_SIZE | ATTR_CTIME)) {
if (is_interrupt_error(rc)) { rc = filemap_write_and_wait(inode->i_mapping);
rc = -ERESTARTSYS; if (is_interrupt_error(rc)) {
goto cifs_setattr_exit; rc = -ERESTARTSYS;
goto cifs_setattr_exit;
}
mapping_set_error(inode->i_mapping, rc);
} }
mapping_set_error(inode->i_mapping, rc);
rc = 0; rc = 0;
if (attrs->ia_valid & ATTR_MTIME) { if ((attrs->ia_valid & ATTR_MTIME) &&
!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
rc = cifs_get_writable_file(cifsInode, FIND_WR_ANY, &wfile); rc = cifs_get_writable_file(cifsInode, FIND_WR_ANY, &wfile);
if (!rc) { if (!rc) {
tcon = tlink_tcon(wfile->tlink); tcon = tlink_tcon(wfile->tlink);
......
...@@ -416,7 +416,7 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, ...@@ -416,7 +416,7 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
} }
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL, rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL,
NULL); NULL, NULL);
if (rc) if (rc)
goto qmf_out_open_fail; goto qmf_out_open_fail;
...@@ -470,7 +470,7 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, ...@@ -470,7 +470,7 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
oparms.reconnect = false; oparms.reconnect = false;
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
NULL); NULL, NULL);
if (rc) { if (rc) {
kfree(utf16_path); kfree(utf16_path);
return rc; return rc;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "nterr.h" #include "nterr.h"
#include "cifs_unicode.h" #include "cifs_unicode.h"
#include "smb2pdu.h" #include "smb2pdu.h"
#include "cifsfs.h"
extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_req_poolp;
...@@ -1022,3 +1023,82 @@ int copy_path_name(char *dst, const char *src) ...@@ -1022,3 +1023,82 @@ int copy_path_name(char *dst, const char *src)
name_len++; name_len++;
return name_len; return name_len;
} }
struct super_cb_data {
struct TCP_Server_Info *server;
struct super_block *sb;
};
static void super_cb(struct super_block *sb, void *arg)
{
struct super_cb_data *d = arg;
struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon;
if (d->sb)
return;
cifs_sb = CIFS_SB(sb);
tcon = cifs_sb_master_tcon(cifs_sb);
if (tcon->ses->server == d->server)
d->sb = sb;
}
struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server)
{
struct super_cb_data d = {
.server = server,
.sb = NULL,
};
iterate_supers_type(&cifs_fs_type, super_cb, &d);
if (unlikely(!d.sb))
return ERR_PTR(-ENOENT);
/*
* Grab an active reference in order to prevent automounts (DFS links)
* of expiring and then freeing up our cifs superblock pointer while
* we're doing failover.
*/
cifs_sb_active(d.sb);
return d.sb;
}
void cifs_put_tcp_super(struct super_block *sb)
{
if (!IS_ERR_OR_NULL(sb))
cifs_sb_deactive(sb);
}
int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
size_t prefix_len)
{
struct super_block *sb;
struct cifs_sb_info *cifs_sb;
int rc = 0;
sb = cifs_get_tcp_super(tcon->ses->server);
if (IS_ERR(sb))
return PTR_ERR(sb);
cifs_sb = CIFS_SB(sb);
kfree(cifs_sb->prepath);
if (*prefix && prefix_len) {
cifs_sb->prepath = kstrndup(prefix, prefix_len, GFP_ATOMIC);
if (!cifs_sb->prepath) {
rc = -ENOMEM;
goto out;
}
convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
} else
cifs_sb->prepath = NULL;
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
out:
cifs_put_tcp_super(sb);
return rc;
}
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "cifs_debug.h" #include "cifs_debug.h"
#include "cifs_fs_sb.h" #include "cifs_fs_sb.h"
#include "cifsfs.h" #include "cifsfs.h"
#include "smb2proto.h"
/* /*
* To be safe - for UCS to UTF-8 with strings loaded with the rare long * To be safe - for UCS to UTF-8 with strings loaded with the rare long
...@@ -217,6 +218,60 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) ...@@ -217,6 +218,60 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
} }
} }
/* Fill a cifs_fattr struct with info from SMB_FIND_FILE_POSIX_INFO. */
static void
cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
struct cifs_sb_info *cifs_sb)
{
struct smb2_posix_info_parsed parsed;
posix_info_parse(info, NULL, &parsed);
memset(fattr, 0, sizeof(*fattr));
fattr->cf_uniqueid = le64_to_cpu(info->Inode);
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
fattr->cf_eof = le64_to_cpu(info->EndOfFile);
fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
fattr->cf_ctime = cifs_NTtimeToUnix(info->CreationTime);
fattr->cf_nlink = le32_to_cpu(info->HardLinks);
fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes);
/*
* Since we set the inode type below we need to mask off
* to avoid strange results if bits set above.
* XXX: why not make server&client use the type bits?
*/
fattr->cf_mode = le32_to_cpu(info->Mode) & ~S_IFMT;
cifs_dbg(VFS, "XXX dev %d, reparse %d, mode %o",
le32_to_cpu(info->DeviceId),
le32_to_cpu(info->ReparseTag),
le32_to_cpu(info->Mode));
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
fattr->cf_mode |= S_IFDIR;
fattr->cf_dtype = DT_DIR;
} else {
/*
* mark anything that is not a dir as regular
* file. special files should have the REPARSE
* attribute and will be marked as needing revaluation
*/
fattr->cf_mode |= S_IFREG;
fattr->cf_dtype = DT_REG;
}
if (reparse_file_needs_reval(fattr))
fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
/* TODO map SIDs */
fattr->cf_uid = cifs_sb->mnt_uid;
fattr->cf_gid = cifs_sb->mnt_gid;
}
static void __dir_info_to_fattr(struct cifs_fattr *fattr, const void *info) static void __dir_info_to_fattr(struct cifs_fattr *fattr, const void *info)
{ {
const FILE_DIRECTORY_INFO *fi = info; const FILE_DIRECTORY_INFO *fi = info;
...@@ -359,6 +414,8 @@ initiate_cifs_search(const unsigned int xid, struct file *file) ...@@ -359,6 +414,8 @@ initiate_cifs_search(const unsigned int xid, struct file *file)
/* if (cap_unix(tcon->ses) { */ /* if (cap_unix(tcon->ses) { */
if (tcon->unix_ext) if (tcon->unix_ext)
cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
else if (tcon->posix_extensions)
cifsFile->srch_inf.info_level = SMB_FIND_FILE_POSIX_INFO;
else if ((tcon->ses->capabilities & else if ((tcon->ses->capabilities &
tcon->ses->server->vals->cap_nt_find) == 0) { tcon->ses->server->vals->cap_nt_find) == 0) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD; cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
...@@ -451,6 +508,23 @@ struct cifs_dirent { ...@@ -451,6 +508,23 @@ struct cifs_dirent {
u64 ino; u64 ino;
}; };
static void cifs_fill_dirent_posix(struct cifs_dirent *de,
const struct smb2_posix_info *info)
{
struct smb2_posix_info_parsed parsed;
/* payload should have already been checked at this point */
if (posix_info_parse(info, NULL, &parsed) < 0) {
cifs_dbg(VFS, "invalid POSIX info payload");
return;
}
de->name = parsed.name;
de->namelen = parsed.name_len;
de->resume_key = info->Ignored;
de->ino = le64_to_cpu(info->Inode);
}
static void cifs_fill_dirent_unix(struct cifs_dirent *de, static void cifs_fill_dirent_unix(struct cifs_dirent *de,
const FILE_UNIX_INFO *info, bool is_unicode) const FILE_UNIX_INFO *info, bool is_unicode)
{ {
...@@ -511,6 +585,9 @@ static int cifs_fill_dirent(struct cifs_dirent *de, const void *info, ...@@ -511,6 +585,9 @@ static int cifs_fill_dirent(struct cifs_dirent *de, const void *info,
memset(de, 0, sizeof(*de)); memset(de, 0, sizeof(*de));
switch (level) { switch (level) {
case SMB_FIND_FILE_POSIX_INFO:
cifs_fill_dirent_posix(de, info);
break;
case SMB_FIND_FILE_UNIX: case SMB_FIND_FILE_UNIX:
cifs_fill_dirent_unix(de, info, is_unicode); cifs_fill_dirent_unix(de, info, is_unicode);
break; break;
...@@ -786,6 +863,11 @@ static int cifs_filldir(char *find_entry, struct file *file, ...@@ -786,6 +863,11 @@ static int cifs_filldir(char *find_entry, struct file *file,
} }
switch (file_info->srch_inf.info_level) { switch (file_info->srch_inf.info_level) {
case SMB_FIND_FILE_POSIX_INFO:
cifs_posix_to_fattr(&fattr,
(struct smb2_posix_info *)find_entry,
cifs_sb);
break;
case SMB_FIND_FILE_UNIX: case SMB_FIND_FILE_UNIX:
cifs_unix_basic_to_fattr(&fattr, cifs_unix_basic_to_fattr(&fattr,
&((FILE_UNIX_INFO *)find_entry)->basic, &((FILE_UNIX_INFO *)find_entry)->basic,
......
...@@ -62,7 +62,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, ...@@ -62,7 +62,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH; smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH;
rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL,
NULL); NULL, NULL);
if (rc) if (rc)
goto out; goto out;
...@@ -152,7 +152,12 @@ smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, ...@@ -152,7 +152,12 @@ smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
(li->offset + li->length)) (li->offset + li->length))
continue; continue;
if (current->tgid != li->pid) if (current->tgid != li->pid)
continue; /*
* flock and OFD lock are associated with an open
* file description, not the process.
*/
if (!(flock->fl_flags & (FL_FLOCK | FL_OFDLCK)))
continue;
if (cinode->can_cache_brlcks) { if (cinode->can_cache_brlcks) {
/* /*
* We can cache brlock requests - simply remove a lock * We can cache brlock requests - simply remove a lock
......
...@@ -328,16 +328,6 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) ...@@ -328,16 +328,6 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
/* start with specified wsize, or default */ /* start with specified wsize, or default */
wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE; wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE;
wsize = min_t(unsigned int, wsize, server->max_write); wsize = min_t(unsigned int, wsize, server->max_write);
#ifdef CONFIG_CIFS_SMB_DIRECT
if (server->rdma) {
if (server->sign)
wsize = min_t(unsigned int,
wsize, server->smbd_conn->max_fragmented_send_size);
else
wsize = min_t(unsigned int,
wsize, server->smbd_conn->max_readwrite_size);
}
#endif
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
...@@ -356,8 +346,15 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) ...@@ -356,8 +346,15 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
#ifdef CONFIG_CIFS_SMB_DIRECT #ifdef CONFIG_CIFS_SMB_DIRECT
if (server->rdma) { if (server->rdma) {
if (server->sign) if (server->sign)
/*
* Account for SMB2 data transfer packet header and
* possible encryption header
*/
wsize = min_t(unsigned int, wsize = min_t(unsigned int,
wsize, server->smbd_conn->max_fragmented_send_size); wsize,
server->smbd_conn->max_fragmented_send_size -
SMB2_READWRITE_PDU_HEADER_SIZE -
sizeof(struct smb2_transform_hdr));
else else
wsize = min_t(unsigned int, wsize = min_t(unsigned int,
wsize, server->smbd_conn->max_readwrite_size); wsize, server->smbd_conn->max_readwrite_size);
...@@ -378,16 +375,6 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) ...@@ -378,16 +375,6 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
/* start with specified rsize, or default */ /* start with specified rsize, or default */
rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE; rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
rsize = min_t(unsigned int, rsize, server->max_read); rsize = min_t(unsigned int, rsize, server->max_read);
#ifdef CONFIG_CIFS_SMB_DIRECT
if (server->rdma) {
if (server->sign)
rsize = min_t(unsigned int,
rsize, server->smbd_conn->max_fragmented_recv_size);
else
rsize = min_t(unsigned int,
rsize, server->smbd_conn->max_readwrite_size);
}
#endif
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE); rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
...@@ -407,8 +394,15 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) ...@@ -407,8 +394,15 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
#ifdef CONFIG_CIFS_SMB_DIRECT #ifdef CONFIG_CIFS_SMB_DIRECT
if (server->rdma) { if (server->rdma) {
if (server->sign) if (server->sign)
/*
* Account for SMB2 data transfer packet header and
* possible encryption header
*/
rsize = min_t(unsigned int, rsize = min_t(unsigned int,
rsize, server->smbd_conn->max_fragmented_recv_size); rsize,
server->smbd_conn->max_fragmented_recv_size -
SMB2_READWRITE_PDU_HEADER_SIZE -
sizeof(struct smb2_transform_hdr));
else else
rsize = min_t(unsigned int, rsize = min_t(unsigned int,
rsize, server->smbd_conn->max_readwrite_size); rsize, server->smbd_conn->max_readwrite_size);
...@@ -794,7 +788,8 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, ...@@ -794,7 +788,8 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon,
tcon->crfid.has_lease = true; tcon->crfid.has_lease = true;
smb2_parse_contexts(server, o_rsp, smb2_parse_contexts(server, o_rsp,
&oparms.fid->epoch, &oparms.fid->epoch,
oparms.fid->lease_key, &oplock, NULL); oparms.fid->lease_key, &oplock,
NULL, NULL);
} else } else
goto oshr_exit; goto oshr_exit;
...@@ -838,7 +833,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -838,7 +833,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon,
if (no_cached_open) if (no_cached_open)
rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL,
NULL); NULL, NULL);
else else
rc = open_shroot(xid, tcon, cifs_sb, &fid); rc = open_shroot(xid, tcon, cifs_sb, &fid);
...@@ -878,7 +873,8 @@ smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -878,7 +873,8 @@ smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon,
oparms.fid = &fid; oparms.fid = &fid;
oparms.reconnect = false; oparms.reconnect = false;
rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, NULL); rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL,
NULL, NULL);
if (rc) if (rc)
return; return;
...@@ -913,7 +909,8 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -913,7 +909,8 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
oparms.fid = &fid; oparms.fid = &fid;
oparms.reconnect = false; oparms.reconnect = false;
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL,
NULL);
if (rc) { if (rc) {
kfree(utf16_path); kfree(utf16_path);
return rc; return rc;
...@@ -2122,7 +2119,8 @@ smb3_notify(const unsigned int xid, struct file *pfile, ...@@ -2122,7 +2119,8 @@ smb3_notify(const unsigned int xid, struct file *pfile,
oparms.fid = &fid; oparms.fid = &fid;
oparms.reconnect = false; oparms.reconnect = false;
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL,
NULL);
if (rc) if (rc)
goto notify_exit; goto notify_exit;
...@@ -2543,7 +2541,8 @@ smb311_queryfs(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2543,7 +2541,8 @@ smb311_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
oparms.fid = &fid; oparms.fid = &fid;
oparms.reconnect = false; oparms.reconnect = false;
rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, NULL); rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL,
NULL, NULL);
if (rc) if (rc)
return rc; return rc;
...@@ -3028,7 +3027,8 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb, ...@@ -3028,7 +3027,8 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb,
oparms.fid = &fid; oparms.fid = &fid;
oparms.reconnect = false; oparms.reconnect = false;
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL,
NULL);
kfree(utf16_path); kfree(utf16_path);
if (!rc) { if (!rc) {
rc = SMB2_query_acl(xid, tlink_tcon(tlink), fid.persistent_fid, rc = SMB2_query_acl(xid, tlink_tcon(tlink), fid.persistent_fid,
...@@ -3086,7 +3086,8 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen, ...@@ -3086,7 +3086,8 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
oparms.fid = &fid; oparms.fid = &fid;
oparms.reconnect = false; oparms.reconnect = false;
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
NULL, NULL);
kfree(utf16_path); kfree(utf16_path);
if (!rc) { if (!rc) {
rc = SMB2_set_acl(xid, tlink_tcon(tlink), fid.persistent_fid, rc = SMB2_set_acl(xid, tlink_tcon(tlink), fid.persistent_fid,
...@@ -3248,6 +3249,10 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, ...@@ -3248,6 +3249,10 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
* Extending the file * Extending the file
*/ */
if ((keep_size == false) && i_size_read(inode) < off + len) { if ((keep_size == false) && i_size_read(inode) < off + len) {
rc = inode_newsize_ok(inode, off + len);
if (rc)
goto out;
if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) == 0) if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) == 0)
smb2_set_sparse(xid, tcon, cfile, inode, false); smb2_set_sparse(xid, tcon, cfile, inode, false);
...@@ -4151,7 +4156,6 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, ...@@ -4151,7 +4156,6 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
if (server->ops->is_session_expired && if (server->ops->is_session_expired &&
server->ops->is_session_expired(buf)) { server->ops->is_session_expired(buf)) {
cifs_reconnect(server); cifs_reconnect(server);
wake_up(&server->response_q);
return -1; return -1;
} }
...@@ -4515,14 +4519,12 @@ smb3_receive_transform(struct TCP_Server_Info *server, ...@@ -4515,14 +4519,12 @@ smb3_receive_transform(struct TCP_Server_Info *server,
cifs_server_dbg(VFS, "Transform message is too small (%u)\n", cifs_server_dbg(VFS, "Transform message is too small (%u)\n",
pdu_length); pdu_length);
cifs_reconnect(server); cifs_reconnect(server);
wake_up(&server->response_q);
return -ECONNABORTED; return -ECONNABORTED;
} }
if (pdu_length < orig_len + sizeof(struct smb2_transform_hdr)) { if (pdu_length < orig_len + sizeof(struct smb2_transform_hdr)) {
cifs_server_dbg(VFS, "Transform message is broken\n"); cifs_server_dbg(VFS, "Transform message is broken\n");
cifs_reconnect(server); cifs_reconnect(server);
wake_up(&server->response_q);
return -ECONNABORTED; return -ECONNABORTED;
} }
......
...@@ -193,9 +193,18 @@ static int __smb2_reconnect(const struct nls_table *nlsc, ...@@ -193,9 +193,18 @@ static int __smb2_reconnect(const struct nls_table *nlsc,
for (it = dfs_cache_get_tgt_iterator(&tl); it; for (it = dfs_cache_get_tgt_iterator(&tl); it;
it = dfs_cache_get_next_tgt(&tl, it)) { it = dfs_cache_get_next_tgt(&tl, it)) {
const char *tgt = dfs_cache_get_tgt_name(it); const char *share, *prefix;
size_t share_len, prefix_len;
extract_unc_hostname(tgt, &dfs_host, &dfs_host_len); rc = dfs_cache_get_tgt_share(it, &share, &share_len, &prefix,
&prefix_len);
if (rc) {
cifs_dbg(VFS, "%s: failed to parse target share %d\n",
__func__, rc);
continue;
}
extract_unc_hostname(share, &dfs_host, &dfs_host_len);
if (dfs_host_len != tcp_host_len if (dfs_host_len != tcp_host_len
|| strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) { || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
...@@ -206,11 +215,13 @@ static int __smb2_reconnect(const struct nls_table *nlsc, ...@@ -206,11 +215,13 @@ static int __smb2_reconnect(const struct nls_table *nlsc,
continue; continue;
} }
scnprintf(tree, MAX_TREE_SIZE, "\\%s", tgt); scnprintf(tree, MAX_TREE_SIZE, "\\%.*s", (int)share_len, share);
rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc); rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc);
if (!rc) if (!rc) {
rc = update_super_prepath(tcon, prefix, prefix_len);
break; break;
}
if (rc == -EREMOTE) if (rc == -EREMOTE)
break; break;
} }
...@@ -378,7 +389,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) ...@@ -378,7 +389,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
} }
if (smb2_command != SMB2_INTERNAL_CMD) if (smb2_command != SMB2_INTERNAL_CMD)
queue_delayed_work(cifsiod_wq, &server->reconnect, 0); mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
atomic_inc(&tconInfoReconnectCount); atomic_inc(&tconInfoReconnectCount);
out: out:
...@@ -1940,20 +1951,46 @@ parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *buf) ...@@ -1940,20 +1951,46 @@ parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *buf)
} }
static void static void
parse_posix_ctxt(struct create_context *cc, struct smb_posix_info *pposix_inf) parse_posix_ctxt(struct create_context *cc, struct smb2_file_all_info *info,
struct create_posix_rsp *posix)
{ {
/* struct smb_posix_info *ppinf = (struct smb_posix_info *)cc; */ int sid_len;
u8 *beg = (u8 *)cc + le16_to_cpu(cc->DataOffset);
u8 *end = beg + le32_to_cpu(cc->DataLength);
u8 *sid;
memset(posix, 0, sizeof(*posix));
posix->nlink = le32_to_cpu(*(__le32 *)(beg + 0));
posix->reparse_tag = le32_to_cpu(*(__le32 *)(beg + 4));
posix->mode = le32_to_cpu(*(__le32 *)(beg + 8));
/* TODO: Need to add parsing for the context and return */ sid = beg + 12;
printk_once(KERN_WARNING sid_len = posix_info_sid_size(sid, end);
"SMB3 3.11 POSIX response context not completed yet\n"); if (sid_len < 0) {
cifs_dbg(VFS, "bad owner sid in posix create response\n");
return;
}
memcpy(&posix->owner, sid, sid_len);
sid = sid + sid_len;
sid_len = posix_info_sid_size(sid, end);
if (sid_len < 0) {
cifs_dbg(VFS, "bad group sid in posix create response\n");
return;
}
memcpy(&posix->group, sid, sid_len);
cifs_dbg(FYI, "nlink=%d mode=%o reparse_tag=%x\n",
posix->nlink, posix->mode, posix->reparse_tag);
} }
void void
smb2_parse_contexts(struct TCP_Server_Info *server, smb2_parse_contexts(struct TCP_Server_Info *server,
struct smb2_create_rsp *rsp, struct smb2_create_rsp *rsp,
unsigned int *epoch, char *lease_key, __u8 *oplock, unsigned int *epoch, char *lease_key, __u8 *oplock,
struct smb2_file_all_info *buf) struct smb2_file_all_info *buf,
struct create_posix_rsp *posix)
{ {
char *data_offset; char *data_offset;
struct create_context *cc; struct create_context *cc;
...@@ -1983,8 +2020,9 @@ smb2_parse_contexts(struct TCP_Server_Info *server, ...@@ -1983,8 +2020,9 @@ smb2_parse_contexts(struct TCP_Server_Info *server,
strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4) == 0) strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4) == 0)
parse_query_id_ctxt(cc, buf); parse_query_id_ctxt(cc, buf);
else if ((le16_to_cpu(cc->NameLength) == 16)) { else if ((le16_to_cpu(cc->NameLength) == 16)) {
if (memcmp(name, smb3_create_tag_posix, 16) == 0) if (posix &&
parse_posix_ctxt(cc, NULL); memcmp(name, smb3_create_tag_posix, 16) == 0)
parse_posix_ctxt(cc, buf, posix);
} }
/* else { /* else {
cifs_dbg(FYI, "Context not matched with len %d\n", cifs_dbg(FYI, "Context not matched with len %d\n",
...@@ -2709,6 +2747,7 @@ SMB2_open_free(struct smb_rqst *rqst) ...@@ -2709,6 +2747,7 @@ SMB2_open_free(struct smb_rqst *rqst)
int int
SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
__u8 *oplock, struct smb2_file_all_info *buf, __u8 *oplock, struct smb2_file_all_info *buf,
struct create_posix_rsp *posix,
struct kvec *err_iov, int *buftype) struct kvec *err_iov, int *buftype)
{ {
struct smb_rqst rqst; struct smb_rqst rqst;
...@@ -2787,7 +2826,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, ...@@ -2787,7 +2826,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
smb2_parse_contexts(server, rsp, &oparms->fid->epoch, smb2_parse_contexts(server, rsp, &oparms->fid->epoch,
oparms->fid->lease_key, oplock, buf); oparms->fid->lease_key, oplock, buf, posix);
creat_exit: creat_exit:
SMB2_open_free(&rqst); SMB2_open_free(&rqst);
free_rsp_buf(resp_buftype, rsp); free_rsp_buf(resp_buftype, rsp);
...@@ -3559,7 +3598,7 @@ SMB2_echo(struct TCP_Server_Info *server) ...@@ -3559,7 +3598,7 @@ SMB2_echo(struct TCP_Server_Info *server)
if (server->tcpStatus == CifsNeedNegotiate) { if (server->tcpStatus == CifsNeedNegotiate) {
/* No need to send echo on newly established connections */ /* No need to send echo on newly established connections */
queue_delayed_work(cifsiod_wq, &server->reconnect, 0); mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
return rc; return rc;
} }
...@@ -4286,8 +4325,104 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, ...@@ -4286,8 +4325,104 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
return rc; return rc;
} }
int posix_info_sid_size(const void *beg, const void *end)
{
size_t subauth;
int total;
if (beg + 1 > end)
return -1;
subauth = *(u8 *)(beg+1);
if (subauth < 1 || subauth > 15)
return -1;
total = 1 + 1 + 6 + 4*subauth;
if (beg + total > end)
return -1;
return total;
}
int posix_info_parse(const void *beg, const void *end,
struct smb2_posix_info_parsed *out)
{
int total_len = 0;
int sid_len;
int name_len;
const void *owner_sid;
const void *group_sid;
const void *name;
/* if no end bound given, assume payload to be correct */
if (!end) {
const struct smb2_posix_info *p = beg;
end = beg + le32_to_cpu(p->NextEntryOffset);
/* last element will have a 0 offset, pick a sensible bound */
if (end == beg)
end += 0xFFFF;
}
/* check base buf */
if (beg + sizeof(struct smb2_posix_info) > end)
return -1;
total_len = sizeof(struct smb2_posix_info);
/* check owner sid */
owner_sid = beg + total_len;
sid_len = posix_info_sid_size(owner_sid, end);
if (sid_len < 0)
return -1;
total_len += sid_len;
/* check group sid */
group_sid = beg + total_len;
sid_len = posix_info_sid_size(group_sid, end);
if (sid_len < 0)
return -1;
total_len += sid_len;
/* check name len */
if (beg + total_len + 4 > end)
return -1;
name_len = le32_to_cpu(*(__le32 *)(beg + total_len));
if (name_len < 1 || name_len > 0xFFFF)
return -1;
total_len += 4;
/* check name */
name = beg + total_len;
if (name + name_len > end)
return -1;
total_len += name_len;
if (out) {
out->base = beg;
out->size = total_len;
out->name_len = name_len;
out->name = name;
memcpy(&out->owner, owner_sid,
posix_info_sid_size(owner_sid, end));
memcpy(&out->group, group_sid,
posix_info_sid_size(group_sid, end));
}
return total_len;
}
static int posix_info_extra_size(const void *beg, const void *end)
{
int len = posix_info_parse(beg, end, NULL);
if (len < 0)
return -1;
return len - sizeof(struct smb2_posix_info);
}
static unsigned int static unsigned int
num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size) num_entries(int infotype, char *bufstart, char *end_of_buf, char **lastentry,
size_t size)
{ {
int len; int len;
unsigned int entrycount = 0; unsigned int entrycount = 0;
...@@ -4311,8 +4446,13 @@ num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size) ...@@ -4311,8 +4446,13 @@ num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size)
entryptr = entryptr + next_offset; entryptr = entryptr + next_offset;
dir_info = (FILE_DIRECTORY_INFO *)entryptr; dir_info = (FILE_DIRECTORY_INFO *)entryptr;
len = le32_to_cpu(dir_info->FileNameLength); if (infotype == SMB_FIND_FILE_POSIX_INFO)
if (entryptr + len < entryptr || len = posix_info_extra_size(entryptr, end_of_buf);
else
len = le32_to_cpu(dir_info->FileNameLength);
if (len < 0 ||
entryptr + len < entryptr ||
entryptr + len > end_of_buf || entryptr + len > end_of_buf ||
entryptr + len + size > end_of_buf) { entryptr + len + size > end_of_buf) {
cifs_dbg(VFS, "directory entry name would overflow frame end of buf %p\n", cifs_dbg(VFS, "directory entry name would overflow frame end of buf %p\n",
...@@ -4362,6 +4502,9 @@ int SMB2_query_directory_init(const unsigned int xid, ...@@ -4362,6 +4502,9 @@ int SMB2_query_directory_init(const unsigned int xid,
case SMB_FIND_FILE_ID_FULL_DIR_INFO: case SMB_FIND_FILE_ID_FULL_DIR_INFO:
req->FileInformationClass = FILEID_FULL_DIRECTORY_INFORMATION; req->FileInformationClass = FILEID_FULL_DIRECTORY_INFORMATION;
break; break;
case SMB_FIND_FILE_POSIX_INFO:
req->FileInformationClass = SMB_FIND_FILE_POSIX_INFO;
break;
default: default:
cifs_tcon_dbg(VFS, "info level %u isn't supported\n", cifs_tcon_dbg(VFS, "info level %u isn't supported\n",
info_level); info_level);
...@@ -4427,6 +4570,10 @@ smb2_parse_query_directory(struct cifs_tcon *tcon, ...@@ -4427,6 +4570,10 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
case SMB_FIND_FILE_ID_FULL_DIR_INFO: case SMB_FIND_FILE_ID_FULL_DIR_INFO:
info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO) - 1; info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO) - 1;
break; break;
case SMB_FIND_FILE_POSIX_INFO:
/* note that posix payload are variable size */
info_buf_size = sizeof(struct smb2_posix_info);
break;
default: default:
cifs_tcon_dbg(VFS, "info level %u isn't supported\n", cifs_tcon_dbg(VFS, "info level %u isn't supported\n",
srch_inf->info_level); srch_inf->info_level);
...@@ -4436,8 +4583,10 @@ smb2_parse_query_directory(struct cifs_tcon *tcon, ...@@ -4436,8 +4583,10 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
le32_to_cpu(rsp->OutputBufferLength), rsp_iov, le32_to_cpu(rsp->OutputBufferLength), rsp_iov,
info_buf_size); info_buf_size);
if (rc) if (rc) {
cifs_tcon_dbg(VFS, "bad info payload");
return rc; return rc;
}
srch_inf->unicode = true; srch_inf->unicode = true;
...@@ -4451,9 +4600,14 @@ smb2_parse_query_directory(struct cifs_tcon *tcon, ...@@ -4451,9 +4600,14 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
srch_inf->srch_entries_start = srch_inf->last_entry = srch_inf->srch_entries_start = srch_inf->last_entry =
(char *)rsp + le16_to_cpu(rsp->OutputBufferOffset); (char *)rsp + le16_to_cpu(rsp->OutputBufferOffset);
end_of_smb = rsp_iov->iov_len + (char *)rsp; end_of_smb = rsp_iov->iov_len + (char *)rsp;
srch_inf->entries_in_buffer =
num_entries(srch_inf->srch_entries_start, end_of_smb, srch_inf->entries_in_buffer = num_entries(
&srch_inf->last_entry, info_buf_size); srch_inf->info_level,
srch_inf->srch_entries_start,
end_of_smb,
&srch_inf->last_entry,
info_buf_size);
srch_inf->index_of_last_entry += srch_inf->entries_in_buffer; srch_inf->index_of_last_entry += srch_inf->entries_in_buffer;
cifs_dbg(FYI, "num entries %d last_index %lld srch start %p srch end %p\n", cifs_dbg(FYI, "num entries %d last_index %lld srch start %p srch end %p\n",
srch_inf->entries_in_buffer, srch_inf->index_of_last_entry, srch_inf->entries_in_buffer, srch_inf->index_of_last_entry,
......
This diff is collapsed.
...@@ -139,6 +139,7 @@ extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon); ...@@ -139,6 +139,7 @@ extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);
extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms,
__le16 *path, __u8 *oplock, __le16 *path, __u8 *oplock,
struct smb2_file_all_info *buf, struct smb2_file_all_info *buf,
struct create_posix_rsp *posix,
struct kvec *err_iov, int *resp_buftype); struct kvec *err_iov, int *resp_buftype);
extern int SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, extern int SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
__u8 *oplock, struct cifs_open_parms *oparms, __u8 *oplock, struct cifs_open_parms *oparms,
...@@ -252,7 +253,8 @@ extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, ...@@ -252,7 +253,8 @@ extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
extern void smb2_parse_contexts(struct TCP_Server_Info *server, extern void smb2_parse_contexts(struct TCP_Server_Info *server,
struct smb2_create_rsp *rsp, struct smb2_create_rsp *rsp,
unsigned int *epoch, char *lease_key, unsigned int *epoch, char *lease_key,
__u8 *oplock, struct smb2_file_all_info *buf); __u8 *oplock, struct smb2_file_all_info *buf,
struct create_posix_rsp *posix);
extern int smb3_encryption_required(const struct cifs_tcon *tcon); extern int smb3_encryption_required(const struct cifs_tcon *tcon);
extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length, extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
struct kvec *iov, unsigned int min_buf_size); struct kvec *iov, unsigned int min_buf_size);
...@@ -272,4 +274,7 @@ extern int smb2_query_info_compound(const unsigned int xid, ...@@ -272,4 +274,7 @@ extern int smb2_query_info_compound(const unsigned int xid,
u32 class, u32 type, u32 output_len, u32 class, u32 type, u32 output_len,
struct kvec *rsp, int *buftype, struct kvec *rsp, int *buftype,
struct cifs_sb_info *cifs_sb); struct cifs_sb_info *cifs_sb);
int posix_info_parse(const void *beg, const void *end,
struct smb2_posix_info_parsed *out);
int posix_info_sid_size(const void *beg, const void *end);
#endif /* _SMB2PROTO_H */ #endif /* _SMB2PROTO_H */
...@@ -602,7 +602,7 @@ int ...@@ -602,7 +602,7 @@ int
smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
{ {
unsigned int rc; unsigned int rc;
char server_response_sig[16]; char server_response_sig[SMB2_SIGNATURE_SIZE];
struct smb2_sync_hdr *shdr = struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base;
...@@ -638,9 +638,11 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ...@@ -638,9 +638,11 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
if (rc) if (rc)
return rc; return rc;
if (memcmp(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE)) if (memcmp(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE)) {
dump_stack();
cifs_dbg(VFS, "sign fail cmd 0x%x message id 0x%llx\n", shdr->Command, shdr->MessageId);
return -EACCES; return -EACCES;
else } else
return 0; return 0;
} }
......
...@@ -459,25 +459,6 @@ static void smbd_post_send_credits(struct work_struct *work) ...@@ -459,25 +459,6 @@ static void smbd_post_send_credits(struct work_struct *work)
check_and_send_immediate(info); check_and_send_immediate(info);
} }
static void smbd_recv_done_work(struct work_struct *work)
{
struct smbd_connection *info =
container_of(work, struct smbd_connection, recv_done_work);
/*
* We may have new send credits granted from remote peer
* If any sender is blcoked on lack of credets, unblock it
*/
if (atomic_read(&info->send_credits))
wake_up_interruptible(&info->wait_send_queue);
/*
* Check if we need to send something to remote peer to
* grant more credits or respond to KEEP_ALIVE packet
*/
check_and_send_immediate(info);
}
/* Called from softirq, when recv is done */ /* Called from softirq, when recv is done */
static void recv_done(struct ib_cq *cq, struct ib_wc *wc) static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
{ {
...@@ -546,8 +527,15 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) ...@@ -546,8 +527,15 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
atomic_dec(&info->receive_credits); atomic_dec(&info->receive_credits);
info->receive_credit_target = info->receive_credit_target =
le16_to_cpu(data_transfer->credits_requested); le16_to_cpu(data_transfer->credits_requested);
atomic_add(le16_to_cpu(data_transfer->credits_granted), if (le16_to_cpu(data_transfer->credits_granted)) {
&info->send_credits); atomic_add(le16_to_cpu(data_transfer->credits_granted),
&info->send_credits);
/*
* We have new send credits granted from remote peer
* If any sender is waiting for credits, unblock it
*/
wake_up_interruptible(&info->wait_send_queue);
}
log_incoming(INFO, "data flags %d data_offset %d " log_incoming(INFO, "data flags %d data_offset %d "
"data_length %d remaining_data_length %d\n", "data_length %d remaining_data_length %d\n",
...@@ -563,7 +551,12 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) ...@@ -563,7 +551,12 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
info->keep_alive_requested = KEEP_ALIVE_PENDING; info->keep_alive_requested = KEEP_ALIVE_PENDING;
} }
queue_work(info->workqueue, &info->recv_done_work); /*
* Check if we need to send something to remote peer to
* grant more credits or respond to KEEP_ALIVE packet
*/
check_and_send_immediate(info);
return; return;
default: default:
...@@ -1762,7 +1755,6 @@ static struct smbd_connection *_smbd_get_connection( ...@@ -1762,7 +1755,6 @@ static struct smbd_connection *_smbd_get_connection(
atomic_set(&info->send_payload_pending, 0); atomic_set(&info->send_payload_pending, 0);
INIT_WORK(&info->disconnect_work, smbd_disconnect_rdma_work); INIT_WORK(&info->disconnect_work, smbd_disconnect_rdma_work);
INIT_WORK(&info->recv_done_work, smbd_recv_done_work);
INIT_WORK(&info->post_send_credits_work, smbd_post_send_credits); INIT_WORK(&info->post_send_credits_work, smbd_post_send_credits);
info->new_credits_offered = 0; info->new_credits_offered = 0;
spin_lock_init(&info->lock_new_credits_offered); spin_lock_init(&info->lock_new_credits_offered);
...@@ -2097,8 +2089,7 @@ int smbd_send(struct TCP_Server_Info *server, ...@@ -2097,8 +2089,7 @@ int smbd_send(struct TCP_Server_Info *server,
for (i = 0; i < num_rqst; i++) for (i = 0; i < num_rqst; i++)
remaining_data_length += smb_rqst_len(server, &rqst_array[i]); remaining_data_length += smb_rqst_len(server, &rqst_array[i]);
if (remaining_data_length + sizeof(struct smbd_data_transfer) > if (remaining_data_length > info->max_fragmented_send_size) {
info->max_fragmented_send_size) {
log_write(ERR, "payload size %d > max size %d\n", log_write(ERR, "payload size %d > max size %d\n",
remaining_data_length, info->max_fragmented_send_size); remaining_data_length, info->max_fragmented_send_size);
rc = -EINVAL; rc = -EINVAL;
......
...@@ -67,7 +67,6 @@ struct smbd_connection { ...@@ -67,7 +67,6 @@ struct smbd_connection {
bool negotiate_done; bool negotiate_done;
struct work_struct disconnect_work; struct work_struct disconnect_work;
struct work_struct recv_done_work;
struct work_struct post_send_credits_work; struct work_struct post_send_credits_work;
spinlock_t lock_new_credits_offered; spinlock_t lock_new_credits_offered;
......
...@@ -466,7 +466,7 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, ...@@ -466,7 +466,7 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
struct smb_rqst *rqst, int flags) struct smb_rqst *rqst, int flags)
{ {
struct kvec iov; struct kvec iov;
struct smb2_transform_hdr tr_hdr; struct smb2_transform_hdr *tr_hdr;
struct smb_rqst cur_rqst[MAX_COMPOUND]; struct smb_rqst cur_rqst[MAX_COMPOUND];
int rc; int rc;
...@@ -476,28 +476,34 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, ...@@ -476,28 +476,34 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
if (num_rqst > MAX_COMPOUND - 1) if (num_rqst > MAX_COMPOUND - 1)
return -ENOMEM; return -ENOMEM;
memset(&cur_rqst[0], 0, sizeof(cur_rqst));
memset(&iov, 0, sizeof(iov));
memset(&tr_hdr, 0, sizeof(tr_hdr));
iov.iov_base = &tr_hdr;
iov.iov_len = sizeof(tr_hdr);
cur_rqst[0].rq_iov = &iov;
cur_rqst[0].rq_nvec = 1;
if (!server->ops->init_transform_rq) { if (!server->ops->init_transform_rq) {
cifs_server_dbg(VFS, "Encryption requested but transform " cifs_server_dbg(VFS, "Encryption requested but transform "
"callback is missing\n"); "callback is missing\n");
return -EIO; return -EIO;
} }
tr_hdr = kmalloc(sizeof(*tr_hdr), GFP_NOFS);
if (!tr_hdr)
return -ENOMEM;
memset(&cur_rqst[0], 0, sizeof(cur_rqst));
memset(&iov, 0, sizeof(iov));
memset(tr_hdr, 0, sizeof(*tr_hdr));
iov.iov_base = tr_hdr;
iov.iov_len = sizeof(*tr_hdr);
cur_rqst[0].rq_iov = &iov;
cur_rqst[0].rq_nvec = 1;
rc = server->ops->init_transform_rq(server, num_rqst + 1, rc = server->ops->init_transform_rq(server, num_rqst + 1,
&cur_rqst[0], rqst); &cur_rqst[0], rqst);
if (rc) if (rc)
return rc; goto out;
rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]); rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]);
smb3_free_compound_rqst(num_rqst, &cur_rqst[1]); smb3_free_compound_rqst(num_rqst, &cur_rqst[1]);
out:
kfree(tr_hdr);
return rc; return rc;
} }
......
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