CIFS/SMB3 changes, three for stable, adds fiemap support, improves zero-range support, and includes various RDMA (smb direct fixes)
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAlzTHtoACgkQiiy9cAdy T1HMTwwAizpsu/coczGhe5s6CKsyckuToQtMcM8KVcDipzJ/8tDNzWpwAanBffy/ X/g/+EOeplf9blMP4P7KDGV9hp1vfidqm1sa00mb/IEmEhQDQUXW3Mmg8CDKoOtv 0xYKcgOdvaPSsCwI2sgBGZnT1RAFa1kg/pM9ObZN7qCSrLXtFapBfz8HEmPjCMBH Cv0Dra6+XuOQmOF0LfLvgUsrS2cbBkXBV2RX+BV1ouSOLV0r08cHk2gAUib+9tG2 qaQpk3BgW2BIb4Od0TnYOP1V6yqe/jQSfC+J1RMO6evNXT0YCF7A6RpAaZYm674U efp4NJpjqKIfuWWl/VDiuFykAj4JLSDiM6O8xpxl63KjjarYl2HLUSXAfmklDOrB kpnKF4W948kZ75ngGlUIQthRvcI0ynOweGBeaUg5SgNqaww879vfFT0GuTvw4Izv tuc8IIb1k1BD+5s69bYbyjs4INl1Ikb+/Mxl6xx28mISCc/ISQF1d0cBcPkb3ChS qf8Ai+tK =dpRC -----END PGP SIGNATURE----- Merge tag '5.2-smb3' of git://git.samba.org/sfrench/cifs-2.6 Pull cifs fixes from Steve French: "CIFS/SMB3 changes: - three fixes for stable - add fiemap support - improve zero-range support - various RDMA (smb direct fixes) I have an additional set of fixes (for improved handling of sparse files, mode bits, POSIX extensions) that are still being tested that are not included in this pull request but I expect to send in the next week" * tag '5.2-smb3' of git://git.samba.org/sfrench/cifs-2.6: (29 commits) cifs: update module internal version number SMB3: Clean up query symlink when reparse point cifs: fix strcat buffer overflow and reduce raciness in smb21_set_oplock_level() Negotiate and save preferred compression algorithms cifs: rename and clarify CIFS_ASYNC_OP and CIFS_NO_RESP cifs: fix credits leak for SMB1 oplock breaks smb3: Add protocol structs for change notify support cifs: fix smb3_zero_range for Azure cifs: zero-range does not require the file is sparse Add new flag on SMB3.1.1 read cifs: add fiemap support SMB3: Add defines for new negotiate contexts cifs: fix bi-directional fsctl passthrough calls cifs: smbd: take an array of reqeusts when sending upper layer data SMB3: Add handling for different FSCTL access flags cifs: Add support for FSCTL passthrough that write data to the server cifs: remove superfluous inode_lock in cifs_{strict_}fsync cifs: Call MID callback before destroying transport cifs: smbd: Retry on memory registration failure cifs: smbd: Indicate to retry on transport sending failure ...
This commit is contained in:
commit
78d9affbb0
|
@ -312,12 +312,10 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
|||
atomic_read(&server->smbd_conn->send_credits),
|
||||
atomic_read(&server->smbd_conn->receive_credits),
|
||||
server->smbd_conn->receive_credit_target);
|
||||
seq_printf(m, "\nPending send_pending: %x send_payload_pending:"
|
||||
" %x smbd_send_pending: %x smbd_recv_pending: %x",
|
||||
seq_printf(m, "\nPending send_pending: %x "
|
||||
"send_payload_pending: %x",
|
||||
atomic_read(&server->smbd_conn->send_pending),
|
||||
atomic_read(&server->smbd_conn->send_payload_pending),
|
||||
server->smbd_conn->smbd_send_pending,
|
||||
server->smbd_conn->smbd_recv_pending);
|
||||
atomic_read(&server->smbd_conn->send_payload_pending));
|
||||
seq_printf(m, "\nReceive buffers count_receive_queue: %x "
|
||||
"count_empty_packet_queue: %x",
|
||||
server->smbd_conn->count_receive_queue,
|
||||
|
@ -334,6 +332,12 @@ skip_rdma:
|
|||
#endif
|
||||
seq_printf(m, "\nNumber of credits: %d Dialect 0x%x",
|
||||
server->credits, server->dialect);
|
||||
if (server->compress_algorithm == SMB3_COMPRESS_LZNT1)
|
||||
seq_printf(m, " COMPRESS_LZNT1");
|
||||
else if (server->compress_algorithm == SMB3_COMPRESS_LZ77)
|
||||
seq_printf(m, " COMPRESS_LZ77");
|
||||
else if (server->compress_algorithm == SMB3_COMPRESS_LZ77_HUFF)
|
||||
seq_printf(m, " COMPRESS_LZ77_HUFF");
|
||||
if (server->sign)
|
||||
seq_printf(m, " signed");
|
||||
if (server->posix_ext_supported)
|
||||
|
@ -462,8 +466,13 @@ static ssize_t cifs_stats_proc_write(struct file *file,
|
|||
server = list_entry(tmp1, struct TCP_Server_Info,
|
||||
tcp_ses_list);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++)
|
||||
for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) {
|
||||
atomic_set(&server->num_cmds[i], 0);
|
||||
atomic_set(&server->smb2slowcmd[i], 0);
|
||||
server->time_per_cmd[i] = 0;
|
||||
server->slowest_cmd[i] = 0;
|
||||
server->fastest_cmd[0] = 0;
|
||||
}
|
||||
#endif /* CONFIG_CIFS_STATS2 */
|
||||
list_for_each(tmp2, &server->smb_ses_list) {
|
||||
ses = list_entry(tmp2, struct cifs_ses,
|
||||
|
@ -531,9 +540,19 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
|
|||
server = list_entry(tmp1, struct TCP_Server_Info,
|
||||
tcp_ses_list);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
seq_puts(m, "\nTotal time spent processing by command. Time ");
|
||||
seq_printf(m, "units are jiffies (%d per second)\n", HZ);
|
||||
seq_puts(m, " SMB3 CMD\tNumber\tTotal Time\tFastest\tSlowest\n");
|
||||
seq_puts(m, " --------\t------\t----------\t-------\t-------\n");
|
||||
for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++)
|
||||
seq_printf(m, " %d\t\t%d\t%llu\t\t%u\t%u\n", j,
|
||||
atomic_read(&server->num_cmds[j]),
|
||||
server->time_per_cmd[j],
|
||||
server->fastest_cmd[j],
|
||||
server->slowest_cmd[j]);
|
||||
for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++)
|
||||
if (atomic_read(&server->smb2slowcmd[j]))
|
||||
seq_printf(m, "%d slow responses from %s for command %d\n",
|
||||
seq_printf(m, " %d slow responses from %s for command %d\n",
|
||||
atomic_read(&server->smb2slowcmd[j]),
|
||||
server->hostname, j);
|
||||
#endif /* STATS2 */
|
||||
|
|
|
@ -483,6 +483,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
|
|||
seq_puts(s, ",seal");
|
||||
if (tcon->nocase)
|
||||
seq_puts(s, ",nocase");
|
||||
if (tcon->local_lease)
|
||||
seq_puts(s, ",locallease");
|
||||
if (tcon->retry)
|
||||
seq_puts(s, ",hard");
|
||||
else
|
||||
|
@ -984,6 +986,7 @@ const struct inode_operations cifs_file_inode_ops = {
|
|||
.getattr = cifs_getattr,
|
||||
.permission = cifs_permission,
|
||||
.listxattr = cifs_listxattr,
|
||||
.fiemap = cifs_fiemap,
|
||||
};
|
||||
|
||||
const struct inode_operations cifs_symlink_inode_ops = {
|
||||
|
|
|
@ -84,6 +84,8 @@ extern int cifs_revalidate_mapping(struct inode *inode);
|
|||
extern int cifs_zap_mapping(struct inode *inode);
|
||||
extern int cifs_getattr(const struct path *, struct kstat *, u32, unsigned int);
|
||||
extern int cifs_setattr(struct dentry *, struct iattr *);
|
||||
extern int cifs_fiemap(struct inode *, struct fiemap_extent_info *, u64 start,
|
||||
u64 len);
|
||||
|
||||
extern const struct inode_operations cifs_file_inode_ops;
|
||||
extern const struct inode_operations cifs_symlink_inode_ops;
|
||||
|
@ -150,5 +152,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
|||
extern const struct export_operations cifs_export_ops;
|
||||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||
|
||||
#define CIFS_VERSION "2.19"
|
||||
#define CIFS_VERSION "2.20"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
|
|
@ -355,7 +355,8 @@ struct smb_version_operations {
|
|||
struct cifs_sb_info *);
|
||||
/* query symlink target */
|
||||
int (*query_symlink)(const unsigned int, struct cifs_tcon *,
|
||||
const char *, char **, struct cifs_sb_info *);
|
||||
struct cifs_sb_info *, const char *,
|
||||
char **, bool);
|
||||
/* open a file for non-posix mounts */
|
||||
int (*open)(const unsigned int, struct cifs_open_parms *,
|
||||
__u32 *, FILE_ALL_INFO *);
|
||||
|
@ -493,6 +494,9 @@ struct smb_version_operations {
|
|||
char *full_path,
|
||||
umode_t mode,
|
||||
dev_t device_number);
|
||||
/* version specific fiemap implementation */
|
||||
int (*fiemap)(struct cifs_tcon *tcon, struct cifsFileInfo *,
|
||||
struct fiemap_extent_info *, u64, u64);
|
||||
};
|
||||
|
||||
struct smb_version_values {
|
||||
|
@ -596,6 +600,10 @@ struct smb_vol {
|
|||
unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
|
||||
};
|
||||
|
||||
/**
|
||||
* CIFS superblock mount flags (mnt_cifs_flags) to consider when
|
||||
* trying to reuse existing superblock for a new mount
|
||||
*/
|
||||
#define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \
|
||||
CIFS_MOUNT_SERVER_INUM | CIFS_MOUNT_DIRECT_IO | \
|
||||
CIFS_MOUNT_NO_XATTR | CIFS_MOUNT_MAP_SPECIAL_CHR | \
|
||||
|
@ -606,8 +614,13 @@ struct smb_vol {
|
|||
CIFS_MOUNT_NOPOSIXBRL | CIFS_MOUNT_NOSSYNC | \
|
||||
CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | \
|
||||
CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO | \
|
||||
CIFS_MOUNT_CIFS_BACKUPUID | CIFS_MOUNT_CIFS_BACKUPGID)
|
||||
CIFS_MOUNT_CIFS_BACKUPUID | CIFS_MOUNT_CIFS_BACKUPGID | \
|
||||
CIFS_MOUNT_NO_DFS)
|
||||
|
||||
/**
|
||||
* Generic VFS superblock mount flags (s_flags) to consider when
|
||||
* trying to reuse existing superblock for a new mount
|
||||
*/
|
||||
#define CIFS_MS_MASK (SB_RDONLY | SB_MANDLOCK | SB_NOEXEC | SB_NOSUID | \
|
||||
SB_NODEV | SB_SYNCHRONOUS)
|
||||
|
||||
|
@ -714,10 +727,15 @@ struct TCP_Server_Info {
|
|||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_t in_send; /* requests trying to send */
|
||||
atomic_t num_waiters; /* blocked waiting to get in sendrecv */
|
||||
atomic_t num_cmds[NUMBER_OF_SMB2_COMMANDS]; /* total requests by cmd */
|
||||
atomic_t smb2slowcmd[NUMBER_OF_SMB2_COMMANDS]; /* count resps > 1 sec */
|
||||
__u64 time_per_cmd[NUMBER_OF_SMB2_COMMANDS]; /* total time per cmd */
|
||||
__u32 slowest_cmd[NUMBER_OF_SMB2_COMMANDS];
|
||||
__u32 fastest_cmd[NUMBER_OF_SMB2_COMMANDS];
|
||||
#endif /* STATS2 */
|
||||
unsigned int max_read;
|
||||
unsigned int max_write;
|
||||
__le16 compress_algorithm;
|
||||
__le16 cipher_type;
|
||||
/* save initital negprot hash */
|
||||
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
|
||||
|
@ -1673,11 +1691,11 @@ static inline bool is_retryable_error(int error)
|
|||
|
||||
/* Type of Request to SendReceive2 */
|
||||
#define CIFS_BLOCKING_OP 1 /* operation can block */
|
||||
#define CIFS_ASYNC_OP 2 /* do not wait for response */
|
||||
#define CIFS_NON_BLOCKING 2 /* do not block waiting for credits */
|
||||
#define CIFS_TIMEOUT_MASK 0x003 /* only one of above set in req */
|
||||
#define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */
|
||||
#define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */
|
||||
#define CIFS_NO_RESP 0x040 /* no response buffer required */
|
||||
#define CIFS_NO_RSP_BUF 0x040 /* no response buffer required */
|
||||
|
||||
/* Type of request operation */
|
||||
#define CIFS_ECHO_OP 0x080 /* echo request */
|
||||
|
@ -1687,6 +1705,7 @@ static inline bool is_retryable_error(int error)
|
|||
|
||||
#define CIFS_HAS_CREDITS 0x0400 /* already has credits */
|
||||
#define CIFS_TRANSFORM_REQ 0x0800 /* transform request before sending */
|
||||
#define CIFS_NO_SRV_RSP 0x1000 /* there is no server response */
|
||||
|
||||
/* Security Flags: indicate type of session setup needed */
|
||||
#define CIFSSEC_MAY_SIGN 0x00001
|
||||
|
|
|
@ -526,12 +526,21 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
|
|||
const struct nls_table *codepage);
|
||||
extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
|
||||
extern int
|
||||
cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
|
||||
const char *devname, bool is_smb3);
|
||||
extern void
|
||||
cifs_cleanup_volume_info_contents(struct smb_vol *volume_info);
|
||||
|
||||
extern struct TCP_Server_Info *
|
||||
cifs_find_tcp_session(struct smb_vol *vol);
|
||||
|
||||
extern void cifs_put_smb_ses(struct cifs_ses *ses);
|
||||
|
||||
extern struct cifs_ses *
|
||||
cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info);
|
||||
|
||||
void cifs_readdata_release(struct kref *refcount);
|
||||
int cifs_async_readv(struct cifs_readdata *rdata);
|
||||
int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
|
||||
|
|
|
@ -860,7 +860,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
|
|||
iov[1].iov_base = (char *)smb + 4;
|
||||
|
||||
rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
|
||||
server, CIFS_ASYNC_OP | CIFS_ECHO_OP, NULL);
|
||||
server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL);
|
||||
if (rc)
|
||||
cifs_dbg(FYI, "Echo request failed: %d\n", rc);
|
||||
|
||||
|
@ -2508,8 +2508,8 @@ int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
|
||||
|
||||
cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
|
||||
rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
|
||||
&rsp_iov);
|
||||
rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type,
|
||||
CIFS_NO_RSP_BUF, &rsp_iov);
|
||||
cifs_small_buf_release(pSMB);
|
||||
if (rc)
|
||||
cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
|
||||
|
@ -2540,7 +2540,7 @@ CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
|
||||
/* no response expected */
|
||||
flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
|
||||
flags = CIFS_NO_SRV_RSP | CIFS_NON_BLOCKING | CIFS_OBREAK_OP;
|
||||
pSMB->Timeout = 0;
|
||||
} else if (waitFlag) {
|
||||
flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
|
||||
|
@ -6567,93 +6567,3 @@ SetEARetry:
|
|||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
|
||||
/*
|
||||
* Years ago the kernel added a "dnotify" function for Samba server,
|
||||
* to allow network clients (such as Windows) to display updated
|
||||
* lists of files in directory listings automatically when
|
||||
* files are added by one user when another user has the
|
||||
* same directory open on their desktop. The Linux cifs kernel
|
||||
* client hooked into the kernel side of this interface for
|
||||
* the same reason, but ironically when the VFS moved from
|
||||
* "dnotify" to "inotify" it became harder to plug in Linux
|
||||
* network file system clients (the most obvious use case
|
||||
* for notify interfaces is when multiple users can update
|
||||
* the contents of the same directory - exactly what network
|
||||
* file systems can do) although the server (Samba) could
|
||||
* still use it. For the short term we leave the worker
|
||||
* function ifdeffed out (below) until inotify is fixed
|
||||
* in the VFS to make it easier to plug in network file
|
||||
* system clients. If inotify turns out to be permanently
|
||||
* incompatible for network fs clients, we could instead simply
|
||||
* expose this config flag by adding a future cifs (and smb2) notify ioctl.
|
||||
*/
|
||||
int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const int notify_subdirs, const __u16 netfid,
|
||||
__u32 filter, struct file *pfile, int multishot,
|
||||
const struct nls_table *nls_codepage)
|
||||
{
|
||||
int rc = 0;
|
||||
struct smb_com_transaction_change_notify_req *pSMB = NULL;
|
||||
struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
|
||||
struct dir_notify_req *dnotify_req;
|
||||
int bytes_returned;
|
||||
|
||||
cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
|
||||
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
|
||||
(void **) &pSMBr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pSMB->TotalParameterCount = 0 ;
|
||||
pSMB->TotalDataCount = 0;
|
||||
pSMB->MaxParameterCount = cpu_to_le32(2);
|
||||
pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
|
||||
pSMB->MaxSetupCount = 4;
|
||||
pSMB->Reserved = 0;
|
||||
pSMB->ParameterOffset = 0;
|
||||
pSMB->DataCount = 0;
|
||||
pSMB->DataOffset = 0;
|
||||
pSMB->SetupCount = 4; /* single byte does not need le conversion */
|
||||
pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
|
||||
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
||||
if (notify_subdirs)
|
||||
pSMB->WatchTree = 1; /* one byte - no le conversion needed */
|
||||
pSMB->Reserved2 = 0;
|
||||
pSMB->CompletionFilter = cpu_to_le32(filter);
|
||||
pSMB->Fid = netfid; /* file handle always le */
|
||||
pSMB->ByteCount = 0;
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *)pSMBr, &bytes_returned,
|
||||
CIFS_ASYNC_OP);
|
||||
if (rc) {
|
||||
cifs_dbg(FYI, "Error in Notify = %d\n", rc);
|
||||
} else {
|
||||
/* Add file to outstanding requests */
|
||||
/* BB change to kmem cache alloc */
|
||||
dnotify_req = kmalloc(
|
||||
sizeof(struct dir_notify_req),
|
||||
GFP_KERNEL);
|
||||
if (dnotify_req) {
|
||||
dnotify_req->Pid = pSMB->hdr.Pid;
|
||||
dnotify_req->PidHigh = pSMB->hdr.PidHigh;
|
||||
dnotify_req->Mid = pSMB->hdr.Mid;
|
||||
dnotify_req->Tid = pSMB->hdr.Tid;
|
||||
dnotify_req->Uid = pSMB->hdr.Uid;
|
||||
dnotify_req->netfid = netfid;
|
||||
dnotify_req->pfile = pfile;
|
||||
dnotify_req->filter = filter;
|
||||
dnotify_req->multishot = multishot;
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
list_add_tail(&dnotify_req->lhead,
|
||||
&GlobalDnotifyReqList);
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
} else
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
cifs_buf_release(pSMB);
|
||||
return rc;
|
||||
}
|
||||
#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */
|
||||
|
|
|
@ -323,8 +323,6 @@ static int ip_connect(struct TCP_Server_Info *server);
|
|||
static int generic_ip_connect(struct TCP_Server_Info *server);
|
||||
static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
|
||||
static void cifs_prune_tlinks(struct work_struct *work);
|
||||
static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
|
||||
const char *devname, bool is_smb3);
|
||||
static char *extract_hostname(const char *unc);
|
||||
|
||||
/*
|
||||
|
@ -530,21 +528,6 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
|||
/* do not want to be sending data on a socket we are freeing */
|
||||
cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
|
||||
mutex_lock(&server->srv_mutex);
|
||||
if (server->ssocket) {
|
||||
cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n",
|
||||
server->ssocket->state, server->ssocket->flags);
|
||||
kernel_sock_shutdown(server->ssocket, SHUT_WR);
|
||||
cifs_dbg(FYI, "Post shutdown state: 0x%x Flags: 0x%lx\n",
|
||||
server->ssocket->state, server->ssocket->flags);
|
||||
sock_release(server->ssocket);
|
||||
server->ssocket = NULL;
|
||||
}
|
||||
server->sequence_number = 0;
|
||||
server->session_estab = false;
|
||||
kfree(server->session_key.response);
|
||||
server->session_key.response = NULL;
|
||||
server->session_key.len = 0;
|
||||
server->lstrp = jiffies;
|
||||
|
||||
/* mark submitted MIDs for retry and issue callback */
|
||||
INIT_LIST_HEAD(&retry_list);
|
||||
|
@ -557,7 +540,6 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
|||
list_move(&mid_entry->qhead, &retry_list);
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
mutex_unlock(&server->srv_mutex);
|
||||
|
||||
cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
|
||||
list_for_each_safe(tmp, tmp2, &retry_list) {
|
||||
|
@ -566,6 +548,25 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
|||
mid_entry->callback(mid_entry);
|
||||
}
|
||||
|
||||
if (server->ssocket) {
|
||||
cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n",
|
||||
server->ssocket->state, server->ssocket->flags);
|
||||
kernel_sock_shutdown(server->ssocket, SHUT_WR);
|
||||
cifs_dbg(FYI, "Post shutdown state: 0x%x Flags: 0x%lx\n",
|
||||
server->ssocket->state, server->ssocket->flags);
|
||||
sock_release(server->ssocket);
|
||||
server->ssocket = NULL;
|
||||
} else if (cifs_rdma_enabled(server))
|
||||
smbd_destroy(server);
|
||||
server->sequence_number = 0;
|
||||
server->session_estab = false;
|
||||
kfree(server->session_key.response);
|
||||
server->session_key.response = NULL;
|
||||
server->session_key.len = 0;
|
||||
server->lstrp = jiffies;
|
||||
|
||||
mutex_unlock(&server->srv_mutex);
|
||||
|
||||
do {
|
||||
try_to_freeze();
|
||||
|
||||
|
@ -931,10 +932,8 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
|
|||
wake_up_all(&server->request_q);
|
||||
/* give those requests time to exit */
|
||||
msleep(125);
|
||||
if (cifs_rdma_enabled(server) && server->smbd_conn) {
|
||||
smbd_destroy(server->smbd_conn);
|
||||
server->smbd_conn = NULL;
|
||||
}
|
||||
if (cifs_rdma_enabled(server))
|
||||
smbd_destroy(server);
|
||||
if (server->ssocket) {
|
||||
sock_release(server->ssocket);
|
||||
server->ssocket = NULL;
|
||||
|
@ -2904,8 +2903,7 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
cifs_put_smb_ses(struct cifs_ses *ses)
|
||||
void cifs_put_smb_ses(struct cifs_ses *ses)
|
||||
{
|
||||
unsigned int rc, xid;
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
|
@ -3082,7 +3080,7 @@ cifs_set_cifscreds(struct smb_vol *vol __attribute__((unused)),
|
|||
* already got a server reference (server refcount +1). See
|
||||
* cifs_get_tcon() for refcount explanations.
|
||||
*/
|
||||
static struct cifs_ses *
|
||||
struct cifs_ses *
|
||||
cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
|
||||
{
|
||||
int rc = -ENOMEM;
|
||||
|
@ -4389,7 +4387,7 @@ static int mount_do_dfs_failover(const char *path,
|
|||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
int
|
||||
cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
|
||||
const char *devname, bool is_smb3)
|
||||
{
|
||||
|
@ -4543,7 +4541,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
|
|||
struct cifs_tcon *tcon = NULL;
|
||||
struct TCP_Server_Info *server;
|
||||
char *root_path = NULL, *full_path = NULL;
|
||||
char *old_mountdata;
|
||||
char *old_mountdata, *origin_mountdata = NULL;
|
||||
int count;
|
||||
|
||||
rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon);
|
||||
|
@ -4602,6 +4600,14 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
|
|||
goto error;
|
||||
}
|
||||
|
||||
/* Save DFS root volume information for DFS refresh worker */
|
||||
origin_mountdata = kstrndup(cifs_sb->mountdata,
|
||||
strlen(cifs_sb->mountdata), GFP_KERNEL);
|
||||
if (!origin_mountdata) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (cifs_sb->mountdata != old_mountdata) {
|
||||
/* If we were redirected, reconnect to new target server */
|
||||
mount_put_conns(cifs_sb, xid, server, ses, tcon);
|
||||
|
@ -4710,7 +4716,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
|
|||
}
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
rc = dfs_cache_add_vol(vol, cifs_sb->origin_fullpath);
|
||||
rc = dfs_cache_add_vol(origin_mountdata, vol, cifs_sb->origin_fullpath);
|
||||
if (rc) {
|
||||
kfree(cifs_sb->origin_fullpath);
|
||||
goto error;
|
||||
|
@ -4728,6 +4734,7 @@ out:
|
|||
error:
|
||||
kfree(full_path);
|
||||
kfree(root_path);
|
||||
kfree(origin_mountdata);
|
||||
mount_put_conns(cifs_sb, xid, server, ses, tcon);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* DFS referral cache routines
|
||||
*
|
||||
* Copyright (c) 2018 Paulo Alcantara <palcantara@suse.de>
|
||||
* Copyright (c) 2018-2019 Paulo Alcantara <palcantara@suse.de>
|
||||
*/
|
||||
|
||||
#include <linux/rcupdate.h>
|
||||
|
@ -52,6 +52,7 @@ static struct kmem_cache *dfs_cache_slab __read_mostly;
|
|||
struct dfs_cache_vol_info {
|
||||
char *vi_fullpath;
|
||||
struct smb_vol vi_vol;
|
||||
char *vi_mntdata;
|
||||
struct list_head vi_list;
|
||||
};
|
||||
|
||||
|
@ -529,6 +530,7 @@ static inline void free_vol(struct dfs_cache_vol_info *vi)
|
|||
{
|
||||
list_del(&vi->vi_list);
|
||||
kfree(vi->vi_fullpath);
|
||||
kfree(vi->vi_mntdata);
|
||||
cifs_cleanup_volume_info_contents(&vi->vi_vol);
|
||||
kfree(vi);
|
||||
}
|
||||
|
@ -1139,17 +1141,18 @@ err_free_username:
|
|||
* dfs_cache_add_vol - add a cifs volume during mount() that will be handled by
|
||||
* DFS cache refresh worker.
|
||||
*
|
||||
* @mntdata: mount data.
|
||||
* @vol: cifs volume.
|
||||
* @fullpath: origin full path.
|
||||
*
|
||||
* Return zero if volume was set up correctly, otherwise non-zero.
|
||||
*/
|
||||
int dfs_cache_add_vol(struct smb_vol *vol, const char *fullpath)
|
||||
int dfs_cache_add_vol(char *mntdata, struct smb_vol *vol, const char *fullpath)
|
||||
{
|
||||
int rc;
|
||||
struct dfs_cache_vol_info *vi;
|
||||
|
||||
if (!vol || !fullpath)
|
||||
if (!vol || !fullpath || !mntdata)
|
||||
return -EINVAL;
|
||||
|
||||
cifs_dbg(FYI, "%s: fullpath: %s\n", __func__, fullpath);
|
||||
|
@ -1168,6 +1171,8 @@ int dfs_cache_add_vol(struct smb_vol *vol, const char *fullpath)
|
|||
if (rc)
|
||||
goto err_free_fullpath;
|
||||
|
||||
vi->vi_mntdata = mntdata;
|
||||
|
||||
mutex_lock(&dfs_cache.dc_lock);
|
||||
list_add_tail(&vi->vi_list, &dfs_cache.dc_vol_list);
|
||||
mutex_unlock(&dfs_cache.dc_lock);
|
||||
|
@ -1275,8 +1280,102 @@ static void get_tcons(struct TCP_Server_Info *server, struct list_head *head)
|
|||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
}
|
||||
|
||||
static inline bool is_dfs_link(const char *path)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = strchr(path + 1, '\\');
|
||||
if (!s)
|
||||
return false;
|
||||
return !!strchr(s + 1, '\\');
|
||||
}
|
||||
|
||||
static inline char *get_dfs_root(const char *path)
|
||||
{
|
||||
char *s, *npath;
|
||||
|
||||
s = strchr(path + 1, '\\');
|
||||
if (!s)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
s = strchr(s + 1, '\\');
|
||||
if (!s)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
npath = kstrndup(path, s - path, GFP_KERNEL);
|
||||
if (!npath)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
return npath;
|
||||
}
|
||||
|
||||
/* Find root SMB session out of a DFS link path */
|
||||
static struct cifs_ses *find_root_ses(struct dfs_cache_vol_info *vi,
|
||||
struct cifs_tcon *tcon, const char *path)
|
||||
{
|
||||
char *rpath;
|
||||
int rc;
|
||||
struct dfs_info3_param ref = {0};
|
||||
char *mdata = NULL, *devname = NULL;
|
||||
bool is_smb3 = tcon->ses->server->vals->header_preamble_size == 0;
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifs_ses *ses;
|
||||
struct smb_vol vol;
|
||||
|
||||
rpath = get_dfs_root(path);
|
||||
if (IS_ERR(rpath))
|
||||
return ERR_CAST(rpath);
|
||||
|
||||
memset(&vol, 0, sizeof(vol));
|
||||
|
||||
rc = dfs_cache_noreq_find(rpath, &ref, NULL);
|
||||
if (rc) {
|
||||
ses = ERR_PTR(rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mdata = cifs_compose_mount_options(vi->vi_mntdata, rpath, &ref,
|
||||
&devname);
|
||||
free_dfs_info_param(&ref);
|
||||
|
||||
if (IS_ERR(mdata)) {
|
||||
ses = ERR_CAST(mdata);
|
||||
mdata = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = cifs_setup_volume_info(&vol, mdata, devname, is_smb3);
|
||||
kfree(devname);
|
||||
|
||||
if (rc) {
|
||||
ses = ERR_PTR(rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
server = cifs_find_tcp_session(&vol);
|
||||
if (IS_ERR_OR_NULL(server)) {
|
||||
ses = ERR_PTR(-EHOSTDOWN);
|
||||
goto out;
|
||||
}
|
||||
if (server->tcpStatus != CifsGood) {
|
||||
cifs_put_tcp_session(server, 0);
|
||||
ses = ERR_PTR(-EHOSTDOWN);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ses = cifs_get_smb_ses(server, &vol);
|
||||
|
||||
out:
|
||||
cifs_cleanup_volume_info_contents(&vol);
|
||||
kfree(mdata);
|
||||
kfree(rpath);
|
||||
|
||||
return ses;
|
||||
}
|
||||
|
||||
/* Refresh DFS cache entry from a given tcon */
|
||||
static void do_refresh_tcon(struct dfs_cache *dc, struct cifs_tcon *tcon)
|
||||
static void do_refresh_tcon(struct dfs_cache *dc, struct dfs_cache_vol_info *vi,
|
||||
struct cifs_tcon *tcon)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned int xid;
|
||||
|
@ -1285,6 +1384,7 @@ static void do_refresh_tcon(struct dfs_cache *dc, struct cifs_tcon *tcon)
|
|||
struct dfs_cache_entry *ce;
|
||||
struct dfs_info3_param *refs = NULL;
|
||||
int numrefs = 0;
|
||||
struct cifs_ses *root_ses = NULL, *ses;
|
||||
|
||||
xid = get_xid();
|
||||
|
||||
|
@ -1306,13 +1406,24 @@ static void do_refresh_tcon(struct dfs_cache *dc, struct cifs_tcon *tcon)
|
|||
if (!cache_entry_expired(ce))
|
||||
goto out;
|
||||
|
||||
if (unlikely(!tcon->ses->server->ops->get_dfs_refer)) {
|
||||
/* If it's a DFS Link, then use root SMB session for refreshing it */
|
||||
if (is_dfs_link(npath)) {
|
||||
ses = root_ses = find_root_ses(vi, tcon, npath);
|
||||
if (IS_ERR(ses)) {
|
||||
rc = PTR_ERR(ses);
|
||||
root_ses = NULL;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
ses = tcon->ses;
|
||||
}
|
||||
|
||||
if (unlikely(!ses->server->ops->get_dfs_refer)) {
|
||||
rc = -EOPNOTSUPP;
|
||||
} else {
|
||||
rc = tcon->ses->server->ops->get_dfs_refer(xid, tcon->ses, path,
|
||||
&refs, &numrefs,
|
||||
dc->dc_nlsc,
|
||||
tcon->remap);
|
||||
rc = ses->server->ops->get_dfs_refer(xid, ses, path, &refs,
|
||||
&numrefs, dc->dc_nlsc,
|
||||
tcon->remap);
|
||||
if (!rc) {
|
||||
mutex_lock(&dfs_cache_list_lock);
|
||||
ce = __update_cache_entry(npath, refs, numrefs);
|
||||
|
@ -1323,9 +1434,11 @@ static void do_refresh_tcon(struct dfs_cache *dc, struct cifs_tcon *tcon)
|
|||
rc = PTR_ERR(ce);
|
||||
}
|
||||
}
|
||||
if (rc)
|
||||
cifs_dbg(FYI, "%s: failed to update expired entry\n", __func__);
|
||||
|
||||
out:
|
||||
if (root_ses)
|
||||
cifs_put_smb_ses(root_ses);
|
||||
|
||||
free_xid(xid);
|
||||
free_normalized_path(path, npath);
|
||||
}
|
||||
|
@ -1333,9 +1446,6 @@ out:
|
|||
/*
|
||||
* Worker that will refresh DFS cache based on lowest TTL value from a DFS
|
||||
* referral.
|
||||
*
|
||||
* FIXME: ensure that all requests are sent to DFS root for refreshing the
|
||||
* cache.
|
||||
*/
|
||||
static void refresh_cache_worker(struct work_struct *work)
|
||||
{
|
||||
|
@ -1356,7 +1466,7 @@ static void refresh_cache_worker(struct work_struct *work)
|
|||
goto next;
|
||||
get_tcons(server, &list);
|
||||
list_for_each_entry_safe(tcon, ntcon, &list, ulist) {
|
||||
do_refresh_tcon(dc, tcon);
|
||||
do_refresh_tcon(dc, vi, tcon);
|
||||
list_del_init(&tcon->ulist);
|
||||
cifs_put_tcon(tcon);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* DFS referral cache routines
|
||||
*
|
||||
* Copyright (c) 2018 Paulo Alcantara <palcantara@suse.de>
|
||||
* Copyright (c) 2018-2019 Paulo Alcantara <palcantara@suse.de>
|
||||
*/
|
||||
|
||||
#ifndef _CIFS_DFS_CACHE_H
|
||||
|
@ -43,7 +43,8 @@ dfs_cache_noreq_update_tgthint(const char *path,
|
|||
extern int dfs_cache_get_tgt_referral(const char *path,
|
||||
const struct dfs_cache_tgt_iterator *it,
|
||||
struct dfs_info3_param *ref);
|
||||
extern int dfs_cache_add_vol(struct smb_vol *vol, const char *fullpath);
|
||||
extern int dfs_cache_add_vol(char *mntdata, struct smb_vol *vol,
|
||||
const char *fullpath);
|
||||
extern int dfs_cache_update_vol(const char *fullpath,
|
||||
struct TCP_Server_Info *server);
|
||||
extern void dfs_cache_del_vol(const char *fullpath);
|
||||
|
|
|
@ -2443,7 +2443,6 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
|
|||
rc = file_write_and_wait_range(file, start, end);
|
||||
if (rc)
|
||||
return rc;
|
||||
inode_lock(inode);
|
||||
|
||||
xid = get_xid();
|
||||
|
||||
|
@ -2468,7 +2467,6 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
|
|||
}
|
||||
|
||||
free_xid(xid);
|
||||
inode_unlock(inode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -2480,12 +2478,10 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
|||
struct TCP_Server_Info *server;
|
||||
struct cifsFileInfo *smbfile = file->private_data;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
|
||||
rc = file_write_and_wait_range(file, start, end);
|
||||
if (rc)
|
||||
return rc;
|
||||
inode_lock(inode);
|
||||
|
||||
xid = get_xid();
|
||||
|
||||
|
@ -2502,7 +2498,6 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
|||
}
|
||||
|
||||
free_xid(xid);
|
||||
inode_unlock(inode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -2116,6 +2116,43 @@ int cifs_getattr(const struct path *path, struct kstat *stat,
|
|||
return rc;
|
||||
}
|
||||
|
||||
int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
|
||||
u64 len)
|
||||
{
|
||||
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_i->vfs_inode.i_sb);
|
||||
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
struct cifsFileInfo *cfile;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* We need to be sure that all dirty pages are written as they
|
||||
* might fill holes on the server.
|
||||
*/
|
||||
if (!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);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
cfile = find_readable_file(cifs_i, false);
|
||||
if (cfile == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (server->ops->fiemap) {
|
||||
rc = server->ops->fiemap(tcon, cfile, fei, start, len);
|
||||
cifsFileInfo_put(cfile);
|
||||
return rc;
|
||||
}
|
||||
|
||||
cifsFileInfo_put(cfile);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int cifs_truncate_page(struct address_space *mapping, loff_t from)
|
||||
{
|
||||
pgoff_t index = from >> PAGE_SHIFT;
|
||||
|
|
|
@ -648,9 +648,16 @@ cifs_get_link(struct dentry *direntry, struct inode *inode,
|
|||
rc = query_mf_symlink(xid, tcon, cifs_sb, full_path,
|
||||
&target_path);
|
||||
|
||||
if (rc != 0 && server->ops->query_symlink)
|
||||
rc = server->ops->query_symlink(xid, tcon, full_path,
|
||||
&target_path, cifs_sb);
|
||||
if (rc != 0 && server->ops->query_symlink) {
|
||||
struct cifsInodeInfo *cifsi = CIFS_I(inode);
|
||||
bool reparse_point = false;
|
||||
|
||||
if (cifsi->cifsAttrs & ATTR_REPARSE)
|
||||
reparse_point = true;
|
||||
|
||||
rc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path,
|
||||
&target_path, reparse_point);
|
||||
}
|
||||
|
||||
kfree(full_path);
|
||||
free_xid(xid);
|
||||
|
|
|
@ -950,8 +950,8 @@ cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
static int
|
||||
cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *full_path, char **target_path,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
char **target_path, bool is_reparse_point)
|
||||
{
|
||||
int rc;
|
||||
int oplock = 0;
|
||||
|
@ -960,6 +960,11 @@ cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
|
||||
|
||||
if (is_reparse_point) {
|
||||
cifs_dbg(VFS, "reparse points not handled for SMB1 symlinks\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Check for unix extensions */
|
||||
if (cap_unix(tcon->ses)) {
|
||||
rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path,
|
||||
|
|
|
@ -1382,6 +1382,26 @@ smb2_ioctl_query_info(const unsigned int xid,
|
|||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
/*
|
||||
* FSCTL codes encode the special access they need in the fsctl code.
|
||||
*/
|
||||
if (qi.flags & PASSTHRU_FSCTL) {
|
||||
switch (qi.info_type & FSCTL_DEVICE_ACCESS_MASK) {
|
||||
case FSCTL_DEVICE_ACCESS_FILE_READ_WRITE_ACCESS:
|
||||
oparms.desired_access = FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE;
|
||||
break;
|
||||
case FSCTL_DEVICE_ACCESS_FILE_ANY_ACCESS:
|
||||
oparms.desired_access = GENERIC_ALL;
|
||||
break;
|
||||
case FSCTL_DEVICE_ACCESS_FILE_READ_ACCESS:
|
||||
oparms.desired_access = GENERIC_READ;
|
||||
break;
|
||||
case FSCTL_DEVICE_ACCESS_FILE_WRITE_ACCESS:
|
||||
oparms.desired_access = GENERIC_WRITE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path);
|
||||
if (rc)
|
||||
goto iqinf_exit;
|
||||
|
@ -1399,8 +1419,9 @@ smb2_ioctl_query_info(const unsigned int xid,
|
|||
|
||||
rc = SMB2_ioctl_init(tcon, &rqst[1],
|
||||
COMPOUND_FID, COMPOUND_FID,
|
||||
qi.info_type, true, NULL,
|
||||
0, CIFSMaxBufSize);
|
||||
qi.info_type, true, buffer,
|
||||
qi.output_buffer_length,
|
||||
CIFSMaxBufSize);
|
||||
}
|
||||
} else if (qi.flags == PASSTHRU_QUERY_INFO) {
|
||||
memset(&qi_iov, 0, sizeof(qi_iov));
|
||||
|
@ -1441,12 +1462,19 @@ smb2_ioctl_query_info(const unsigned int xid,
|
|||
io_rsp = (struct smb2_ioctl_rsp *)rsp_iov[1].iov_base;
|
||||
if (le32_to_cpu(io_rsp->OutputCount) < qi.input_buffer_length)
|
||||
qi.input_buffer_length = le32_to_cpu(io_rsp->OutputCount);
|
||||
if (qi.input_buffer_length > 0 &&
|
||||
le32_to_cpu(io_rsp->OutputOffset) + qi.input_buffer_length > rsp_iov[1].iov_len) {
|
||||
rc = -EFAULT;
|
||||
goto iqinf_exit;
|
||||
}
|
||||
if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length,
|
||||
sizeof(qi.input_buffer_length))) {
|
||||
rc = -EFAULT;
|
||||
goto iqinf_exit;
|
||||
}
|
||||
if (copy_to_user(pqi + 1, &io_rsp[1], qi.input_buffer_length)) {
|
||||
if (copy_to_user((void __user *)pqi + sizeof(struct smb_query_info),
|
||||
(const void *)io_rsp + le32_to_cpu(io_rsp->OutputOffset),
|
||||
qi.input_buffer_length)) {
|
||||
rc = -EFAULT;
|
||||
goto iqinf_exit;
|
||||
}
|
||||
|
@ -1821,6 +1849,14 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
u32 max_response_size;
|
||||
struct smb_snapshot_array snapshot_in;
|
||||
|
||||
/*
|
||||
* On the first query to enumerate the list of snapshots available
|
||||
* for this volume the buffer begins with 0 (number of snapshots
|
||||
* which can be returned is zero since at that point we do not know
|
||||
* how big the buffer needs to be). On the second query,
|
||||
* it (ret_data_len) is set to number of snapshots so we can
|
||||
* know to set the maximum response size larger (see below).
|
||||
*/
|
||||
if (get_user(ret_data_len, (unsigned int __user *)ioc_buf))
|
||||
return -EFAULT;
|
||||
|
||||
|
@ -2354,46 +2390,129 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
|
|||
|
||||
static int
|
||||
smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *full_path, char **target_path,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
char **target_path, bool is_reparse_point)
|
||||
{
|
||||
int rc;
|
||||
__le16 *utf16_path;
|
||||
__le16 *utf16_path = NULL;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
struct kvec err_iov = {NULL, 0};
|
||||
struct smb2_err_rsp *err_buf = NULL;
|
||||
int resp_buftype;
|
||||
struct smb2_symlink_err_rsp *symlink;
|
||||
unsigned int sub_len;
|
||||
unsigned int sub_offset;
|
||||
unsigned int print_len;
|
||||
unsigned int print_offset;
|
||||
int flags = 0;
|
||||
struct smb_rqst rqst[3];
|
||||
int resp_buftype[3];
|
||||
struct kvec rsp_iov[3];
|
||||
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
||||
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
|
||||
struct kvec close_iov[1];
|
||||
struct smb2_create_rsp *create_rsp;
|
||||
struct smb2_ioctl_rsp *ioctl_rsp;
|
||||
char *ioctl_buf;
|
||||
u32 plen;
|
||||
|
||||
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
memset(rqst, 0, sizeof(rqst));
|
||||
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
||||
memset(rsp_iov, 0, sizeof(rsp_iov));
|
||||
|
||||
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Open */
|
||||
memset(&open_iov, 0, sizeof(open_iov));
|
||||
rqst[0].rq_iov = open_iov;
|
||||
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
||||
|
||||
memset(&oparms, 0, sizeof(oparms));
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = FILE_READ_ATTRIBUTES;
|
||||
oparms.disposition = FILE_OPEN;
|
||||
|
||||
if (backup_cred(cifs_sb))
|
||||
oparms.create_options = CREATE_OPEN_BACKUP_INTENT;
|
||||
else
|
||||
oparms.create_options = 0;
|
||||
if (is_reparse_point)
|
||||
oparms.create_options = OPEN_REPARSE_POINT;
|
||||
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, &err_iov,
|
||||
&resp_buftype);
|
||||
if (!rc)
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, utf16_path);
|
||||
if (rc)
|
||||
goto querty_exit;
|
||||
smb2_set_next_command(tcon, &rqst[0]);
|
||||
|
||||
|
||||
/* IOCTL */
|
||||
memset(&io_iov, 0, sizeof(io_iov));
|
||||
rqst[1].rq_iov = io_iov;
|
||||
rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
|
||||
|
||||
rc = SMB2_ioctl_init(tcon, &rqst[1], fid.persistent_fid,
|
||||
fid.volatile_fid, FSCTL_GET_REPARSE_POINT,
|
||||
true /* is_fctl */, NULL, 0, CIFSMaxBufSize);
|
||||
if (rc)
|
||||
goto querty_exit;
|
||||
|
||||
smb2_set_next_command(tcon, &rqst[1]);
|
||||
smb2_set_related(&rqst[1]);
|
||||
|
||||
|
||||
/* Close */
|
||||
memset(&close_iov, 0, sizeof(close_iov));
|
||||
rqst[2].rq_iov = close_iov;
|
||||
rqst[2].rq_nvec = 1;
|
||||
|
||||
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
|
||||
if (rc)
|
||||
goto querty_exit;
|
||||
|
||||
smb2_set_related(&rqst[2]);
|
||||
|
||||
rc = compound_send_recv(xid, tcon->ses, flags, 3, rqst,
|
||||
resp_buftype, rsp_iov);
|
||||
|
||||
create_rsp = rsp_iov[0].iov_base;
|
||||
if (create_rsp && create_rsp->sync_hdr.Status)
|
||||
err_iov = rsp_iov[0];
|
||||
ioctl_rsp = rsp_iov[1].iov_base;
|
||||
|
||||
/*
|
||||
* Open was successful and we got an ioctl response.
|
||||
*/
|
||||
if ((rc == 0) && (is_reparse_point)) {
|
||||
/* See MS-FSCC 2.3.23 */
|
||||
|
||||
ioctl_buf = (char *)ioctl_rsp + le32_to_cpu(ioctl_rsp->OutputOffset);
|
||||
plen = le32_to_cpu(ioctl_rsp->OutputCount);
|
||||
|
||||
if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) >
|
||||
rsp_iov[1].iov_len) {
|
||||
cifs_dbg(VFS, "srv returned invalid ioctl length: %d\n", plen);
|
||||
rc = -EIO;
|
||||
goto querty_exit;
|
||||
}
|
||||
|
||||
/* Do stuff with ioctl_buf/plen */
|
||||
goto querty_exit;
|
||||
}
|
||||
|
||||
if (!rc || !err_iov.iov_base) {
|
||||
rc = -ENOENT;
|
||||
goto free_path;
|
||||
goto querty_exit;
|
||||
}
|
||||
|
||||
err_buf = err_iov.iov_base;
|
||||
|
@ -2433,9 +2552,14 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
|
||||
|
||||
querty_exit:
|
||||
free_rsp_buf(resp_buftype, err_buf);
|
||||
free_path:
|
||||
cifs_dbg(FYI, "query symlink rc %d\n", rc);
|
||||
kfree(utf16_path);
|
||||
SMB2_open_free(&rqst[0]);
|
||||
SMB2_ioctl_free(&rqst[1]);
|
||||
SMB2_close_free(&rqst[2]);
|
||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
||||
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -2612,16 +2736,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
|||
struct cifsInodeInfo *cifsi;
|
||||
struct cifsFileInfo *cfile = file->private_data;
|
||||
struct file_zero_data_information fsctl_buf;
|
||||
struct smb_rqst rqst[2];
|
||||
int resp_buftype[2];
|
||||
struct kvec rsp_iov[2];
|
||||
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
|
||||
struct kvec si_iov[1];
|
||||
unsigned int size[1];
|
||||
void *data[1];
|
||||
long rc;
|
||||
unsigned int xid;
|
||||
int num = 0, flags = 0;
|
||||
__le64 eof;
|
||||
|
||||
xid = get_xid();
|
||||
|
@ -2643,39 +2759,16 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must check if file sparse since fallocate -z (zero range) assumes
|
||||
* non-sparse allocation
|
||||
*/
|
||||
if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)) {
|
||||
rc = -EOPNOTSUPP;
|
||||
trace_smb3_zero_err(xid, cfile->fid.persistent_fid, tcon->tid,
|
||||
ses->Suid, offset, len, rc);
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
cifs_dbg(FYI, "offset %lld len %lld", offset, len);
|
||||
|
||||
fsctl_buf.FileOffset = cpu_to_le64(offset);
|
||||
fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
|
||||
|
||||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
memset(rqst, 0, sizeof(rqst));
|
||||
resp_buftype[0] = resp_buftype[1] = CIFS_NO_BUFFER;
|
||||
memset(rsp_iov, 0, sizeof(rsp_iov));
|
||||
|
||||
|
||||
memset(&io_iov, 0, sizeof(io_iov));
|
||||
rqst[num].rq_iov = io_iov;
|
||||
rqst[num].rq_nvec = SMB2_IOCTL_IOV_SIZE;
|
||||
rc = SMB2_ioctl_init(tcon, &rqst[num++], cfile->fid.persistent_fid,
|
||||
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
|
||||
true /* is_fctl */, (char *)&fsctl_buf,
|
||||
sizeof(struct file_zero_data_information),
|
||||
CIFSMaxBufSize);
|
||||
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
|
||||
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, true,
|
||||
(char *)&fsctl_buf,
|
||||
sizeof(struct file_zero_data_information),
|
||||
0, NULL, NULL);
|
||||
if (rc)
|
||||
goto zero_range_exit;
|
||||
|
||||
|
@ -2683,33 +2776,12 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
|||
* do we also need to change the size of the file?
|
||||
*/
|
||||
if (keep_size == false && i_size_read(inode) < offset + len) {
|
||||
smb2_set_next_command(tcon, &rqst[0]);
|
||||
|
||||
memset(&si_iov, 0, sizeof(si_iov));
|
||||
rqst[num].rq_iov = si_iov;
|
||||
rqst[num].rq_nvec = 1;
|
||||
|
||||
eof = cpu_to_le64(offset + len);
|
||||
size[0] = 8; /* sizeof __le64 */
|
||||
data[0] = &eof;
|
||||
|
||||
rc = SMB2_set_info_init(tcon, &rqst[num++],
|
||||
cfile->fid.persistent_fid,
|
||||
cfile->fid.persistent_fid,
|
||||
current->tgid,
|
||||
FILE_END_OF_FILE_INFORMATION,
|
||||
SMB2_O_INFO_FILE, 0, data, size);
|
||||
smb2_set_related(&rqst[1]);
|
||||
rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
|
||||
cfile->fid.volatile_fid, cfile->pid, &eof);
|
||||
}
|
||||
|
||||
rc = compound_send_recv(xid, ses, flags, num, rqst,
|
||||
resp_buftype, rsp_iov);
|
||||
|
||||
zero_range_exit:
|
||||
SMB2_ioctl_free(&rqst[0]);
|
||||
SMB2_set_info_free(&rqst[1]);
|
||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
||||
free_xid(xid);
|
||||
if (rc)
|
||||
trace_smb3_zero_err(xid, cfile->fid.persistent_fid, tcon->tid,
|
||||
|
@ -2850,6 +2922,79 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int smb3_fiemap(struct cifs_tcon *tcon,
|
||||
struct cifsFileInfo *cfile,
|
||||
struct fiemap_extent_info *fei, u64 start, u64 len)
|
||||
{
|
||||
unsigned int xid;
|
||||
struct file_allocated_range_buffer in_data, *out_data;
|
||||
u32 out_data_len;
|
||||
int i, num, rc, flags, last_blob;
|
||||
u64 next;
|
||||
|
||||
if (fiemap_check_flags(fei, FIEMAP_FLAG_SYNC))
|
||||
return -EBADR;
|
||||
|
||||
xid = get_xid();
|
||||
again:
|
||||
in_data.file_offset = cpu_to_le64(start);
|
||||
in_data.length = cpu_to_le64(len);
|
||||
|
||||
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
|
||||
cfile->fid.volatile_fid,
|
||||
FSCTL_QUERY_ALLOCATED_RANGES, true,
|
||||
(char *)&in_data, sizeof(in_data),
|
||||
1024 * sizeof(struct file_allocated_range_buffer),
|
||||
(char **)&out_data, &out_data_len);
|
||||
if (rc == -E2BIG) {
|
||||
last_blob = 0;
|
||||
rc = 0;
|
||||
} else
|
||||
last_blob = 1;
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (out_data_len < sizeof(struct file_allocated_range_buffer)) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (out_data_len % sizeof(struct file_allocated_range_buffer)) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
num = out_data_len / sizeof(struct file_allocated_range_buffer);
|
||||
for (i = 0; i < num; i++) {
|
||||
flags = 0;
|
||||
if (i == num - 1 && last_blob)
|
||||
flags |= FIEMAP_EXTENT_LAST;
|
||||
|
||||
rc = fiemap_fill_next_extent(fei,
|
||||
le64_to_cpu(out_data[i].file_offset),
|
||||
le64_to_cpu(out_data[i].file_offset),
|
||||
le64_to_cpu(out_data[i].length),
|
||||
flags);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
if (rc == 1) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!last_blob) {
|
||||
next = le64_to_cpu(out_data[num - 1].file_offset) +
|
||||
le64_to_cpu(out_data[num - 1].length);
|
||||
len = len - (next - start);
|
||||
start = next;
|
||||
goto again;
|
||||
}
|
||||
|
||||
out:
|
||||
free_xid(xid);
|
||||
kfree(out_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode,
|
||||
loff_t off, loff_t len)
|
||||
|
@ -2917,26 +3062,28 @@ smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
|
|||
unsigned int epoch, bool *purge_cache)
|
||||
{
|
||||
char message[5] = {0};
|
||||
unsigned int new_oplock = 0;
|
||||
|
||||
oplock &= 0xFF;
|
||||
if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
|
||||
return;
|
||||
|
||||
cinode->oplock = 0;
|
||||
if (oplock & SMB2_LEASE_READ_CACHING_HE) {
|
||||
cinode->oplock |= CIFS_CACHE_READ_FLG;
|
||||
new_oplock |= CIFS_CACHE_READ_FLG;
|
||||
strcat(message, "R");
|
||||
}
|
||||
if (oplock & SMB2_LEASE_HANDLE_CACHING_HE) {
|
||||
cinode->oplock |= CIFS_CACHE_HANDLE_FLG;
|
||||
new_oplock |= CIFS_CACHE_HANDLE_FLG;
|
||||
strcat(message, "H");
|
||||
}
|
||||
if (oplock & SMB2_LEASE_WRITE_CACHING_HE) {
|
||||
cinode->oplock |= CIFS_CACHE_WRITE_FLG;
|
||||
new_oplock |= CIFS_CACHE_WRITE_FLG;
|
||||
strcat(message, "W");
|
||||
}
|
||||
if (!cinode->oplock)
|
||||
strcat(message, "None");
|
||||
if (!new_oplock)
|
||||
strncpy(message, "None", sizeof(message));
|
||||
|
||||
cinode->oplock = new_oplock;
|
||||
cifs_dbg(FYI, "%s Lease granted on inode %p\n", message,
|
||||
&cinode->vfs_inode);
|
||||
}
|
||||
|
@ -4018,6 +4165,7 @@ struct smb_version_operations smb20_operations = {
|
|||
.next_header = smb2_next_header,
|
||||
.ioctl_query_info = smb2_ioctl_query_info,
|
||||
.make_node = smb2_make_node,
|
||||
.fiemap = smb3_fiemap,
|
||||
};
|
||||
|
||||
struct smb_version_operations smb21_operations = {
|
||||
|
@ -4117,6 +4265,7 @@ struct smb_version_operations smb21_operations = {
|
|||
.next_header = smb2_next_header,
|
||||
.ioctl_query_info = smb2_ioctl_query_info,
|
||||
.make_node = smb2_make_node,
|
||||
.fiemap = smb3_fiemap,
|
||||
};
|
||||
|
||||
struct smb_version_operations smb30_operations = {
|
||||
|
@ -4225,6 +4374,7 @@ struct smb_version_operations smb30_operations = {
|
|||
.next_header = smb2_next_header,
|
||||
.ioctl_query_info = smb2_ioctl_query_info,
|
||||
.make_node = smb2_make_node,
|
||||
.fiemap = smb3_fiemap,
|
||||
};
|
||||
|
||||
struct smb_version_operations smb311_operations = {
|
||||
|
@ -4334,6 +4484,7 @@ struct smb_version_operations smb311_operations = {
|
|||
.next_header = smb2_next_header,
|
||||
.ioctl_query_info = smb2_ioctl_query_info,
|
||||
.make_node = smb2_make_node,
|
||||
.fiemap = smb3_fiemap,
|
||||
};
|
||||
|
||||
struct smb_version_values smb20_values = {
|
||||
|
|
|
@ -459,10 +459,7 @@ smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
|
|||
return rc;
|
||||
}
|
||||
|
||||
|
||||
#define SMB2_PREAUTH_INTEGRITY_CAPABILITIES cpu_to_le16(1)
|
||||
#define SMB2_ENCRYPTION_CAPABILITIES cpu_to_le16(2)
|
||||
#define SMB2_POSIX_EXTENSIONS_AVAILABLE cpu_to_le16(0x100)
|
||||
/* For explanation of negotiate contexts see MS-SMB2 section 2.2.3.1 */
|
||||
|
||||
static void
|
||||
build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt)
|
||||
|
@ -475,6 +472,19 @@ build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt)
|
|||
pneg_ctxt->HashAlgorithms = SMB2_PREAUTH_INTEGRITY_SHA512;
|
||||
}
|
||||
|
||||
static void
|
||||
build_compression_ctxt(struct smb2_compression_capabilities_context *pneg_ctxt)
|
||||
{
|
||||
pneg_ctxt->ContextType = SMB2_COMPRESSION_CAPABILITIES;
|
||||
pneg_ctxt->DataLength =
|
||||
cpu_to_le16(sizeof(struct smb2_compression_capabilities_context)
|
||||
- sizeof(struct smb2_neg_context));
|
||||
pneg_ctxt->CompressionAlgorithmCount = cpu_to_le16(3);
|
||||
pneg_ctxt->CompressionAlgorithms[0] = SMB3_COMPRESS_LZ77;
|
||||
pneg_ctxt->CompressionAlgorithms[1] = SMB3_COMPRESS_LZ77_HUFF;
|
||||
pneg_ctxt->CompressionAlgorithms[2] = SMB3_COMPRESS_LZNT1;
|
||||
}
|
||||
|
||||
static void
|
||||
build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt)
|
||||
{
|
||||
|
@ -541,10 +551,17 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
|
|||
*total_len += ctxt_len;
|
||||
pneg_ctxt += ctxt_len;
|
||||
|
||||
build_compression_ctxt((struct smb2_compression_capabilities_context *)
|
||||
pneg_ctxt);
|
||||
ctxt_len = DIV_ROUND_UP(
|
||||
sizeof(struct smb2_compression_capabilities_context), 8) * 8;
|
||||
*total_len += ctxt_len;
|
||||
pneg_ctxt += ctxt_len;
|
||||
|
||||
build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
|
||||
*total_len += sizeof(struct smb2_posix_neg_context);
|
||||
|
||||
req->NegotiateContextCount = cpu_to_le16(3);
|
||||
req->NegotiateContextCount = cpu_to_le16(4);
|
||||
}
|
||||
|
||||
static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
|
||||
|
@ -562,6 +579,27 @@ static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
|
|||
printk_once(KERN_WARNING "unknown SMB3 hash algorithm\n");
|
||||
}
|
||||
|
||||
static void decode_compress_ctx(struct TCP_Server_Info *server,
|
||||
struct smb2_compression_capabilities_context *ctxt)
|
||||
{
|
||||
unsigned int len = le16_to_cpu(ctxt->DataLength);
|
||||
|
||||
/* sizeof compress context is a one element compression capbility struct */
|
||||
if (len < 10) {
|
||||
printk_once(KERN_WARNING "server sent bad compression cntxt\n");
|
||||
return;
|
||||
}
|
||||
if (le16_to_cpu(ctxt->CompressionAlgorithmCount) != 1) {
|
||||
printk_once(KERN_WARNING "illegal SMB3 compress algorithm count\n");
|
||||
return;
|
||||
}
|
||||
if (le16_to_cpu(ctxt->CompressionAlgorithms[0]) > 3) {
|
||||
printk_once(KERN_WARNING "unknown compression algorithm\n");
|
||||
return;
|
||||
}
|
||||
server->compress_algorithm = ctxt->CompressionAlgorithms[0];
|
||||
}
|
||||
|
||||
static int decode_encrypt_ctx(struct TCP_Server_Info *server,
|
||||
struct smb2_encryption_neg_context *ctxt)
|
||||
{
|
||||
|
@ -626,6 +664,9 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
|
|||
else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES)
|
||||
rc = decode_encrypt_ctx(server,
|
||||
(struct smb2_encryption_neg_context *)pctx);
|
||||
else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES)
|
||||
decode_compress_ctx(server,
|
||||
(struct smb2_compression_capabilities_context *)pctx);
|
||||
else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE)
|
||||
server->posix_ext_supported = true;
|
||||
else
|
||||
|
@ -1541,7 +1582,7 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
|
|||
else if (server->sign)
|
||||
req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED;
|
||||
|
||||
flags |= CIFS_NO_RESP;
|
||||
flags |= CIFS_NO_RSP_BUF;
|
||||
|
||||
iov[0].iov_base = (char *)req;
|
||||
iov[0].iov_len = total_len;
|
||||
|
@ -1742,7 +1783,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
|
|||
if (smb3_encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
flags |= CIFS_NO_RESP;
|
||||
flags |= CIFS_NO_RSP_BUF;
|
||||
|
||||
iov[0].iov_base = (char *)req;
|
||||
iov[0].iov_len = total_len;
|
||||
|
@ -2625,7 +2666,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||
trace_smb3_fsctl_err(xid, persistent_fid, tcon->tid,
|
||||
ses->Suid, 0, opcode, rc);
|
||||
|
||||
if ((rc != 0) && (rc != -EINVAL)) {
|
||||
if ((rc != 0) && (rc != -EINVAL) && (rc != -E2BIG)) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
|
||||
goto ioctl_exit;
|
||||
} else if (rc == -EINVAL) {
|
||||
|
@ -2634,6 +2675,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||
cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
|
||||
goto ioctl_exit;
|
||||
}
|
||||
} else if (rc == -E2BIG) {
|
||||
if (opcode != FSCTL_QUERY_ALLOCATED_RANGES) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
|
||||
goto ioctl_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if caller wants to look at return data or just return rc */
|
||||
|
@ -3223,7 +3269,7 @@ smb2_new_read_req(void **buf, unsigned int *total_len,
|
|||
rdata->nr_pages, rdata->page_offset,
|
||||
rdata->tailsz, true, need_invalidate);
|
||||
if (!rdata->mr)
|
||||
return -ENOBUFS;
|
||||
return -EAGAIN;
|
||||
|
||||
req->Channel = SMB2_CHANNEL_RDMA_V1_INVALIDATE;
|
||||
if (need_invalidate)
|
||||
|
@ -3628,7 +3674,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
|
|||
wdata->nr_pages, wdata->page_offset,
|
||||
wdata->tailsz, false, need_invalidate);
|
||||
if (!wdata->mr) {
|
||||
rc = -ENOBUFS;
|
||||
rc = -EAGAIN;
|
||||
goto async_writev_out;
|
||||
}
|
||||
req->Length = 0;
|
||||
|
@ -4164,7 +4210,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
req->OplockLevel = oplock_level;
|
||||
req->sync_hdr.CreditRequest = cpu_to_le16(1);
|
||||
|
||||
flags |= CIFS_NO_RESP;
|
||||
flags |= CIFS_NO_RSP_BUF;
|
||||
|
||||
iov[0].iov_base = (char *)req;
|
||||
iov[0].iov_len = total_len;
|
||||
|
@ -4438,7 +4484,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
struct kvec rsp_iov;
|
||||
int resp_buf_type;
|
||||
unsigned int count;
|
||||
int flags = CIFS_NO_RESP;
|
||||
int flags = CIFS_NO_RSP_BUF;
|
||||
unsigned int total_len;
|
||||
|
||||
cifs_dbg(FYI, "smb2_lockv num lock %d\n", num_lock);
|
||||
|
@ -4531,7 +4577,7 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
memcpy(req->LeaseKey, lease_key, 16);
|
||||
req->LeaseState = lease_state;
|
||||
|
||||
flags |= CIFS_NO_RESP;
|
||||
flags |= CIFS_NO_RSP_BUF;
|
||||
|
||||
iov[0].iov_base = (char *)req;
|
||||
iov[0].iov_len = total_len;
|
||||
|
|
|
@ -251,6 +251,14 @@ struct smb2_negotiate_req {
|
|||
#define SMB2_NT_FIND 0x00100000
|
||||
#define SMB2_LARGE_FILES 0x00200000
|
||||
|
||||
|
||||
/* Negotiate Contexts - ContextTypes. See MS-SMB2 section 2.2.3.1 for details */
|
||||
#define SMB2_PREAUTH_INTEGRITY_CAPABILITIES cpu_to_le16(1)
|
||||
#define SMB2_ENCRYPTION_CAPABILITIES cpu_to_le16(2)
|
||||
#define SMB2_COMPRESSION_CAPABILITIES cpu_to_le16(3)
|
||||
#define SMB2_NETNAME_NEGOTIATE_CONTEXT_ID cpu_to_le16(5)
|
||||
#define SMB2_POSIX_EXTENSIONS_AVAILABLE cpu_to_le16(0x100)
|
||||
|
||||
struct smb2_neg_context {
|
||||
__le16 ContextType;
|
||||
__le16 DataLength;
|
||||
|
@ -288,6 +296,27 @@ struct smb2_encryption_neg_context {
|
|||
__le16 Ciphers[1]; /* Ciphers[0] since only one used now */
|
||||
} __packed;
|
||||
|
||||
/* See MS-SMB2 2.2.3.1.3 */
|
||||
#define SMB3_COMPRESS_NONE cpu_to_le16(0x0000)
|
||||
#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)
|
||||
|
||||
struct smb2_compression_capabilities_context {
|
||||
__le16 ContextType; /* 3 */
|
||||
__le16 DataLength;
|
||||
__u32 Reserved;
|
||||
__le16 CompressionAlgorithmCount;
|
||||
__u16 Padding;
|
||||
__u32 Reserved1;
|
||||
__le16 CompressionAlgorithms[3];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* For smb2_netname_negotiate_context_id See MS-SMB2 2.2.3.1.4.
|
||||
* Its struct simply contains NetName, an array of Unicode characters
|
||||
*/
|
||||
|
||||
#define POSIX_CTXT_DATA_LEN 16
|
||||
struct smb2_posix_neg_context {
|
||||
__le16 ContextType; /* 0x100 */
|
||||
|
@ -842,6 +871,11 @@ struct fsctl_get_integrity_information_rsp {
|
|||
__le32 ClusterSizeInBytes;
|
||||
} __packed;
|
||||
|
||||
struct file_allocated_range_buffer {
|
||||
__le64 file_offset;
|
||||
__le64 length;
|
||||
} __packed;
|
||||
|
||||
/* Integrity ChecksumAlgorithm choices for above */
|
||||
#define CHECKSUM_TYPE_NONE 0x0000
|
||||
#define CHECKSUM_TYPE_CRC64 0x0002
|
||||
|
@ -1047,6 +1081,7 @@ struct smb2_flush_rsp {
|
|||
|
||||
/* For read request Flags field below, following flag is defined for SMB3.02 */
|
||||
#define SMB2_READFLAG_READ_UNBUFFERED 0x01
|
||||
#define SMB2_READFLAG_REQUEST_COMPRESSED 0x02 /* See MS-SMB2 2.2.19 */
|
||||
|
||||
/* Channel field for read and write: exactly one of following flags can be set*/
|
||||
#define SMB2_CHANNEL_NONE cpu_to_le32(0x00000000)
|
||||
|
@ -1113,6 +1148,42 @@ struct smb2_write_rsp {
|
|||
__u8 Buffer[1];
|
||||
} __packed;
|
||||
|
||||
/* notify flags */
|
||||
#define SMB2_WATCH_TREE 0x0001
|
||||
|
||||
/* notify completion filter flags. See MS-FSCC 2.6 and MS-SMB2 2.2.35 */
|
||||
#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
|
||||
#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
|
||||
#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004
|
||||
#define FILE_NOTIFY_CHANGE_SIZE 0x00000008
|
||||
#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
|
||||
#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020
|
||||
#define FILE_NOTIFY_CHANGE_CREATION 0x00000040
|
||||
#define FILE_NOTIFY_CHANGE_EA 0x00000080
|
||||
#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100
|
||||
#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
|
||||
#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
|
||||
#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
|
||||
|
||||
struct smb2_change_notify_req {
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize;
|
||||
__le16 Flags;
|
||||
__le32 OutputBufferLength;
|
||||
__u64 PersistentFileId; /* opaque endianness */
|
||||
__u64 VolatileFileId; /* opaque endianness */
|
||||
__le32 CompletionFilter;
|
||||
__u32 Reserved;
|
||||
} __packed;
|
||||
|
||||
struct smb2_change_notify_rsp {
|
||||
struct smb2_sync_hdr sync_hdr;
|
||||
__le16 StructureSize; /* Must be 9 */
|
||||
__le16 OutputBufferOffset;
|
||||
__le32 OutputBufferLength;
|
||||
__u8 Buffer[1]; /* array of file notify structs */
|
||||
} __packed;
|
||||
|
||||
#define SMB2_LOCKFLAG_SHARED_LOCK 0x0001
|
||||
#define SMB2_LOCKFLAG_EXCLUSIVE_LOCK 0x0002
|
||||
#define SMB2_LOCKFLAG_UNLOCK 0x0004
|
||||
|
|
3480
fs/cifs/smb2status.h
3480
fs/cifs/smb2status.h
File diff suppressed because it is too large
Load Diff
|
@ -164,95 +164,6 @@ do { \
|
|||
#define log_rdma_mr(level, fmt, args...) \
|
||||
log_rdma(level, LOG_RDMA_MR, fmt, ##args)
|
||||
|
||||
/*
|
||||
* Destroy the transport and related RDMA and memory resources
|
||||
* Need to go through all the pending counters and make sure on one is using
|
||||
* the transport while it is destroyed
|
||||
*/
|
||||
static void smbd_destroy_rdma_work(struct work_struct *work)
|
||||
{
|
||||
struct smbd_response *response;
|
||||
struct smbd_connection *info =
|
||||
container_of(work, struct smbd_connection, destroy_work);
|
||||
unsigned long flags;
|
||||
|
||||
log_rdma_event(INFO, "destroying qp\n");
|
||||
ib_drain_qp(info->id->qp);
|
||||
rdma_destroy_qp(info->id);
|
||||
|
||||
/* Unblock all I/O waiting on the send queue */
|
||||
wake_up_interruptible_all(&info->wait_send_queue);
|
||||
|
||||
log_rdma_event(INFO, "cancelling idle timer\n");
|
||||
cancel_delayed_work_sync(&info->idle_timer_work);
|
||||
log_rdma_event(INFO, "cancelling send immediate work\n");
|
||||
cancel_delayed_work_sync(&info->send_immediate_work);
|
||||
|
||||
log_rdma_event(INFO, "wait for all send to finish\n");
|
||||
wait_event(info->wait_smbd_send_pending,
|
||||
info->smbd_send_pending == 0);
|
||||
|
||||
log_rdma_event(INFO, "wait for all recv to finish\n");
|
||||
wake_up_interruptible(&info->wait_reassembly_queue);
|
||||
wait_event(info->wait_smbd_recv_pending,
|
||||
info->smbd_recv_pending == 0);
|
||||
|
||||
log_rdma_event(INFO, "wait for all send posted to IB to finish\n");
|
||||
wait_event(info->wait_send_pending,
|
||||
atomic_read(&info->send_pending) == 0);
|
||||
wait_event(info->wait_send_payload_pending,
|
||||
atomic_read(&info->send_payload_pending) == 0);
|
||||
|
||||
log_rdma_event(INFO, "freeing mr list\n");
|
||||
wake_up_interruptible_all(&info->wait_mr);
|
||||
wait_event(info->wait_for_mr_cleanup,
|
||||
atomic_read(&info->mr_used_count) == 0);
|
||||
destroy_mr_list(info);
|
||||
|
||||
/* It's not posssible for upper layer to get to reassembly */
|
||||
log_rdma_event(INFO, "drain the reassembly queue\n");
|
||||
do {
|
||||
spin_lock_irqsave(&info->reassembly_queue_lock, flags);
|
||||
response = _get_first_reassembly(info);
|
||||
if (response) {
|
||||
list_del(&response->list);
|
||||
spin_unlock_irqrestore(
|
||||
&info->reassembly_queue_lock, flags);
|
||||
put_receive_buffer(info, response);
|
||||
} else
|
||||
spin_unlock_irqrestore(&info->reassembly_queue_lock, flags);
|
||||
} while (response);
|
||||
|
||||
info->reassembly_data_length = 0;
|
||||
|
||||
log_rdma_event(INFO, "free receive buffers\n");
|
||||
wait_event(info->wait_receive_queues,
|
||||
info->count_receive_queue + info->count_empty_packet_queue
|
||||
== info->receive_credit_max);
|
||||
destroy_receive_buffers(info);
|
||||
|
||||
ib_free_cq(info->send_cq);
|
||||
ib_free_cq(info->recv_cq);
|
||||
ib_dealloc_pd(info->pd);
|
||||
rdma_destroy_id(info->id);
|
||||
|
||||
/* free mempools */
|
||||
mempool_destroy(info->request_mempool);
|
||||
kmem_cache_destroy(info->request_cache);
|
||||
|
||||
mempool_destroy(info->response_mempool);
|
||||
kmem_cache_destroy(info->response_cache);
|
||||
|
||||
info->transport_status = SMBD_DESTROYED;
|
||||
wake_up_all(&info->wait_destroy);
|
||||
}
|
||||
|
||||
static int smbd_process_disconnected(struct smbd_connection *info)
|
||||
{
|
||||
schedule_work(&info->destroy_work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smbd_disconnect_rdma_work(struct work_struct *work)
|
||||
{
|
||||
struct smbd_connection *info =
|
||||
|
@ -319,7 +230,9 @@ static int smbd_conn_upcall(
|
|||
}
|
||||
|
||||
info->transport_status = SMBD_DISCONNECTED;
|
||||
smbd_process_disconnected(info);
|
||||
wake_up_interruptible(&info->disconn_wait);
|
||||
wake_up_interruptible(&info->wait_reassembly_queue);
|
||||
wake_up_interruptible_all(&info->wait_send_queue);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -940,7 +853,7 @@ static int smbd_create_header(struct smbd_connection *info,
|
|||
|
||||
if (info->transport_status != SMBD_CONNECTED) {
|
||||
log_outgoing(ERR, "disconnected not sending\n");
|
||||
return -ENOENT;
|
||||
return -EAGAIN;
|
||||
}
|
||||
atomic_dec(&info->send_credits);
|
||||
|
||||
|
@ -1066,6 +979,7 @@ static int smbd_post_send(struct smbd_connection *info,
|
|||
wake_up(&info->wait_send_pending);
|
||||
}
|
||||
smbd_disconnect_rdma_connection(info);
|
||||
rc = -EAGAIN;
|
||||
} else
|
||||
/* Reset timer for idle connection after packet is sent */
|
||||
mod_delayed_work(info->workqueue, &info->idle_timer_work,
|
||||
|
@ -1478,17 +1392,97 @@ static void idle_connection_timer(struct work_struct *work)
|
|||
info->keep_alive_interval*HZ);
|
||||
}
|
||||
|
||||
/* Destroy this SMBD connection, called from upper layer */
|
||||
void smbd_destroy(struct smbd_connection *info)
|
||||
/*
|
||||
* Destroy the transport and related RDMA and memory resources
|
||||
* Need to go through all the pending counters and make sure on one is using
|
||||
* the transport while it is destroyed
|
||||
*/
|
||||
void smbd_destroy(struct TCP_Server_Info *server)
|
||||
{
|
||||
struct smbd_connection *info = server->smbd_conn;
|
||||
struct smbd_response *response;
|
||||
unsigned long flags;
|
||||
|
||||
if (!info) {
|
||||
log_rdma_event(INFO, "rdma session already destroyed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
log_rdma_event(INFO, "destroying rdma session\n");
|
||||
if (info->transport_status != SMBD_DISCONNECTED) {
|
||||
rdma_disconnect(server->smbd_conn->id);
|
||||
log_rdma_event(INFO, "wait for transport being disconnected\n");
|
||||
wait_event_interruptible(
|
||||
info->disconn_wait,
|
||||
info->transport_status == SMBD_DISCONNECTED);
|
||||
}
|
||||
|
||||
/* Kick off the disconnection process */
|
||||
smbd_disconnect_rdma_connection(info);
|
||||
log_rdma_event(INFO, "destroying qp\n");
|
||||
ib_drain_qp(info->id->qp);
|
||||
rdma_destroy_qp(info->id);
|
||||
|
||||
log_rdma_event(INFO, "wait for transport being destroyed\n");
|
||||
wait_event(info->wait_destroy,
|
||||
info->transport_status == SMBD_DESTROYED);
|
||||
log_rdma_event(INFO, "cancelling idle timer\n");
|
||||
cancel_delayed_work_sync(&info->idle_timer_work);
|
||||
log_rdma_event(INFO, "cancelling send immediate work\n");
|
||||
cancel_delayed_work_sync(&info->send_immediate_work);
|
||||
|
||||
log_rdma_event(INFO, "wait for all send posted to IB to finish\n");
|
||||
wait_event(info->wait_send_pending,
|
||||
atomic_read(&info->send_pending) == 0);
|
||||
wait_event(info->wait_send_payload_pending,
|
||||
atomic_read(&info->send_payload_pending) == 0);
|
||||
|
||||
/* It's not posssible for upper layer to get to reassembly */
|
||||
log_rdma_event(INFO, "drain the reassembly queue\n");
|
||||
do {
|
||||
spin_lock_irqsave(&info->reassembly_queue_lock, flags);
|
||||
response = _get_first_reassembly(info);
|
||||
if (response) {
|
||||
list_del(&response->list);
|
||||
spin_unlock_irqrestore(
|
||||
&info->reassembly_queue_lock, flags);
|
||||
put_receive_buffer(info, response);
|
||||
} else
|
||||
spin_unlock_irqrestore(
|
||||
&info->reassembly_queue_lock, flags);
|
||||
} while (response);
|
||||
info->reassembly_data_length = 0;
|
||||
|
||||
log_rdma_event(INFO, "free receive buffers\n");
|
||||
wait_event(info->wait_receive_queues,
|
||||
info->count_receive_queue + info->count_empty_packet_queue
|
||||
== info->receive_credit_max);
|
||||
destroy_receive_buffers(info);
|
||||
|
||||
/*
|
||||
* For performance reasons, memory registration and deregistration
|
||||
* are not locked by srv_mutex. It is possible some processes are
|
||||
* blocked on transport srv_mutex while holding memory registration.
|
||||
* Release the transport srv_mutex to allow them to hit the failure
|
||||
* path when sending data, and then release memory registartions.
|
||||
*/
|
||||
log_rdma_event(INFO, "freeing mr list\n");
|
||||
wake_up_interruptible_all(&info->wait_mr);
|
||||
while (atomic_read(&info->mr_used_count)) {
|
||||
mutex_unlock(&server->srv_mutex);
|
||||
msleep(1000);
|
||||
mutex_lock(&server->srv_mutex);
|
||||
}
|
||||
destroy_mr_list(info);
|
||||
|
||||
ib_free_cq(info->send_cq);
|
||||
ib_free_cq(info->recv_cq);
|
||||
ib_dealloc_pd(info->pd);
|
||||
rdma_destroy_id(info->id);
|
||||
|
||||
/* free mempools */
|
||||
mempool_destroy(info->request_mempool);
|
||||
kmem_cache_destroy(info->request_cache);
|
||||
|
||||
mempool_destroy(info->response_mempool);
|
||||
kmem_cache_destroy(info->response_cache);
|
||||
|
||||
info->transport_status = SMBD_DESTROYED;
|
||||
|
||||
destroy_workqueue(info->workqueue);
|
||||
kfree(info);
|
||||
|
@ -1513,17 +1507,9 @@ int smbd_reconnect(struct TCP_Server_Info *server)
|
|||
*/
|
||||
if (server->smbd_conn->transport_status == SMBD_CONNECTED) {
|
||||
log_rdma_event(INFO, "disconnecting transport\n");
|
||||
smbd_disconnect_rdma_connection(server->smbd_conn);
|
||||
smbd_destroy(server);
|
||||
}
|
||||
|
||||
/* wait until the transport is destroyed */
|
||||
if (!wait_event_timeout(server->smbd_conn->wait_destroy,
|
||||
server->smbd_conn->transport_status == SMBD_DESTROYED, 5*HZ))
|
||||
return -EAGAIN;
|
||||
|
||||
destroy_workqueue(server->smbd_conn->workqueue);
|
||||
kfree(server->smbd_conn);
|
||||
|
||||
create_conn:
|
||||
log_rdma_event(INFO, "creating rdma session\n");
|
||||
server->smbd_conn = smbd_get_connection(
|
||||
|
@ -1739,12 +1725,13 @@ static struct smbd_connection *_smbd_get_connection(
|
|||
conn_param.retry_count = SMBD_CM_RETRY;
|
||||
conn_param.rnr_retry_count = SMBD_CM_RNR_RETRY;
|
||||
conn_param.flow_control = 0;
|
||||
init_waitqueue_head(&info->wait_destroy);
|
||||
|
||||
log_rdma_event(INFO, "connecting to IP %pI4 port %d\n",
|
||||
&addr_in->sin_addr, port);
|
||||
|
||||
init_waitqueue_head(&info->conn_wait);
|
||||
init_waitqueue_head(&info->disconn_wait);
|
||||
init_waitqueue_head(&info->wait_reassembly_queue);
|
||||
rc = rdma_connect(info->id, &conn_param);
|
||||
if (rc) {
|
||||
log_rdma_event(ERR, "rdma_connect() failed with %i\n", rc);
|
||||
|
@ -1768,19 +1755,11 @@ static struct smbd_connection *_smbd_get_connection(
|
|||
}
|
||||
|
||||
init_waitqueue_head(&info->wait_send_queue);
|
||||
init_waitqueue_head(&info->wait_reassembly_queue);
|
||||
|
||||
INIT_DELAYED_WORK(&info->idle_timer_work, idle_connection_timer);
|
||||
INIT_DELAYED_WORK(&info->send_immediate_work, send_immediate_work);
|
||||
queue_delayed_work(info->workqueue, &info->idle_timer_work,
|
||||
info->keep_alive_interval*HZ);
|
||||
|
||||
init_waitqueue_head(&info->wait_smbd_send_pending);
|
||||
info->smbd_send_pending = 0;
|
||||
|
||||
init_waitqueue_head(&info->wait_smbd_recv_pending);
|
||||
info->smbd_recv_pending = 0;
|
||||
|
||||
init_waitqueue_head(&info->wait_send_pending);
|
||||
atomic_set(&info->send_pending, 0);
|
||||
|
||||
|
@ -1788,7 +1767,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->destroy_work, smbd_destroy_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;
|
||||
|
@ -1810,7 +1788,7 @@ static struct smbd_connection *_smbd_get_connection(
|
|||
|
||||
allocate_mr_failed:
|
||||
/* At this point, need to a full transport shutdown */
|
||||
smbd_destroy(info);
|
||||
smbd_destroy(server);
|
||||
return NULL;
|
||||
|
||||
negotiation_failed:
|
||||
|
@ -1882,11 +1860,6 @@ static int smbd_recv_buf(struct smbd_connection *info, char *buf,
|
|||
int rc;
|
||||
|
||||
again:
|
||||
if (info->transport_status != SMBD_CONNECTED) {
|
||||
log_read(ERR, "disconnected\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* No need to hold the reassembly queue lock all the time as we are
|
||||
* the only one reading from the front of the queue. The transport
|
||||
|
@ -2000,7 +1973,12 @@ read_rfc1002_done:
|
|||
info->transport_status != SMBD_CONNECTED);
|
||||
/* Don't return any data if interrupted */
|
||||
if (rc)
|
||||
return -ENODEV;
|
||||
return rc;
|
||||
|
||||
if (info->transport_status != SMBD_CONNECTED) {
|
||||
log_read(ERR, "disconnected\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
goto again;
|
||||
}
|
||||
|
@ -2052,8 +2030,6 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg)
|
|||
unsigned int to_read, page_offset;
|
||||
int rc;
|
||||
|
||||
info->smbd_recv_pending++;
|
||||
|
||||
if (iov_iter_rw(&msg->msg_iter) == WRITE) {
|
||||
/* It's a bug in upper layer to get there */
|
||||
cifs_dbg(VFS, "CIFS: invalid msg iter dir %u\n",
|
||||
|
@ -2084,9 +2060,6 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg)
|
|||
}
|
||||
|
||||
out:
|
||||
info->smbd_recv_pending--;
|
||||
wake_up(&info->wait_smbd_recv_pending);
|
||||
|
||||
/* SMBDirect will read it all or nothing */
|
||||
if (rc > 0)
|
||||
msg->msg_iter.count = 0;
|
||||
|
@ -2099,7 +2072,8 @@ out:
|
|||
* rqst: the data to write
|
||||
* return value: 0 if successfully write, otherwise error code
|
||||
*/
|
||||
int smbd_send(struct TCP_Server_Info *server, struct smb_rqst *rqst)
|
||||
int smbd_send(struct TCP_Server_Info *server,
|
||||
int num_rqst, struct smb_rqst *rqst_array)
|
||||
{
|
||||
struct smbd_connection *info = server->smbd_conn;
|
||||
struct kvec vec;
|
||||
|
@ -2111,54 +2085,49 @@ int smbd_send(struct TCP_Server_Info *server, struct smb_rqst *rqst)
|
|||
info->max_send_size - sizeof(struct smbd_data_transfer);
|
||||
struct kvec *iov;
|
||||
int rc;
|
||||
struct smb_rqst *rqst;
|
||||
int rqst_idx;
|
||||
|
||||
info->smbd_send_pending++;
|
||||
if (info->transport_status != SMBD_CONNECTED) {
|
||||
rc = -ENODEV;
|
||||
rc = -EAGAIN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip the RFC1002 length defined in MS-SMB2 section 2.1
|
||||
* It is used only for TCP transport in the iov[0]
|
||||
* In future we may want to add a transport layer under protocol
|
||||
* layer so this will only be issued to TCP transport
|
||||
*/
|
||||
|
||||
if (rqst->rq_iov[0].iov_len != 4) {
|
||||
log_write(ERR, "expected the pdu length in 1st iov, but got %zu\n", rqst->rq_iov[0].iov_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add in the page array if there is one. The caller needs to set
|
||||
* rq_tailsz to PAGE_SIZE when the buffer has multiple pages and
|
||||
* ends at page boundary
|
||||
*/
|
||||
buflen = smb_rqst_len(server, rqst);
|
||||
remaining_data_length = 0;
|
||||
for (i = 0; i < num_rqst; i++)
|
||||
remaining_data_length += smb_rqst_len(server, &rqst_array[i]);
|
||||
|
||||
if (buflen + sizeof(struct smbd_data_transfer) >
|
||||
if (remaining_data_length + sizeof(struct smbd_data_transfer) >
|
||||
info->max_fragmented_send_size) {
|
||||
log_write(ERR, "payload size %d > max size %d\n",
|
||||
buflen, info->max_fragmented_send_size);
|
||||
remaining_data_length, info->max_fragmented_send_size);
|
||||
rc = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
iov = &rqst->rq_iov[1];
|
||||
rqst_idx = 0;
|
||||
|
||||
cifs_dbg(FYI, "Sending smb (RDMA): smb_len=%u\n", buflen);
|
||||
for (i = 0; i < rqst->rq_nvec-1; i++)
|
||||
next_rqst:
|
||||
rqst = &rqst_array[rqst_idx];
|
||||
iov = rqst->rq_iov;
|
||||
|
||||
cifs_dbg(FYI, "Sending smb (RDMA): idx=%d smb_len=%lu\n",
|
||||
rqst_idx, smb_rqst_len(server, rqst));
|
||||
for (i = 0; i < rqst->rq_nvec; i++)
|
||||
dump_smb(iov[i].iov_base, iov[i].iov_len);
|
||||
|
||||
remaining_data_length = buflen;
|
||||
|
||||
log_write(INFO, "rqst->rq_nvec=%d rqst->rq_npages=%d rq_pagesz=%d "
|
||||
"rq_tailsz=%d buflen=%d\n",
|
||||
rqst->rq_nvec, rqst->rq_npages, rqst->rq_pagesz,
|
||||
rqst->rq_tailsz, buflen);
|
||||
log_write(INFO, "rqst_idx=%d nvec=%d rqst->rq_npages=%d rq_pagesz=%d "
|
||||
"rq_tailsz=%d buflen=%lu\n",
|
||||
rqst_idx, rqst->rq_nvec, rqst->rq_npages, rqst->rq_pagesz,
|
||||
rqst->rq_tailsz, smb_rqst_len(server, rqst));
|
||||
|
||||
start = i = iov[0].iov_len ? 0 : 1;
|
||||
start = i = 0;
|
||||
buflen = 0;
|
||||
while (true) {
|
||||
buflen += iov[i].iov_len;
|
||||
|
@ -2206,14 +2175,14 @@ int smbd_send(struct TCP_Server_Info *server, struct smb_rqst *rqst)
|
|||
goto done;
|
||||
}
|
||||
i++;
|
||||
if (i == rqst->rq_nvec-1)
|
||||
if (i == rqst->rq_nvec)
|
||||
break;
|
||||
}
|
||||
start = i;
|
||||
buflen = 0;
|
||||
} else {
|
||||
i++;
|
||||
if (i == rqst->rq_nvec-1) {
|
||||
if (i == rqst->rq_nvec) {
|
||||
/* send out all remaining vecs */
|
||||
remaining_data_length -= buflen;
|
||||
log_write(INFO,
|
||||
|
@ -2257,6 +2226,10 @@ int smbd_send(struct TCP_Server_Info *server, struct smb_rqst *rqst)
|
|||
}
|
||||
}
|
||||
|
||||
rqst_idx++;
|
||||
if (rqst_idx < num_rqst)
|
||||
goto next_rqst;
|
||||
|
||||
done:
|
||||
/*
|
||||
* As an optimization, we don't wait for individual I/O to finish
|
||||
|
@ -2268,9 +2241,6 @@ done:
|
|||
wait_event(info->wait_send_payload_pending,
|
||||
atomic_read(&info->send_payload_pending) == 0);
|
||||
|
||||
info->smbd_send_pending--;
|
||||
wake_up(&info->wait_smbd_send_pending);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,12 +70,11 @@ struct smbd_connection {
|
|||
int ri_rc;
|
||||
struct completion ri_done;
|
||||
wait_queue_head_t conn_wait;
|
||||
wait_queue_head_t wait_destroy;
|
||||
wait_queue_head_t disconn_wait;
|
||||
|
||||
struct completion negotiate_completion;
|
||||
bool negotiate_done;
|
||||
|
||||
struct work_struct destroy_work;
|
||||
struct work_struct disconnect_work;
|
||||
struct work_struct recv_done_work;
|
||||
struct work_struct post_send_credits_work;
|
||||
|
@ -123,13 +122,6 @@ struct smbd_connection {
|
|||
wait_queue_head_t wait_for_mr_cleanup;
|
||||
|
||||
/* Activity accoutning */
|
||||
/* Pending reqeusts issued from upper layer */
|
||||
int smbd_send_pending;
|
||||
wait_queue_head_t wait_smbd_send_pending;
|
||||
|
||||
int smbd_recv_pending;
|
||||
wait_queue_head_t wait_smbd_recv_pending;
|
||||
|
||||
atomic_t send_pending;
|
||||
wait_queue_head_t wait_send_pending;
|
||||
atomic_t send_payload_pending;
|
||||
|
@ -288,11 +280,12 @@ struct smbd_connection *smbd_get_connection(
|
|||
/* Reconnect SMBDirect session */
|
||||
int smbd_reconnect(struct TCP_Server_Info *server);
|
||||
/* Destroy SMBDirect session */
|
||||
void smbd_destroy(struct smbd_connection *info);
|
||||
void smbd_destroy(struct TCP_Server_Info *server);
|
||||
|
||||
/* Interface for carrying upper layer I/O through send/recv */
|
||||
int smbd_recv(struct smbd_connection *info, struct msghdr *msg);
|
||||
int smbd_send(struct TCP_Server_Info *server, struct smb_rqst *rqst);
|
||||
int smbd_send(struct TCP_Server_Info *server,
|
||||
int num_rqst, struct smb_rqst *rqst);
|
||||
|
||||
enum mr_state {
|
||||
MR_READY,
|
||||
|
@ -330,9 +323,9 @@ struct smbd_connection {};
|
|||
static inline void *smbd_get_connection(
|
||||
struct TCP_Server_Info *server, struct sockaddr *dstaddr) {return NULL;}
|
||||
static inline int smbd_reconnect(struct TCP_Server_Info *server) {return -1; }
|
||||
static inline void smbd_destroy(struct smbd_connection *info) {}
|
||||
static inline void smbd_destroy(struct TCP_Server_Info *server) {}
|
||||
static inline int smbd_recv(struct smbd_connection *info, struct msghdr *msg) {return -1; }
|
||||
static inline int smbd_send(struct TCP_Server_Info *server, struct smb_rqst *rqst) {return -1; }
|
||||
static inline int smbd_send(struct TCP_Server_Info *server, int num_rqst, struct smb_rqst *rqst) {return -1; }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,6 +35,33 @@
|
|||
* below). Additional detail on less common ones can be found in MS-FSCC
|
||||
* section 2.3.
|
||||
*/
|
||||
|
||||
/*
|
||||
* FSCTL values are 32 bits and are constructed as
|
||||
* <device 16bits> <access 2bits> <function 12bits> <method 2bits>
|
||||
*/
|
||||
/* Device */
|
||||
#define FSCTL_DEVICE_DFS (0x0006 << 16)
|
||||
#define FSCTL_DEVICE_FILE_SYSTEM (0x0009 << 16)
|
||||
#define FSCTL_DEVICE_NAMED_PIPE (0x0011 << 16)
|
||||
#define FSCTL_DEVICE_NETWORK_FILE_SYSTEM (0x0014 << 16)
|
||||
#define FSCTL_DEVICE_MASK 0xffff0000
|
||||
/* Access */
|
||||
#define FSCTL_DEVICE_ACCESS_FILE_ANY_ACCESS (0x00 << 14)
|
||||
#define FSCTL_DEVICE_ACCESS_FILE_READ_ACCESS (0x01 << 14)
|
||||
#define FSCTL_DEVICE_ACCESS_FILE_WRITE_ACCESS (0x02 << 14)
|
||||
#define FSCTL_DEVICE_ACCESS_FILE_READ_WRITE_ACCESS (0x03 << 14)
|
||||
#define FSCTL_DEVICE_ACCESS_MASK 0x0000c000
|
||||
/* Function */
|
||||
#define FSCTL_DEVICE_FUNCTION_MASK 0x00003ffc
|
||||
/* Method */
|
||||
#define FSCTL_DEVICE_METHOD_BUFFERED 0x00
|
||||
#define FSCTL_DEVICE_METHOD_IN_DIRECT 0x01
|
||||
#define FSCTL_DEVICE_METHOD_OUT_DIRECT 0x02
|
||||
#define FSCTL_DEVICE_METHOD_NEITHER 0x03
|
||||
#define FSCTL_DEVICE_METHOD_MASK 0x00000003
|
||||
|
||||
|
||||
#define FSCTL_DFS_GET_REFERRALS 0x00060194
|
||||
#define FSCTL_DFS_GET_REFERRALS_EX 0x000601B0
|
||||
#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000
|
||||
|
@ -76,7 +103,7 @@
|
|||
#define FSCTL_SET_ZERO_ON_DEALLOC 0x00090194 /* BB add struct */
|
||||
#define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */
|
||||
#define FSCTL_GET_INTEGRITY_INFORMATION 0x0009027C
|
||||
#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF /* BB add struct */
|
||||
#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF
|
||||
#define FSCTL_SET_DEFECT_MANAGEMENT 0x00098134 /* BB add struct */
|
||||
#define FSCTL_FILE_LEVEL_TRIM 0x00098208 /* BB add struct */
|
||||
#define FSCTL_DUPLICATE_EXTENTS_TO_FILE 0x00098344
|
||||
|
|
|
@ -104,7 +104,10 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
|
|||
{
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
__le16 command = midEntry->server->vals->lock_cmd;
|
||||
__u16 smb_cmd = le16_to_cpu(midEntry->command);
|
||||
unsigned long now;
|
||||
unsigned long roundtrip_time;
|
||||
struct TCP_Server_Info *server = midEntry->server;
|
||||
#endif
|
||||
midEntry->mid_state = MID_FREE;
|
||||
atomic_dec(&midCount);
|
||||
|
@ -114,6 +117,23 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
|
|||
cifs_small_buf_release(midEntry->resp_buf);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
now = jiffies;
|
||||
if (now < midEntry->when_alloc)
|
||||
cifs_dbg(VFS, "invalid mid allocation time\n");
|
||||
roundtrip_time = now - midEntry->when_alloc;
|
||||
|
||||
if (smb_cmd < NUMBER_OF_SMB2_COMMANDS) {
|
||||
if (atomic_read(&server->num_cmds[smb_cmd]) == 0) {
|
||||
server->slowest_cmd[smb_cmd] = roundtrip_time;
|
||||
server->fastest_cmd[smb_cmd] = roundtrip_time;
|
||||
} else {
|
||||
if (server->slowest_cmd[smb_cmd] < roundtrip_time)
|
||||
server->slowest_cmd[smb_cmd] = roundtrip_time;
|
||||
else if (server->fastest_cmd[smb_cmd] > roundtrip_time)
|
||||
server->fastest_cmd[smb_cmd] = roundtrip_time;
|
||||
}
|
||||
cifs_stats_inc(&server->num_cmds[smb_cmd]);
|
||||
server->time_per_cmd[smb_cmd] += roundtrip_time;
|
||||
}
|
||||
/*
|
||||
* commands taking longer than one second (default) can be indications
|
||||
* that something is wrong, unless it is quite a slow link or a very
|
||||
|
@ -131,11 +151,10 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
|
|||
* smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command
|
||||
* NB: le16_to_cpu returns unsigned so can not be negative below
|
||||
*/
|
||||
if (le16_to_cpu(midEntry->command) < NUMBER_OF_SMB2_COMMANDS)
|
||||
cifs_stats_inc(&midEntry->server->smb2slowcmd[le16_to_cpu(midEntry->command)]);
|
||||
if (smb_cmd < NUMBER_OF_SMB2_COMMANDS)
|
||||
cifs_stats_inc(&server->smb2slowcmd[smb_cmd]);
|
||||
|
||||
trace_smb3_slow_rsp(le16_to_cpu(midEntry->command),
|
||||
midEntry->mid, midEntry->pid,
|
||||
trace_smb3_slow_rsp(smb_cmd, midEntry->mid, midEntry->pid,
|
||||
midEntry->when_sent, midEntry->when_received);
|
||||
if (cifsFYI & CIFS_TIMER) {
|
||||
pr_debug(" CIFS slow rsp: cmd %d mid %llu",
|
||||
|
@ -300,7 +319,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
|||
__be32 rfc1002_marker;
|
||||
|
||||
if (cifs_rdma_enabled(server) && server->smbd_conn) {
|
||||
rc = smbd_send(server, rqst);
|
||||
rc = smbd_send(server, num_rqst, rqst);
|
||||
goto smbd_done;
|
||||
}
|
||||
|
||||
|
@ -510,7 +529,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits,
|
|||
return -EAGAIN;
|
||||
|
||||
spin_lock(&server->req_lock);
|
||||
if ((flags & CIFS_TIMEOUT_MASK) == CIFS_ASYNC_OP) {
|
||||
if ((flags & CIFS_TIMEOUT_MASK) == CIFS_NON_BLOCKING) {
|
||||
/* oplock breaks must not be held up */
|
||||
server->in_flight++;
|
||||
*credits -= 1;
|
||||
|
@ -819,7 +838,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
|
|||
|
||||
iov[0].iov_base = in_buf;
|
||||
iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
|
||||
flags |= CIFS_NO_RESP;
|
||||
flags |= CIFS_NO_RSP_BUF;
|
||||
rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
|
||||
cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
|
||||
|
||||
|
@ -1054,8 +1073,11 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
|
||||
if (rc < 0) {
|
||||
/* Sending failed for some reason - return credits back */
|
||||
/*
|
||||
* If sending failed for some reason or it is an oplock break that we
|
||||
* will not receive a response to - return credits back
|
||||
*/
|
||||
if (rc < 0 || (flags & CIFS_NO_SRV_RSP)) {
|
||||
for (i = 0; i < num_rqst; i++)
|
||||
add_credits(ses->server, &credits[i], optype);
|
||||
goto out;
|
||||
|
@ -1076,9 +1098,6 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
smb311_update_preauth_hash(ses, rqst[0].rq_iov,
|
||||
rqst[0].rq_nvec);
|
||||
|
||||
if ((flags & CIFS_TIMEOUT_MASK) == CIFS_ASYNC_OP)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < num_rqst; i++) {
|
||||
rc = wait_for_response(ses->server, midQ[i]);
|
||||
if (rc != 0)
|
||||
|
@ -1132,7 +1151,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
|||
flags & CIFS_LOG_ERROR);
|
||||
|
||||
/* mark it so buf will not be freed by cifs_delete_mid */
|
||||
if ((flags & CIFS_NO_RESP) == 0)
|
||||
if ((flags & CIFS_NO_RSP_BUF) == 0)
|
||||
midQ[i]->resp_buf = NULL;
|
||||
|
||||
}
|
||||
|
@ -1283,9 +1302,6 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
|
|||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
if ((flags & CIFS_TIMEOUT_MASK) == CIFS_ASYNC_OP)
|
||||
goto out;
|
||||
|
||||
rc = wait_for_response(ses->server, midQ);
|
||||
if (rc != 0) {
|
||||
send_cancel(ses->server, &rqst, midQ);
|
||||
|
|
Loading…
Reference in New Issue