various RDMA (smbdirect) fixes, addition of SMB3.1.1 POSIX support in readdir, 3 fixes for stable, and a fix for flock
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAl6DXLwACgkQiiy9cAdy T1GqXQwAiJJpu3nBTtZeY9ZcybrpQnLve8H3Y/v/dmxJuu8hXcoEcpGPyzx+etlT 7X7pb1lwfw1n/1p2LGzRxigZUkG86QQ+Qe2D87elA2DtJ3zagIbQg/Jq/nrIK7/U DE+2IJUGh/Q8LS9gXwv95k4+P3iTM1GYoJHmDS+Hnp2EJ+PABBc55ZUe12+wpHYx EE58pkKe7uOc8+F+I8ySprJNgGsh4MT4hpWLIGXCDSROFBnYbBwN/xERKIJwh2zX y6WCWQb18FvoyxqHNTbVz+NayPslAu64GdY8L85Ke/eslguFDcklAb0BNhGe86bH 3l0rM4ghWkHLxG44lAA2QO2ljoUJKUH7/HzKEJ6camm0fg2EUDO04No+k0Mmj6Ye qCi1d7fSbSyPS0ctNICCZnjhCRwDtIiEvQ4hghh1m18ZNuipduSu2tMeRl60DnKp ToAJBTzZMuItRPxZcWQCsihpkzFvG3dCsSL2J2P9esiwp+fXC66difCND6mfBT05 FQedw4H0 =8fDc -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
645c248d6f
|
@ -342,7 +342,7 @@ static int
|
|||
sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
|
||||
struct cifs_fattr *fattr, uint sidtype)
|
||||
{
|
||||
int rc;
|
||||
int rc = 0;
|
||||
struct key *sidkey;
|
||||
char *sidstr;
|
||||
const struct cred *saved_cred;
|
||||
|
@ -450,11 +450,12 @@ out_revert_creds:
|
|||
* fails then we just fall back to using the mnt_uid/mnt_gid.
|
||||
*/
|
||||
got_valid_id:
|
||||
rc = 0;
|
||||
if (sidtype == SIDOWNER)
|
||||
fattr->cf_uid = fuid;
|
||||
else
|
||||
fattr->cf_gid = fgid;
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -1018,7 +1018,7 @@ struct file_system_type cifs_fs_type = {
|
|||
.name = "cifs",
|
||||
.mount = cifs_do_mount,
|
||||
.kill_sb = cifs_kill_sb,
|
||||
/* .fs_flags */
|
||||
.fs_flags = FS_RENAME_DOES_D_MOVE,
|
||||
};
|
||||
MODULE_ALIAS_FS("cifs");
|
||||
|
||||
|
@ -1027,7 +1027,7 @@ static struct file_system_type smb3_fs_type = {
|
|||
.name = "smb3",
|
||||
.mount = smb3_do_mount,
|
||||
.kill_sb = cifs_kill_sb,
|
||||
/* .fs_flags */
|
||||
.fs_flags = FS_RENAME_DOES_D_MOVE,
|
||||
};
|
||||
MODULE_ALIAS_FS("smb3");
|
||||
MODULE_ALIAS("smb3");
|
||||
|
|
|
@ -156,5 +156,5 @@ extern int cifs_truncate_page(struct address_space *mapping, loff_t from);
|
|||
extern const struct export_operations cifs_export_ops;
|
||||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||
|
||||
#define CIFS_VERSION "2.25"
|
||||
#define CIFS_VERSION "2.26"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
|
|
@ -1021,7 +1021,7 @@ typedef struct smb_com_writex_req {
|
|||
__le16 ByteCount;
|
||||
__u8 Pad; /* BB check for whether padded to DWORD
|
||||
boundary and optimum performance here */
|
||||
char Data[0];
|
||||
char Data[];
|
||||
} __attribute__((packed)) WRITEX_REQ;
|
||||
|
||||
typedef struct smb_com_write_req {
|
||||
|
@ -1041,7 +1041,7 @@ typedef struct smb_com_write_req {
|
|||
__le16 ByteCount;
|
||||
__u8 Pad; /* BB check for whether padded to DWORD
|
||||
boundary and optimum performance here */
|
||||
char Data[0];
|
||||
char Data[];
|
||||
} __attribute__((packed)) WRITE_REQ;
|
||||
|
||||
typedef struct smb_com_write_rsp {
|
||||
|
@ -1306,7 +1306,7 @@ typedef struct smb_com_ntransact_req {
|
|||
/* SetupCount words follow then */
|
||||
__le16 ByteCount;
|
||||
__u8 Pad[3];
|
||||
__u8 Parms[0];
|
||||
__u8 Parms[];
|
||||
} __attribute__((packed)) NTRANSACT_REQ;
|
||||
|
||||
typedef struct smb_com_ntransact_rsp {
|
||||
|
@ -1523,7 +1523,7 @@ struct file_notify_information {
|
|||
__le32 NextEntryOffset;
|
||||
__le32 Action;
|
||||
__le32 FileNameLength;
|
||||
__u8 FileName[0];
|
||||
__u8 FileName[];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* For IO_REPARSE_TAG_SYMLINK */
|
||||
|
@ -1536,7 +1536,7 @@ struct reparse_symlink_data {
|
|||
__le16 PrintNameOffset;
|
||||
__le16 PrintNameLength;
|
||||
__le32 Flags;
|
||||
char PathBuffer[0];
|
||||
char PathBuffer[];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Flag above */
|
||||
|
@ -1553,7 +1553,7 @@ struct reparse_posix_data {
|
|||
__le16 ReparseDataLength;
|
||||
__u16 Reserved;
|
||||
__le64 InodeType; /* LNK, FIFO, CHR etc. */
|
||||
char PathBuffer[0];
|
||||
char PathBuffer[];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct cifs_quota_data {
|
||||
|
@ -1691,6 +1691,7 @@ struct smb_t2_rsp {
|
|||
#define SMB_FIND_FILE_ID_FULL_DIR_INFO 0x105
|
||||
#define SMB_FIND_FILE_ID_BOTH_DIR_INFO 0x106
|
||||
#define SMB_FIND_FILE_UNIX 0x202
|
||||
#define SMB_FIND_FILE_POSIX_INFO 0x064
|
||||
|
||||
typedef struct smb_com_transaction2_qpi_req {
|
||||
struct smb_hdr hdr; /* wct = 14+ */
|
||||
|
@ -1761,7 +1762,7 @@ struct set_file_rename {
|
|||
__le32 overwrite; /* 1 = overwrite dest */
|
||||
__u32 root_fid; /* zero */
|
||||
__le32 target_name_len;
|
||||
char target_name[0]; /* Must be unicode */
|
||||
char target_name[]; /* Must be unicode */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct smb_com_transaction2_sfi_req {
|
||||
|
@ -2450,7 +2451,7 @@ struct cifs_posix_acl { /* access conrol list (ACL) */
|
|||
__le16 version;
|
||||
__le16 access_entry_count; /* access 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
|
||||
struct cifs_posix_ace default_ace_arraay[] */
|
||||
} __attribute__((packed)); /* level 0x204 */
|
||||
|
@ -2756,7 +2757,7 @@ typedef struct file_xattr_info {
|
|||
/* BB do we need another field for flags? BB */
|
||||
__u32 xattr_name_len;
|
||||
__u32 xattr_value_len;
|
||||
char xattr_name[0];
|
||||
char xattr_name[];
|
||||
/* followed by xattr_value[xattr_value_len], no pad */
|
||||
} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute info
|
||||
level 0x205 */
|
||||
|
|
|
@ -602,6 +602,11 @@ int smb2_parse_query_directory(struct cifs_tcon *tcon, struct kvec *rsp_iov,
|
|||
int resp_buftype,
|
||||
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
|
||||
static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
|
||||
const char *old_path,
|
||||
|
|
|
@ -162,9 +162,18 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc,
|
|||
|
||||
for (it = dfs_cache_get_tgt_iterator(&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
|
||||
|| strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
|
||||
|
@ -175,11 +184,13 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc,
|
|||
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);
|
||||
if (!rc)
|
||||
if (!rc) {
|
||||
rc = update_super_prepath(tcon, prefix, prefix_len);
|
||||
break;
|
||||
}
|
||||
if (rc == -EREMOTE)
|
||||
break;
|
||||
}
|
||||
|
@ -320,7 +331,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
|||
atomic_inc(&tconInfoReconnectCount);
|
||||
|
||||
/* tell server Unix caps we support */
|
||||
if (ses->capabilities & CAP_UNIX)
|
||||
if (cap_unix(ses))
|
||||
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)
|
|||
if (server->ops->is_session_expired &&
|
||||
server->ops->is_session_expired(buf)) {
|
||||
cifs_reconnect(server);
|
||||
wake_up(&server->response_q);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/fs.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/wait.h>
|
||||
|
@ -57,7 +58,6 @@
|
|||
#include "smb2proto.h"
|
||||
#include "smbdirect.h"
|
||||
#include "dns_resolve.h"
|
||||
#include "cifsfs.h"
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
#include "dfs_cache.h"
|
||||
#endif
|
||||
|
@ -389,54 +389,7 @@ static inline int reconn_set_ipaddr(struct TCP_Server_Info *server)
|
|||
#endif
|
||||
|
||||
#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 */
|
||||
|
||||
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,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
struct dfs_cache_tgt_list *tgt_list,
|
||||
|
@ -508,7 +461,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
|||
server->nr_targets = 1;
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
sb = get_tcp_super(server);
|
||||
sb = cifs_get_tcp_super(server);
|
||||
if (IS_ERR(sb)) {
|
||||
rc = PTR_ERR(sb);
|
||||
cifs_dbg(FYI, "%s: will not do DFS failover: rc = %d\n",
|
||||
|
@ -535,8 +488,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
|||
spin_unlock(&GlobalMid_Lock);
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
dfs_cache_free_tgts(&tgt_list);
|
||||
put_tcp_super(sb);
|
||||
cifs_put_tcp_super(sb);
|
||||
#endif
|
||||
wake_up(&server->response_q);
|
||||
return rc;
|
||||
} else
|
||||
server->tcpStatus = CifsNeedReconnect;
|
||||
|
@ -666,11 +620,12 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
|||
|
||||
}
|
||||
|
||||
put_tcp_super(sb);
|
||||
cifs_put_tcp_super(sb);
|
||||
#endif
|
||||
if (server->tcpStatus == CifsNeedNegotiate)
|
||||
mod_delayed_work(cifsiod_wq, &server->echo, 0);
|
||||
|
||||
wake_up(&server->response_q);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -765,7 +720,6 @@ server_unresponsive(struct TCP_Server_Info *server)
|
|||
cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n",
|
||||
(3 * server->echo_interval) / HZ);
|
||||
cifs_reconnect(server);
|
||||
wake_up(&server->response_q);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -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_reconnect(server);
|
||||
wake_up(&server->response_q);
|
||||
break;
|
||||
default:
|
||||
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)
|
|||
server->vals->header_preamble_size) {
|
||||
cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
|
||||
cifs_reconnect(server);
|
||||
wake_up(&server->response_q);
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
|
@ -1118,7 +1070,6 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
if (server->ops->is_session_expired &&
|
||||
server->ops->is_session_expired(buf)) {
|
||||
cifs_reconnect(server);
|
||||
wake_up(&server->response_q);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1164,8 +1115,9 @@ cifs_demultiplex_thread(void *p)
|
|||
struct task_struct *task_to_wake = NULL;
|
||||
struct mid_q_entry *mids[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));
|
||||
|
||||
length = atomic_inc_return(&tcpSesAllocCount);
|
||||
|
@ -1212,7 +1164,6 @@ next_pdu:
|
|||
cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n",
|
||||
server->pdu_size);
|
||||
cifs_reconnect(server);
|
||||
wake_up(&server->response_q);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1320,6 +1271,7 @@ next_pdu:
|
|||
set_current_state(TASK_RUNNING);
|
||||
}
|
||||
|
||||
memalloc_noreclaim_restore(noreclaim_flag);
|
||||
module_put_and_exit(0);
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
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->vals = &smb1_values;
|
||||
break;
|
||||
|
@ -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");
|
||||
|
||||
if (got_version == false)
|
||||
pr_warn("No dialect specified on mount. Default has changed to "
|
||||
"a more secure dialect, SMB2.1 or later (e.g. SMB3), from CIFS "
|
||||
"(SMB1). To use the less secure SMB1 dialect to access "
|
||||
"old servers which do not support SMB3 (or SMB2.1) specify vers=1.0"
|
||||
" on mount.\n");
|
||||
pr_warn_once("No dialect specified on mount. Default has changed"
|
||||
" to a more secure dialect, SMB2.1 or later (e.g. "
|
||||
"SMB3.1.1), from CIFS (SMB1). To use the less secure "
|
||||
"SMB1 dialect to access old servers which do not "
|
||||
"support SMB3.1.1 (or even SMB3 or SMB2.1) specify "
|
||||
"vers=1.0 on mount.\n");
|
||||
|
||||
kfree(mountdata_copy);
|
||||
return 0;
|
||||
|
@ -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).
|
||||
*/
|
||||
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:
|
||||
free_xid(xid);
|
||||
cifs_try_adding_channels(ses);
|
||||
|
|
|
@ -1260,6 +1260,44 @@ void dfs_cache_del_vol(const char *fullpath)
|
|||
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 */
|
||||
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,
|
|||
struct TCP_Server_Info *server);
|
||||
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 *
|
||||
dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl,
|
||||
struct dfs_cache_tgt_iterator *it)
|
||||
|
|
|
@ -3841,7 +3841,7 @@ again:
|
|||
if (rc == -ENODATA)
|
||||
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);
|
||||
|
||||
|
|
|
@ -1835,6 +1835,8 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
|
|||
CIFSSMBClose(xid, tcon, fid.netfid);
|
||||
}
|
||||
do_rename_exit:
|
||||
if (rc == 0)
|
||||
d_move(from_dentry, to_dentry);
|
||||
cifs_put_tlink(tlink);
|
||||
return rc;
|
||||
}
|
||||
|
@ -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
|
||||
* has actual ctime, mtime and file length.
|
||||
*/
|
||||
if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping &&
|
||||
inode->i_mapping->nrpages != 0) {
|
||||
if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_SIZE)) &&
|
||||
!CIFS_CACHE_READ(CIFS_I(inode)) &&
|
||||
inode->i_mapping && inode->i_mapping->nrpages != 0) {
|
||||
rc = filemap_fdatawait(inode->i_mapping);
|
||||
if (rc) {
|
||||
mapping_set_error(inode->i_mapping, rc);
|
||||
|
@ -2157,9 +2160,20 @@ int cifs_getattr(const struct path *path, struct kstat *stat,
|
|||
}
|
||||
}
|
||||
|
||||
rc = cifs_revalidate_dentry_attr(dentry);
|
||||
if (rc)
|
||||
return rc;
|
||||
if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_FORCE_SYNC)
|
||||
CIFS_I(inode)->time = 0; /* force revalidate */
|
||||
|
||||
/*
|
||||
* 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);
|
||||
stat->blksize = cifs_sb->bsize;
|
||||
|
@ -2516,25 +2530,26 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
|||
|
||||
/*
|
||||
* 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
|
||||
* ownership or mode then we may also need to do this. Here, we take
|
||||
* 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.
|
||||
* this for ATTR_SIZE and ATTR_MTIME. If the flush of the data
|
||||
* returns error, store it to report later and continue.
|
||||
*
|
||||
* BB: This should be smarter. Why bother flushing pages that
|
||||
* 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 (is_interrupt_error(rc)) {
|
||||
rc = -ERESTARTSYS;
|
||||
goto cifs_setattr_exit;
|
||||
if (attrs->ia_valid & (ATTR_MTIME | ATTR_SIZE | ATTR_CTIME)) {
|
||||
rc = filemap_write_and_wait(inode->i_mapping);
|
||||
if (is_interrupt_error(rc)) {
|
||||
rc = -ERESTARTSYS;
|
||||
goto cifs_setattr_exit;
|
||||
}
|
||||
mapping_set_error(inode->i_mapping, rc);
|
||||
}
|
||||
|
||||
mapping_set_error(inode->i_mapping, rc);
|
||||
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);
|
||||
if (!rc) {
|
||||
tcon = tlink_tcon(wfile->tlink);
|
||||
|
|
|
@ -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,
|
||||
NULL);
|
||||
NULL, NULL);
|
||||
if (rc)
|
||||
goto qmf_out_open_fail;
|
||||
|
||||
|
@ -470,7 +470,7 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
|
|||
oparms.reconnect = false;
|
||||
|
||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
|
||||
NULL);
|
||||
NULL, NULL);
|
||||
if (rc) {
|
||||
kfree(utf16_path);
|
||||
return rc;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "nterr.h"
|
||||
#include "cifs_unicode.h"
|
||||
#include "smb2pdu.h"
|
||||
#include "cifsfs.h"
|
||||
|
||||
extern mempool_t *cifs_sm_req_poolp;
|
||||
extern mempool_t *cifs_req_poolp;
|
||||
|
@ -1022,3 +1023,82 @@ int copy_path_name(char *dst, const char *src)
|
|||
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 @@
|
|||
#include "cifs_debug.h"
|
||||
#include "cifs_fs_sb.h"
|
||||
#include "cifsfs.h"
|
||||
#include "smb2proto.h"
|
||||
|
||||
/*
|
||||
* 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)
|
|||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
const FILE_DIRECTORY_INFO *fi = info;
|
||||
|
@ -359,6 +414,8 @@ ffirst_retry:
|
|||
/* if (cap_unix(tcon->ses) { */
|
||||
if (tcon->unix_ext)
|
||||
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 &
|
||||
tcon->ses->server->vals->cap_nt_find) == 0) {
|
||||
cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
|
||||
|
@ -451,6 +508,23 @@ struct cifs_dirent {
|
|||
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,
|
||||
const FILE_UNIX_INFO *info, bool is_unicode)
|
||||
{
|
||||
|
@ -511,6 +585,9 @@ static int cifs_fill_dirent(struct cifs_dirent *de, const void *info,
|
|||
memset(de, 0, sizeof(*de));
|
||||
|
||||
switch (level) {
|
||||
case SMB_FIND_FILE_POSIX_INFO:
|
||||
cifs_fill_dirent_posix(de, info);
|
||||
break;
|
||||
case SMB_FIND_FILE_UNIX:
|
||||
cifs_fill_dirent_unix(de, info, is_unicode);
|
||||
break;
|
||||
|
@ -786,6 +863,11 @@ static int cifs_filldir(char *find_entry, struct file *file,
|
|||
}
|
||||
|
||||
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:
|
||||
cifs_unix_basic_to_fattr(&fattr,
|
||||
&((FILE_UNIX_INFO *)find_entry)->basic,
|
||||
|
|
|
@ -62,7 +62,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
|
|||
smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH;
|
||||
|
||||
rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL,
|
||||
NULL);
|
||||
NULL, NULL);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
@ -152,7 +152,12 @@ smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
|
|||
(li->offset + li->length))
|
||||
continue;
|
||||
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) {
|
||||
/*
|
||||
* 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)
|
|||
/* start with specified wsize, or default */
|
||||
wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE;
|
||||
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))
|
||||
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)
|
|||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
if (server->rdma) {
|
||||
if (server->sign)
|
||||
/*
|
||||
* Account for SMB2 data transfer packet header and
|
||||
* possible encryption header
|
||||
*/
|
||||
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
|
||||
wsize = min_t(unsigned int,
|
||||
wsize, server->smbd_conn->max_readwrite_size);
|
||||
|
@ -378,16 +375,6 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
|
|||
/* start with specified rsize, or default */
|
||||
rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
|
||||
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))
|
||||
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)
|
|||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
if (server->rdma) {
|
||||
if (server->sign)
|
||||
/*
|
||||
* Account for SMB2 data transfer packet header and
|
||||
* possible encryption header
|
||||
*/
|
||||
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
|
||||
rsize = min_t(unsigned int,
|
||||
rsize, server->smbd_conn->max_readwrite_size);
|
||||
|
@ -794,7 +788,8 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon,
|
|||
tcon->crfid.has_lease = true;
|
||||
smb2_parse_contexts(server, o_rsp,
|
||||
&oparms.fid->epoch,
|
||||
oparms.fid->lease_key, &oplock, NULL);
|
||||
oparms.fid->lease_key, &oplock,
|
||||
NULL, NULL);
|
||||
} else
|
||||
goto oshr_exit;
|
||||
|
||||
|
@ -838,7 +833,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
if (no_cached_open)
|
||||
rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL,
|
||||
NULL);
|
||||
NULL, NULL);
|
||||
else
|
||||
rc = open_shroot(xid, tcon, cifs_sb, &fid);
|
||||
|
||||
|
@ -878,7 +873,8 @@ smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
oparms.fid = &fid;
|
||||
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)
|
||||
return;
|
||||
|
||||
|
@ -913,7 +909,8 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
oparms.fid = &fid;
|
||||
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) {
|
||||
kfree(utf16_path);
|
||||
return rc;
|
||||
|
@ -2122,7 +2119,8 @@ smb3_notify(const unsigned int xid, struct file *pfile,
|
|||
oparms.fid = &fid;
|
||||
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)
|
||||
goto notify_exit;
|
||||
|
||||
|
@ -2543,7 +2541,8 @@ smb311_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
oparms.fid = &fid;
|
||||
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)
|
||||
return rc;
|
||||
|
||||
|
@ -3028,7 +3027,8 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb,
|
|||
oparms.fid = &fid;
|
||||
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);
|
||||
if (!rc) {
|
||||
rc = SMB2_query_acl(xid, tlink_tcon(tlink), fid.persistent_fid,
|
||||
|
@ -3086,7 +3086,8 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
|||
oparms.fid = &fid;
|
||||
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);
|
||||
if (!rc) {
|
||||
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,
|
|||
* Extending the file
|
||||
*/
|
||||
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)
|
||||
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,
|
|||
if (server->ops->is_session_expired &&
|
||||
server->ops->is_session_expired(buf)) {
|
||||
cifs_reconnect(server);
|
||||
wake_up(&server->response_q);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -4515,14 +4519,12 @@ smb3_receive_transform(struct TCP_Server_Info *server,
|
|||
cifs_server_dbg(VFS, "Transform message is too small (%u)\n",
|
||||
pdu_length);
|
||||
cifs_reconnect(server);
|
||||
wake_up(&server->response_q);
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
if (pdu_length < orig_len + sizeof(struct smb2_transform_hdr)) {
|
||||
cifs_server_dbg(VFS, "Transform message is broken\n");
|
||||
cifs_reconnect(server);
|
||||
wake_up(&server->response_q);
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
|
|
|
@ -193,9 +193,18 @@ static int __smb2_reconnect(const struct nls_table *nlsc,
|
|||
|
||||
for (it = dfs_cache_get_tgt_iterator(&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
|
||||
|| strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
|
||||
|
@ -206,11 +215,13 @@ static int __smb2_reconnect(const struct nls_table *nlsc,
|
|||
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);
|
||||
if (!rc)
|
||||
if (!rc) {
|
||||
rc = update_super_prepath(tcon, prefix, prefix_len);
|
||||
break;
|
||||
}
|
||||
if (rc == -EREMOTE)
|
||||
break;
|
||||
}
|
||||
|
@ -378,7 +389,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
|
|||
}
|
||||
|
||||
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);
|
||||
out:
|
||||
|
@ -1940,20 +1951,46 @@ parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *buf)
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
/* TODO: Need to add parsing for the context and return */
|
||||
printk_once(KERN_WARNING
|
||||
"SMB3 3.11 POSIX response context not completed yet\n");
|
||||
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));
|
||||
|
||||
sid = beg + 12;
|
||||
sid_len = posix_info_sid_size(sid, end);
|
||||
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
|
||||
smb2_parse_contexts(struct TCP_Server_Info *server,
|
||||
struct smb2_create_rsp *rsp,
|
||||
unsigned int *epoch, char *lease_key, __u8 *oplock,
|
||||
struct smb2_file_all_info *buf)
|
||||
struct smb2_create_rsp *rsp,
|
||||
unsigned int *epoch, char *lease_key, __u8 *oplock,
|
||||
struct smb2_file_all_info *buf,
|
||||
struct create_posix_rsp *posix)
|
||||
{
|
||||
char *data_offset;
|
||||
struct create_context *cc;
|
||||
|
@ -1983,8 +2020,9 @@ smb2_parse_contexts(struct TCP_Server_Info *server,
|
|||
strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4) == 0)
|
||||
parse_query_id_ctxt(cc, buf);
|
||||
else if ((le16_to_cpu(cc->NameLength) == 16)) {
|
||||
if (memcmp(name, smb3_create_tag_posix, 16) == 0)
|
||||
parse_posix_ctxt(cc, NULL);
|
||||
if (posix &&
|
||||
memcmp(name, smb3_create_tag_posix, 16) == 0)
|
||||
parse_posix_ctxt(cc, buf, posix);
|
||||
}
|
||||
/* else {
|
||||
cifs_dbg(FYI, "Context not matched with len %d\n",
|
||||
|
@ -2709,6 +2747,7 @@ SMB2_open_free(struct smb_rqst *rqst)
|
|||
int
|
||||
SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
||||
__u8 *oplock, struct smb2_file_all_info *buf,
|
||||
struct create_posix_rsp *posix,
|
||||
struct kvec *err_iov, int *buftype)
|
||||
{
|
||||
struct smb_rqst rqst;
|
||||
|
@ -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,
|
||||
oparms->fid->lease_key, oplock, buf);
|
||||
oparms->fid->lease_key, oplock, buf, posix);
|
||||
creat_exit:
|
||||
SMB2_open_free(&rqst);
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
|
@ -3559,7 +3598,7 @@ SMB2_echo(struct TCP_Server_Info *server)
|
|||
|
||||
if (server->tcpStatus == CifsNeedNegotiate) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -4286,8 +4325,104 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
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
|
||||
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;
|
||||
unsigned int entrycount = 0;
|
||||
|
@ -4311,8 +4446,13 @@ num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size)
|
|||
entryptr = entryptr + next_offset;
|
||||
dir_info = (FILE_DIRECTORY_INFO *)entryptr;
|
||||
|
||||
len = le32_to_cpu(dir_info->FileNameLength);
|
||||
if (entryptr + len < entryptr ||
|
||||
if (infotype == SMB_FIND_FILE_POSIX_INFO)
|
||||
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 + size > end_of_buf) {
|
||||
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,
|
|||
case SMB_FIND_FILE_ID_FULL_DIR_INFO:
|
||||
req->FileInformationClass = FILEID_FULL_DIRECTORY_INFORMATION;
|
||||
break;
|
||||
case SMB_FIND_FILE_POSIX_INFO:
|
||||
req->FileInformationClass = SMB_FIND_FILE_POSIX_INFO;
|
||||
break;
|
||||
default:
|
||||
cifs_tcon_dbg(VFS, "info level %u isn't supported\n",
|
||||
info_level);
|
||||
|
@ -4427,6 +4570,10 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
|
|||
case SMB_FIND_FILE_ID_FULL_DIR_INFO:
|
||||
info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO) - 1;
|
||||
break;
|
||||
case SMB_FIND_FILE_POSIX_INFO:
|
||||
/* note that posix payload are variable size */
|
||||
info_buf_size = sizeof(struct smb2_posix_info);
|
||||
break;
|
||||
default:
|
||||
cifs_tcon_dbg(VFS, "info level %u isn't supported\n",
|
||||
srch_inf->info_level);
|
||||
|
@ -4436,8 +4583,10 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
|
|||
rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength), rsp_iov,
|
||||
info_buf_size);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
cifs_tcon_dbg(VFS, "bad info payload");
|
||||
return rc;
|
||||
}
|
||||
|
||||
srch_inf->unicode = true;
|
||||
|
||||
|
@ -4451,9 +4600,14 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
|
|||
srch_inf->srch_entries_start = srch_inf->last_entry =
|
||||
(char *)rsp + le16_to_cpu(rsp->OutputBufferOffset);
|
||||
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->last_entry, info_buf_size);
|
||||
|
||||
srch_inf->entries_in_buffer = num_entries(
|
||||
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;
|
||||
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,
|
||||
|
|
|
@ -91,6 +91,7 @@
|
|||
|
||||
#define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe)
|
||||
#define SMB2_TRANSFORM_PROTO_NUM cpu_to_le32(0x424d53fd)
|
||||
#define SMB2_COMPRESSION_TRANSFORM_ID cpu_to_le32(0x424d53fc)
|
||||
|
||||
/*
|
||||
* SMB2 Header Definition
|
||||
|
@ -119,6 +120,9 @@ struct smb2_sync_hdr {
|
|||
__u8 Signature[16];
|
||||
} __packed;
|
||||
|
||||
/* The total header size for SMB2 read and write */
|
||||
#define SMB2_READWRITE_PDU_HEADER_SIZE (48 + sizeof(struct smb2_sync_hdr))
|
||||
|
||||
struct smb2_sync_pdu {
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize2; /* size of wct area (varies, request specific) */
|
||||
|
@ -127,16 +131,33 @@ struct smb2_sync_pdu {
|
|||
#define SMB3_AES128CCM_NONCE 11
|
||||
#define SMB3_AES128GCM_NONCE 12
|
||||
|
||||
/* Transform flags (for 3.0 dialect this flag indicates CCM */
|
||||
#define TRANSFORM_FLAG_ENCRYPTED 0x0001
|
||||
struct smb2_transform_hdr {
|
||||
__le32 ProtocolId; /* 0xFD 'S' 'M' 'B' */
|
||||
__u8 Signature[16];
|
||||
__u8 Nonce[16];
|
||||
__le32 OriginalMessageSize;
|
||||
__u16 Reserved1;
|
||||
__le16 Flags; /* EncryptionAlgorithm */
|
||||
__le16 Flags; /* EncryptionAlgorithm for 3.0, enc enabled for 3.1.1 */
|
||||
__u64 SessionId;
|
||||
} __packed;
|
||||
|
||||
/* See MS-SMB2 2.2.42.1 */
|
||||
struct compression_playload_header {
|
||||
__le16 AlgorithmId;
|
||||
__le16 Reserved;
|
||||
__le32 Length;
|
||||
} __packed;
|
||||
|
||||
/* See MS-SMB2 2.2.42.2 */
|
||||
struct compression_pattern_payload_v1 {
|
||||
__le16 Pattern;
|
||||
__le16 Reserved1;
|
||||
__le16 Reserved2;
|
||||
__le32 Repetitions;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* SMB2 flag definitions
|
||||
*/
|
||||
|
@ -182,7 +203,7 @@ struct smb2_symlink_err_rsp {
|
|||
__le16 PrintNameOffset;
|
||||
__le16 PrintNameLength;
|
||||
__le32 Flags;
|
||||
__u8 PathBuffer[0];
|
||||
__u8 PathBuffer[];
|
||||
} __packed;
|
||||
|
||||
/* SMB 3.1.1 and later dialects. See MS-SMB2 section 2.2.2.1 */
|
||||
|
@ -192,6 +213,10 @@ struct smb2_error_context_rsp {
|
|||
__u8 ErrorContextData; /* ErrorDataLength long array */
|
||||
} __packed;
|
||||
|
||||
/* ErrorId values */
|
||||
#define SMB2_ERROR_ID_DEFAULT 0x00000000
|
||||
#define SMB2_ERROR_ID_SHARE_REDIRECT cpu_to_le32(0x72645253) /* "rdRS" */
|
||||
|
||||
/* Defines for Type field below (see MS-SMB2 2.2.2.2.2.1) */
|
||||
#define MOVE_DST_IPADDR_V4 cpu_to_le32(0x00000001)
|
||||
#define MOVE_DST_IPADDR_V6 cpu_to_le32(0x00000002)
|
||||
|
@ -210,7 +235,7 @@ struct share_redirect_error_context_rsp {
|
|||
__le16 Flags;
|
||||
__le16 TargetType;
|
||||
__le32 IPAddrCount;
|
||||
struct move_dst_ipaddr IpAddrMoveList[0];
|
||||
struct move_dst_ipaddr IpAddrMoveList[];
|
||||
/* __u8 ResourceName[] */ /* Name of share as counted Unicode string */
|
||||
} __packed;
|
||||
|
||||
|
@ -307,11 +332,17 @@ struct smb2_encryption_neg_context {
|
|||
#define SMB3_COMPRESS_LZNT1 cpu_to_le16(0x0001)
|
||||
#define SMB3_COMPRESS_LZ77 cpu_to_le16(0x0002)
|
||||
#define SMB3_COMPRESS_LZ77_HUFF cpu_to_le16(0x0003)
|
||||
/* Pattern scanning algorithm See MS-SMB2 3.1.4.4.1 */
|
||||
#define SMB3_COMPRESS_PATTERN cpu_to_le16(0x0004)
|
||||
|
||||
/* Compression Flags */
|
||||
#define SMB2_COMPRESSION_CAPABILITIES_FLAG_NONE cpu_to_le32(0x00000000)
|
||||
#define SMB2_COMPRESSION_CAPABILITIES_FLAG_CHAINED cpu_to_le32(0x00000001)
|
||||
|
||||
struct smb2_compression_capabilities_context {
|
||||
__le16 ContextType; /* 3 */
|
||||
__le16 DataLength;
|
||||
__u32 Reserved;
|
||||
__u32 Flags;
|
||||
__le16 CompressionAlgorithmCount;
|
||||
__u16 Padding;
|
||||
__u32 Reserved1;
|
||||
|
@ -326,7 +357,7 @@ struct smb2_netname_neg_context {
|
|||
__le16 ContextType; /* 0x100 */
|
||||
__le16 DataLength;
|
||||
__le32 Reserved;
|
||||
__le16 NetName[0]; /* hostname of target converted to UCS-2 */
|
||||
__le16 NetName[]; /* hostname of target converted to UCS-2 */
|
||||
} __packed;
|
||||
|
||||
#define POSIX_CTXT_DATA_LEN 16
|
||||
|
@ -406,7 +437,7 @@ struct smb2_logoff_rsp {
|
|||
struct smb2_tree_connect_req {
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 9 */
|
||||
__le16 Reserved; /* Flags in SMB3.1.1 */
|
||||
__le16 Flags; /* Reserved MBZ for dialects prior to SMB3.1.1 */
|
||||
__le16 PathOffset;
|
||||
__le16 PathLength;
|
||||
__u8 Buffer[1]; /* variable length */
|
||||
|
@ -421,13 +452,13 @@ struct tree_connect_contexts {
|
|||
__le16 ContextType;
|
||||
__le16 DataLength;
|
||||
__le32 Reserved;
|
||||
__u8 Data[0];
|
||||
__u8 Data[];
|
||||
} __packed;
|
||||
|
||||
/* Remoted identity tree connect context structures - see MS-SMB2 2.2.9.2.1 */
|
||||
struct smb3_blob_data {
|
||||
__le16 BlobSize;
|
||||
__u8 BlobData[0];
|
||||
__u8 BlobData[];
|
||||
} __packed;
|
||||
|
||||
/* Valid values for Attr */
|
||||
|
@ -477,14 +508,14 @@ struct remoted_identity_tcon_context {
|
|||
__le16 DeviceGroups; /* offset to SID_ARRAY_DATA struct */
|
||||
__le16 UserClaims; /* offset to BLOB_DATA struct */
|
||||
__le16 DeviceClaims; /* offset to BLOB_DATA struct */
|
||||
__u8 TicketInfo[0]; /* variable length buf - remoted identity data */
|
||||
__u8 TicketInfo[]; /* variable length buf - remoted identity data */
|
||||
} __packed;
|
||||
|
||||
struct smb2_tree_connect_req_extension {
|
||||
__le32 TreeConnectContextOffset;
|
||||
__le16 TreeConnectContextCount;
|
||||
__u8 Reserved[10];
|
||||
__u8 PathName[0]; /* variable sized array */
|
||||
__u8 PathName[]; /* variable sized array */
|
||||
/* followed by array of TreeConnectContexts */
|
||||
} __packed;
|
||||
|
||||
|
@ -633,7 +664,7 @@ struct smb2_tree_disconnect_rsp {
|
|||
| FILE_WRITE_EA_LE | FILE_WRITE_ATTRIBUTES_LE)
|
||||
#define FILE_EXEC_RIGHTS_LE (FILE_EXECUTE_LE)
|
||||
|
||||
/* Impersonation Levels */
|
||||
/* Impersonation Levels. See MS-WPO section 9.7 and MSDN-IMPERS */
|
||||
#define IL_ANONYMOUS cpu_to_le32(0x00000000)
|
||||
#define IL_IDENTIFICATION cpu_to_le32(0x00000001)
|
||||
#define IL_IMPERSONATION cpu_to_le32(0x00000002)
|
||||
|
@ -689,7 +720,7 @@ struct smb2_create_req {
|
|||
__le16 NameLength;
|
||||
__le32 CreateContextsOffset;
|
||||
__le32 CreateContextsLength;
|
||||
__u8 Buffer[0];
|
||||
__u8 Buffer[];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
|
@ -727,7 +758,7 @@ struct create_context {
|
|||
__le16 Reserved;
|
||||
__le16 DataOffset;
|
||||
__le32 DataLength;
|
||||
__u8 Buffer[0];
|
||||
__u8 Buffer[];
|
||||
} __packed;
|
||||
|
||||
#define SMB2_LEASE_READ_CACHING_HE 0x01
|
||||
|
@ -739,7 +770,7 @@ struct create_context {
|
|||
#define SMB2_LEASE_HANDLE_CACHING cpu_to_le32(0x02)
|
||||
#define SMB2_LEASE_WRITE_CACHING cpu_to_le32(0x04)
|
||||
|
||||
#define SMB2_LEASE_FLAG_BREAK_IN_PROGRESS cpu_to_le32(0x02)
|
||||
#define SMB2_LEASE_FLAG_BREAK_IN_PROGRESS cpu_to_le32(0x00000002)
|
||||
#define SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET cpu_to_le32(0x00000004)
|
||||
|
||||
#define SMB2_LEASE_KEY_SIZE 16
|
||||
|
@ -869,7 +900,7 @@ struct crt_sd_ctxt {
|
|||
struct resume_key_req {
|
||||
char ResumeKey[COPY_CHUNK_RES_KEY_SIZE];
|
||||
__le32 ContextLength; /* MBZ */
|
||||
char Context[0]; /* ignored, Windows sets to 4 bytes of zero */
|
||||
char Context[]; /* ignored, Windows sets to 4 bytes of zero */
|
||||
} __packed;
|
||||
|
||||
/* this goes in the ioctl buffer when doing a copychunk request */
|
||||
|
@ -931,7 +962,7 @@ struct reparse_data_buffer {
|
|||
__le32 ReparseTag;
|
||||
__le16 ReparseDataLength;
|
||||
__u16 Reserved;
|
||||
__u8 DataBuffer[0]; /* Variable Length */
|
||||
__u8 DataBuffer[]; /* Variable Length */
|
||||
} __packed;
|
||||
|
||||
struct reparse_guid_data_buffer {
|
||||
|
@ -939,7 +970,7 @@ struct reparse_guid_data_buffer {
|
|||
__le16 ReparseDataLength;
|
||||
__u16 Reserved;
|
||||
__u8 ReparseGuid[16];
|
||||
__u8 DataBuffer[0]; /* Variable Length */
|
||||
__u8 DataBuffer[]; /* Variable Length */
|
||||
} __packed;
|
||||
|
||||
struct reparse_mount_point_data_buffer {
|
||||
|
@ -950,7 +981,7 @@ struct reparse_mount_point_data_buffer {
|
|||
__le16 SubstituteNameLength;
|
||||
__le16 PrintNameOffset;
|
||||
__le16 PrintNameLength;
|
||||
__u8 PathBuffer[0]; /* Variable Length */
|
||||
__u8 PathBuffer[]; /* Variable Length */
|
||||
} __packed;
|
||||
|
||||
#define SYMLINK_FLAG_RELATIVE 0x00000001
|
||||
|
@ -964,7 +995,7 @@ struct reparse_symlink_data_buffer {
|
|||
__le16 PrintNameOffset;
|
||||
__le16 PrintNameLength;
|
||||
__le32 Flags;
|
||||
__u8 PathBuffer[0]; /* Variable Length */
|
||||
__u8 PathBuffer[]; /* Variable Length */
|
||||
} __packed;
|
||||
|
||||
/* See MS-FSCC 2.1.2.6 and cifspdu.h for struct reparse_posix_data */
|
||||
|
@ -1066,7 +1097,7 @@ struct smb2_ioctl_req {
|
|||
__le32 MaxOutputResponse;
|
||||
__le32 Flags;
|
||||
__u32 Reserved2;
|
||||
__u8 Buffer[0];
|
||||
__u8 Buffer[];
|
||||
} __packed;
|
||||
|
||||
struct smb2_ioctl_rsp {
|
||||
|
@ -1180,7 +1211,7 @@ struct smb2_write_req {
|
|||
__le64 Offset;
|
||||
__u64 PersistentFileId; /* opaque endianness */
|
||||
__u64 VolatileFileId; /* opaque endianness */
|
||||
__le32 Channel; /* Reserved MBZ */
|
||||
__le32 Channel; /* MBZ unless SMB3.02 or later */
|
||||
__le32 RemainingBytes;
|
||||
__le16 WriteChannelInfoOffset;
|
||||
__le16 WriteChannelInfoLength;
|
||||
|
@ -1469,7 +1500,7 @@ struct smb3_fs_vol_info {
|
|||
__le32 VolumeLabelLength; /* includes trailing null */
|
||||
__u8 SupportsObjects; /* True if eg like NTFS, supports objects */
|
||||
__u8 Reserved;
|
||||
__u8 VolumeLabel[0]; /* variable len */
|
||||
__u8 VolumeLabel[]; /* variable len */
|
||||
} __packed;
|
||||
|
||||
/* partial list of QUERY INFO levels */
|
||||
|
@ -1531,7 +1562,7 @@ struct smb2_file_rename_info { /* encoding of request for level 10 */
|
|||
__u8 Reserved[7];
|
||||
__u64 RootDirectory; /* MBZ for network operations (why says spec?) */
|
||||
__le32 FileNameLength;
|
||||
char FileName[0]; /* New name to be assigned */
|
||||
char FileName[]; /* New name to be assigned */
|
||||
} __packed; /* level 10 Set */
|
||||
|
||||
struct smb2_file_link_info { /* encoding of request for level 11 */
|
||||
|
@ -1540,7 +1571,7 @@ struct smb2_file_link_info { /* encoding of request for level 11 */
|
|||
__u8 Reserved[7];
|
||||
__u64 RootDirectory; /* MBZ for network operations (why says spec?) */
|
||||
__le32 FileNameLength;
|
||||
char FileName[0]; /* Name to be assigned to new link */
|
||||
char FileName[]; /* Name to be assigned to new link */
|
||||
} __packed; /* level 11 Set */
|
||||
|
||||
struct smb2_file_full_ea_info { /* encoding of response for level 15 */
|
||||
|
@ -1548,7 +1579,7 @@ struct smb2_file_full_ea_info { /* encoding of response for level 15 */
|
|||
__u8 flags;
|
||||
__u8 ea_name_length;
|
||||
__le16 ea_value_length;
|
||||
char ea_data[0]; /* \0 terminated name plus value */
|
||||
char ea_data[]; /* \0 terminated name plus value */
|
||||
} __packed; /* level 15 Set */
|
||||
|
||||
/*
|
||||
|
@ -1604,11 +1635,56 @@ struct smb2_file_id_information {
|
|||
extern char smb2_padding[7];
|
||||
|
||||
/* equivalent of the contents of SMB3.1.1 POSIX open context response */
|
||||
struct smb_posix_info {
|
||||
__le32 nlink;
|
||||
__le32 reparse_tag;
|
||||
__le32 mode;
|
||||
kuid_t uid;
|
||||
kuid_t gid;
|
||||
struct create_posix_rsp {
|
||||
u32 nlink;
|
||||
u32 reparse_tag;
|
||||
u32 mode;
|
||||
struct cifs_sid owner; /* var-sized on the wire */
|
||||
struct cifs_sid group; /* var-sized on the wire */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* SMB2-only POSIX info level
|
||||
*
|
||||
* See posix_info_sid_size(), posix_info_extra_size() and
|
||||
* posix_info_parse() to help with the handling of this struct.
|
||||
*/
|
||||
struct smb2_posix_info {
|
||||
__le32 NextEntryOffset;
|
||||
__u32 Ignored;
|
||||
__le64 CreationTime;
|
||||
__le64 LastAccessTime;
|
||||
__le64 LastWriteTime;
|
||||
__le64 ChangeTime;
|
||||
__le64 EndOfFile;
|
||||
__le64 AllocationSize;
|
||||
__le32 DosAttributes;
|
||||
__le64 Inode;
|
||||
__le32 DeviceId;
|
||||
__le32 Zero;
|
||||
/* beginning of POSIX Create Context Response */
|
||||
__le32 HardLinks;
|
||||
__le32 ReparseTag;
|
||||
__le32 Mode;
|
||||
/*
|
||||
* var sized owner SID
|
||||
* var sized group SID
|
||||
* le32 filenamelength
|
||||
* u8 filename[]
|
||||
*/
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Parsed version of the above struct. Allows direct access to the
|
||||
* variable length fields
|
||||
*/
|
||||
struct smb2_posix_info_parsed {
|
||||
const struct smb2_posix_info *base;
|
||||
size_t size;
|
||||
struct cifs_sid owner;
|
||||
struct cifs_sid group;
|
||||
int name_len;
|
||||
const u8 *name;
|
||||
};
|
||||
|
||||
#endif /* _SMB2PDU_H */
|
||||
|
|
|
@ -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,
|
||||
__le16 *path, __u8 *oplock,
|
||||
struct smb2_file_all_info *buf,
|
||||
struct create_posix_rsp *posix,
|
||||
struct kvec *err_iov, int *resp_buftype);
|
||||
extern int SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
|
||||
__u8 *oplock, struct cifs_open_parms *oparms,
|
||||
|
@ -252,7 +253,8 @@ extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
|
|||
extern void smb2_parse_contexts(struct TCP_Server_Info *server,
|
||||
struct smb2_create_rsp *rsp,
|
||||
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 smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
|
||||
struct kvec *iov, unsigned int min_buf_size);
|
||||
|
@ -272,4 +274,7 @@ extern int smb2_query_info_compound(const unsigned int xid,
|
|||
u32 class, u32 type, u32 output_len,
|
||||
struct kvec *rsp, int *buftype,
|
||||
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 */
|
||||
|
|
|
@ -602,7 +602,7 @@ int
|
|||
smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
||||
{
|
||||
unsigned int rc;
|
||||
char server_response_sig[16];
|
||||
char server_response_sig[SMB2_SIGNATURE_SIZE];
|
||||
struct smb2_sync_hdr *shdr =
|
||||
(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)
|
|||
if (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;
|
||||
else
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -459,25 +459,6 @@ static void smbd_post_send_credits(struct work_struct *work)
|
|||
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 */
|
||||
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);
|
||||
info->receive_credit_target =
|
||||
le16_to_cpu(data_transfer->credits_requested);
|
||||
atomic_add(le16_to_cpu(data_transfer->credits_granted),
|
||||
&info->send_credits);
|
||||
if (le16_to_cpu(data_transfer->credits_granted)) {
|
||||
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 "
|
||||
"data_length %d remaining_data_length %d\n",
|
||||
|
@ -563,7 +551,12 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
|
|||
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;
|
||||
|
||||
default:
|
||||
|
@ -1762,7 +1755,6 @@ static struct smbd_connection *_smbd_get_connection(
|
|||
atomic_set(&info->send_payload_pending, 0);
|
||||
|
||||
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);
|
||||
info->new_credits_offered = 0;
|
||||
spin_lock_init(&info->lock_new_credits_offered);
|
||||
|
@ -2097,8 +2089,7 @@ int smbd_send(struct TCP_Server_Info *server,
|
|||
for (i = 0; i < num_rqst; i++)
|
||||
remaining_data_length += smb_rqst_len(server, &rqst_array[i]);
|
||||
|
||||
if (remaining_data_length + sizeof(struct smbd_data_transfer) >
|
||||
info->max_fragmented_send_size) {
|
||||
if (remaining_data_length > info->max_fragmented_send_size) {
|
||||
log_write(ERR, "payload size %d > max size %d\n",
|
||||
remaining_data_length, info->max_fragmented_send_size);
|
||||
rc = -EINVAL;
|
||||
|
|
|
@ -67,7 +67,6 @@ struct smbd_connection {
|
|||
bool negotiate_done;
|
||||
|
||||
struct work_struct disconnect_work;
|
||||
struct work_struct recv_done_work;
|
||||
struct work_struct post_send_credits_work;
|
||||
|
||||
spinlock_t lock_new_credits_offered;
|
||||
|
|
|
@ -466,7 +466,7 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
|||
struct smb_rqst *rqst, int flags)
|
||||
{
|
||||
struct kvec iov;
|
||||
struct smb2_transform_hdr tr_hdr;
|
||||
struct smb2_transform_hdr *tr_hdr;
|
||||
struct smb_rqst cur_rqst[MAX_COMPOUND];
|
||||
int rc;
|
||||
|
||||
|
@ -476,28 +476,34 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
|||
if (num_rqst > MAX_COMPOUND - 1)
|
||||
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) {
|
||||
cifs_server_dbg(VFS, "Encryption requested but transform "
|
||||
"callback is missing\n");
|
||||
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,
|
||||
&cur_rqst[0], rqst);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto out;
|
||||
|
||||
rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]);
|
||||
smb3_free_compound_rqst(num_rqst, &cur_rqst[1]);
|
||||
out:
|
||||
kfree(tr_hdr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue