mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 14:44:10 +08:00
Five smb3 client fixes
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmSzLRMACgkQiiy9cAdy T1G6twwAtVJTuyoRmG5VbMWlEO7MtSzzeIKImJnpgPD1sjrEb9HLJKyGp/A/3pyD hywQKA76IkkFSnxguccpFWNJAtVaB3ChXz4VPcj+cg/AuFQSteBuK0ZQZ7IjfpUO ROMq8lpWT9olKrgqnsUlzY1a49f40bobeQMMnKLVa3BQJbNdg170fgUuobNqZ4is HcmUNMX6C+i/AKYboA7+7OnaWhwJx3wjO/ZWMwh6RTnxY02jYrlnmAa9Tjz+Lox8 b7QVxadlLYCUv7IgNs6b45IJmWDVWFQ8cfY8LuLIe+Y76ED+liN47jkvV0KR26Zj 15JNQlaNmalpTVPfybv7OaVLmEvmZMwqBLmbPCGSxCvLyvsIIR+2QTrjUzFs772q aVy8k3mGoOgWCIYQYQHC9m0W5pqU0vJ+r5Sc6JZo/QEbaB0xjqZD82spBCN9rybB YfpZR6E3OFFW80UJ6wla8rzcAyxVIR6+DXAwZI2A6x92A9WyXQAwfy4H+Jo7XO2n zMuLc9/E =kcX/ -----END PGP SIGNATURE----- Merge tag '6.5-rc1-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull smb client fixes from Steve French: - Two reconnect fixes: important fix to address inFlight count to leak (which can leak credits), and fix for better handling a deleted share - DFS fix - SMB1 cleanup fix - deferred close fix * tag '6.5-rc1-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: fix mid leak during reconnection after timeout threshold cifs: is_network_name_deleted should return a bool smb: client: fix missed ses refcounting smb: client: Fix -Wstringop-overflow issues cifs: if deferred close is disabled then close files immediately
This commit is contained in:
commit
fe756ad021
@ -532,7 +532,7 @@ struct smb_version_operations {
|
|||||||
/* Check for STATUS_IO_TIMEOUT */
|
/* Check for STATUS_IO_TIMEOUT */
|
||||||
bool (*is_status_io_timeout)(char *buf);
|
bool (*is_status_io_timeout)(char *buf);
|
||||||
/* Check for STATUS_NETWORK_NAME_DELETED */
|
/* Check for STATUS_NETWORK_NAME_DELETED */
|
||||||
void (*is_network_name_deleted)(char *buf, struct TCP_Server_Info *srv);
|
bool (*is_network_name_deleted)(char *buf, struct TCP_Server_Info *srv);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smb_version_values {
|
struct smb_version_values {
|
||||||
|
@ -3184,7 +3184,7 @@ setAclRetry:
|
|||||||
param_offset = offsetof(struct smb_com_transaction2_spi_req,
|
param_offset = offsetof(struct smb_com_transaction2_spi_req,
|
||||||
InformationLevel) - 4;
|
InformationLevel) - 4;
|
||||||
offset = param_offset + params;
|
offset = param_offset + params;
|
||||||
parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
|
parm_data = ((char *)pSMB) + sizeof(pSMB->hdr.smb_buf_length) + offset;
|
||||||
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
||||||
|
|
||||||
/* convert to on the wire format for POSIX ACL */
|
/* convert to on the wire format for POSIX ACL */
|
||||||
|
@ -60,7 +60,7 @@ extern bool disable_legacy_dialects;
|
|||||||
#define TLINK_IDLE_EXPIRE (600 * HZ)
|
#define TLINK_IDLE_EXPIRE (600 * HZ)
|
||||||
|
|
||||||
/* Drop the connection to not overload the server */
|
/* Drop the connection to not overload the server */
|
||||||
#define NUM_STATUS_IO_TIMEOUT 5
|
#define MAX_STATUS_IO_TIMEOUT 5
|
||||||
|
|
||||||
static int ip_connect(struct TCP_Server_Info *server);
|
static int ip_connect(struct TCP_Server_Info *server);
|
||||||
static int generic_ip_connect(struct TCP_Server_Info *server);
|
static int generic_ip_connect(struct TCP_Server_Info *server);
|
||||||
@ -1117,6 +1117,7 @@ cifs_demultiplex_thread(void *p)
|
|||||||
struct mid_q_entry *mids[MAX_COMPOUND];
|
struct mid_q_entry *mids[MAX_COMPOUND];
|
||||||
char *bufs[MAX_COMPOUND];
|
char *bufs[MAX_COMPOUND];
|
||||||
unsigned int noreclaim_flag, num_io_timeout = 0;
|
unsigned int noreclaim_flag, num_io_timeout = 0;
|
||||||
|
bool pending_reconnect = false;
|
||||||
|
|
||||||
noreclaim_flag = memalloc_noreclaim_save();
|
noreclaim_flag = memalloc_noreclaim_save();
|
||||||
cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current));
|
cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current));
|
||||||
@ -1156,6 +1157,8 @@ cifs_demultiplex_thread(void *p)
|
|||||||
cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length);
|
cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length);
|
||||||
if (!is_smb_response(server, buf[0]))
|
if (!is_smb_response(server, buf[0]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
pending_reconnect = false;
|
||||||
next_pdu:
|
next_pdu:
|
||||||
server->pdu_size = pdu_length;
|
server->pdu_size = pdu_length;
|
||||||
|
|
||||||
@ -1213,10 +1216,13 @@ next_pdu:
|
|||||||
if (server->ops->is_status_io_timeout &&
|
if (server->ops->is_status_io_timeout &&
|
||||||
server->ops->is_status_io_timeout(buf)) {
|
server->ops->is_status_io_timeout(buf)) {
|
||||||
num_io_timeout++;
|
num_io_timeout++;
|
||||||
if (num_io_timeout > NUM_STATUS_IO_TIMEOUT) {
|
if (num_io_timeout > MAX_STATUS_IO_TIMEOUT) {
|
||||||
cifs_reconnect(server, false);
|
cifs_server_dbg(VFS,
|
||||||
|
"Number of request timeouts exceeded %d. Reconnecting",
|
||||||
|
MAX_STATUS_IO_TIMEOUT);
|
||||||
|
|
||||||
|
pending_reconnect = true;
|
||||||
num_io_timeout = 0;
|
num_io_timeout = 0;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1226,9 +1232,14 @@ next_pdu:
|
|||||||
if (mids[i] != NULL) {
|
if (mids[i] != NULL) {
|
||||||
mids[i]->resp_buf_size = server->pdu_size;
|
mids[i]->resp_buf_size = server->pdu_size;
|
||||||
|
|
||||||
if (bufs[i] && server->ops->is_network_name_deleted)
|
if (bufs[i] != NULL) {
|
||||||
server->ops->is_network_name_deleted(bufs[i],
|
if (server->ops->is_network_name_deleted &&
|
||||||
server);
|
server->ops->is_network_name_deleted(bufs[i],
|
||||||
|
server)) {
|
||||||
|
cifs_server_dbg(FYI,
|
||||||
|
"Share deleted. Reconnect needed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!mids[i]->multiRsp || mids[i]->multiEnd)
|
if (!mids[i]->multiRsp || mids[i]->multiEnd)
|
||||||
mids[i]->callback(mids[i]);
|
mids[i]->callback(mids[i]);
|
||||||
@ -1263,6 +1274,11 @@ next_pdu:
|
|||||||
buf = server->smallbuf;
|
buf = server->smallbuf;
|
||||||
goto next_pdu;
|
goto next_pdu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* do this reconnect at the very end after processing all MIDs */
|
||||||
|
if (pending_reconnect)
|
||||||
|
cifs_reconnect(server, true);
|
||||||
|
|
||||||
} /* end while !EXITING */
|
} /* end while !EXITING */
|
||||||
|
|
||||||
/* buffer usually freed in free_mid - need to free it here on exit */
|
/* buffer usually freed in free_mid - need to free it here on exit */
|
||||||
|
@ -66,6 +66,12 @@ static int get_session(struct cifs_mount_ctx *mnt_ctx, const char *full_path)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Track individual DFS referral servers used by new DFS mount.
|
||||||
|
*
|
||||||
|
* On success, their lifetime will be shared by final tcon (dfs_ses_list).
|
||||||
|
* Otherwise, they will be put by dfs_put_root_smb_sessions() in cifs_mount().
|
||||||
|
*/
|
||||||
static int add_root_smb_session(struct cifs_mount_ctx *mnt_ctx)
|
static int add_root_smb_session(struct cifs_mount_ctx *mnt_ctx)
|
||||||
{
|
{
|
||||||
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
|
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
|
||||||
@ -80,11 +86,12 @@ static int add_root_smb_session(struct cifs_mount_ctx *mnt_ctx)
|
|||||||
INIT_LIST_HEAD(&root_ses->list);
|
INIT_LIST_HEAD(&root_ses->list);
|
||||||
|
|
||||||
spin_lock(&cifs_tcp_ses_lock);
|
spin_lock(&cifs_tcp_ses_lock);
|
||||||
ses->ses_count++;
|
cifs_smb_ses_inc_refcount(ses);
|
||||||
spin_unlock(&cifs_tcp_ses_lock);
|
spin_unlock(&cifs_tcp_ses_lock);
|
||||||
root_ses->ses = ses;
|
root_ses->ses = ses;
|
||||||
list_add_tail(&root_ses->list, &mnt_ctx->dfs_ses_list);
|
list_add_tail(&root_ses->list, &mnt_ctx->dfs_ses_list);
|
||||||
}
|
}
|
||||||
|
/* Select new DFS referral server so that new referrals go through it */
|
||||||
ctx->dfs_root_ses = ses;
|
ctx->dfs_root_ses = ses;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -242,7 +249,6 @@ out:
|
|||||||
int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
|
int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
|
||||||
{
|
{
|
||||||
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
|
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
|
||||||
struct cifs_ses *ses;
|
|
||||||
bool nodfs = ctx->nodfs;
|
bool nodfs = ctx->nodfs;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@ -276,20 +282,8 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
*isdfs = true;
|
*isdfs = true;
|
||||||
/*
|
add_root_smb_session(mnt_ctx);
|
||||||
* Prevent DFS root session of being put in the first call to
|
return __dfs_mount_share(mnt_ctx);
|
||||||
* cifs_mount_put_conns(). If another DFS root server was not found
|
|
||||||
* while chasing the referrals (@ctx->dfs_root_ses == @ses), then we
|
|
||||||
* can safely put extra refcount of @ses.
|
|
||||||
*/
|
|
||||||
ses = mnt_ctx->ses;
|
|
||||||
mnt_ctx->ses = NULL;
|
|
||||||
mnt_ctx->server = NULL;
|
|
||||||
rc = __dfs_mount_share(mnt_ctx);
|
|
||||||
if (ses == ctx->dfs_root_ses)
|
|
||||||
cifs_put_smb_ses(ses);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update dfs referral path of superblock */
|
/* Update dfs referral path of superblock */
|
||||||
|
@ -1080,8 +1080,8 @@ int cifs_close(struct inode *inode, struct file *file)
|
|||||||
cfile = file->private_data;
|
cfile = file->private_data;
|
||||||
file->private_data = NULL;
|
file->private_data = NULL;
|
||||||
dclose = kmalloc(sizeof(struct cifs_deferred_close), GFP_KERNEL);
|
dclose = kmalloc(sizeof(struct cifs_deferred_close), GFP_KERNEL);
|
||||||
if ((cinode->oplock == CIFS_CACHE_RHW_FLG) &&
|
if ((cifs_sb->ctx->closetimeo && cinode->oplock == CIFS_CACHE_RHW_FLG)
|
||||||
cinode->lease_granted &&
|
&& cinode->lease_granted &&
|
||||||
!test_bit(CIFS_INO_CLOSE_ON_LOCK, &cinode->flags) &&
|
!test_bit(CIFS_INO_CLOSE_ON_LOCK, &cinode->flags) &&
|
||||||
dclose) {
|
dclose) {
|
||||||
if (test_and_clear_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) {
|
if (test_and_clear_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) {
|
||||||
|
@ -2395,7 +2395,7 @@ smb2_is_status_io_timeout(char *buf)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static bool
|
||||||
smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
|
smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
|
||||||
{
|
{
|
||||||
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
|
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
|
||||||
@ -2404,7 +2404,7 @@ smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
|
|||||||
struct cifs_tcon *tcon;
|
struct cifs_tcon *tcon;
|
||||||
|
|
||||||
if (shdr->Status != STATUS_NETWORK_NAME_DELETED)
|
if (shdr->Status != STATUS_NETWORK_NAME_DELETED)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
/* If server is a channel, select the primary channel */
|
/* If server is a channel, select the primary channel */
|
||||||
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
|
pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||||
@ -2419,11 +2419,13 @@ smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
|
|||||||
spin_unlock(&cifs_tcp_ses_lock);
|
spin_unlock(&cifs_tcp_ses_lock);
|
||||||
pr_warn_once("Server share %s deleted.\n",
|
pr_warn_once("Server share %s deleted.\n",
|
||||||
tcon->tree_name);
|
tcon->tree_name);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock(&cifs_tcp_ses_lock);
|
spin_unlock(&cifs_tcp_ses_lock);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -160,7 +160,7 @@ smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
|
|||||||
spin_unlock(&ses->ses_lock);
|
spin_unlock(&ses->ses_lock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
++ses->ses_count;
|
cifs_smb_ses_inc_refcount(ses);
|
||||||
spin_unlock(&ses->ses_lock);
|
spin_unlock(&ses->ses_lock);
|
||||||
return ses;
|
return ses;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user