Skip to content

Commit 4cd8546

Browse files
author
CKI KWF Bot
committed
Merge: smb: client: handle lack of IPC in dfs_cache_refresh() [rhel-9.8]
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/7556 - handle lack of IPC in dfs_cache_refresh() JIRA: https://issues.redhat.com/browse/RHEL-119582 Signed-off-by: Paulo Alcantara <paalcant@redhat.com> Approved-by: Jay Shin <jaeshin@redhat.com> Approved-by: David Howells <dhowells@redhat.com> Approved-by: Scott Mayhew <smayhew@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
2 parents ca5bfda + caa0ac9 commit 4cd8546

File tree

3 files changed

+66
-29
lines changed

3 files changed

+66
-29
lines changed

fs/smb/client/cifsproto.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,8 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
600600
extern struct TCP_Server_Info *
601601
cifs_find_tcp_session(struct smb3_fs_context *ctx);
602602

603+
struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal);
604+
603605
void __cifs_put_smb_ses(struct cifs_ses *ses);
604606

605607
extern struct cifs_ses *

fs/smb/client/connect.c

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2017,39 +2017,31 @@ static int match_session(struct cifs_ses *ses,
20172017
/**
20182018
* cifs_setup_ipc - helper to setup the IPC tcon for the session
20192019
* @ses: smb session to issue the request on
2020-
* @ctx: the superblock configuration context to use for building the
2021-
* new tree connection for the IPC (interprocess communication RPC)
2020+
* @seal: if encryption is requested
20222021
*
20232022
* A new IPC connection is made and stored in the session
20242023
* tcon_ipc. The IPC tcon has the same lifetime as the session.
20252024
*/
2026-
static int
2027-
cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
2025+
struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal)
20282026
{
20292027
int rc = 0, xid;
20302028
struct cifs_tcon *tcon;
20312029
char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0};
2032-
bool seal = false;
20332030
struct TCP_Server_Info *server = ses->server;
20342031

20352032
/*
20362033
* If the mount request that resulted in the creation of the
20372034
* session requires encryption, force IPC to be encrypted too.
20382035
*/
2039-
if (ctx->seal) {
2040-
if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)
2041-
seal = true;
2042-
else {
2043-
cifs_server_dbg(VFS,
2044-
"IPC: server doesn't support encryption\n");
2045-
return -EOPNOTSUPP;
2046-
}
2036+
if (seal && !(server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) {
2037+
cifs_server_dbg(VFS, "IPC: server doesn't support encryption\n");
2038+
return ERR_PTR(-EOPNOTSUPP);
20472039
}
20482040

20492041
/* no need to setup directory caching on IPC share, so pass in false */
20502042
tcon = tcon_info_alloc(false, netfs_trace_tcon_ref_new_ipc);
20512043
if (tcon == NULL)
2052-
return -ENOMEM;
2044+
return ERR_PTR(-ENOMEM);
20532045

20542046
spin_lock(&server->srv_lock);
20552047
scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname);
@@ -2059,23 +2051,21 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
20592051
tcon->ses = ses;
20602052
tcon->ipc = true;
20612053
tcon->seal = seal;
2062-
rc = server->ops->tree_connect(xid, ses, unc, tcon, ctx->local_nls);
2054+
rc = server->ops->tree_connect(xid, ses, unc, tcon, ses->local_nls);
20632055
free_xid(xid);
20642056

20652057
if (rc) {
2066-
cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc);
2058+
cifs_server_dbg(VFS | ONCE, "failed to connect to IPC (rc=%d)\n", rc);
20672059
tconInfoFree(tcon, netfs_trace_tcon_ref_free_ipc_fail);
2068-
goto out;
2060+
return ERR_PTR(rc);
20692061
}
20702062

20712063
cifs_dbg(FYI, "IPC tcon rc=%d ipc tid=0x%x\n", rc, tcon->tid);
20722064

20732065
spin_lock(&tcon->tc_lock);
20742066
tcon->status = TID_GOOD;
20752067
spin_unlock(&tcon->tc_lock);
2076-
ses->tcon_ipc = tcon;
2077-
out:
2078-
return rc;
2068+
return tcon;
20792069
}
20802070

20812071
static struct cifs_ses *
@@ -2349,6 +2339,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
23492339
{
23502340
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
23512341
struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
2342+
struct cifs_tcon *ipc;
23522343
struct cifs_ses *ses;
23532344
unsigned int xid;
23542345
int retries = 0;
@@ -2527,7 +2518,12 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
25272518
list_add(&ses->smb_ses_list, &server->smb_ses_list);
25282519
spin_unlock(&cifs_tcp_ses_lock);
25292520

2530-
cifs_setup_ipc(ses, ctx);
2521+
ipc = cifs_setup_ipc(ses, ctx->seal);
2522+
spin_lock(&cifs_tcp_ses_lock);
2523+
spin_lock(&ses->ses_lock);
2524+
ses->tcon_ipc = !IS_ERR(ipc) ? ipc : NULL;
2525+
spin_unlock(&ses->ses_lock);
2526+
spin_unlock(&cifs_tcp_ses_lock);
25312527

25322528
free_xid(xid);
25332529

fs/smb/client/dfs_cache.c

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,24 +1120,63 @@ static bool target_share_equal(struct cifs_tcon *tcon, const char *s1)
11201120
return match;
11211121
}
11221122

1123-
static bool is_ses_good(struct cifs_ses *ses)
1123+
static bool is_ses_good(struct cifs_tcon *tcon, struct cifs_ses *ses)
11241124
{
11251125
struct TCP_Server_Info *server = ses->server;
1126-
struct cifs_tcon *tcon = ses->tcon_ipc;
1126+
struct cifs_tcon *ipc = NULL;
11271127
bool ret;
11281128

1129+
spin_lock(&cifs_tcp_ses_lock);
11291130
spin_lock(&ses->ses_lock);
11301131
spin_lock(&ses->chan_lock);
1132+
11311133
ret = !cifs_chan_needs_reconnect(ses, server) &&
1132-
ses->ses_status == SES_GOOD &&
1133-
!tcon->need_reconnect;
1134+
ses->ses_status == SES_GOOD;
1135+
11341136
spin_unlock(&ses->chan_lock);
1137+
1138+
if (!ret)
1139+
goto out;
1140+
1141+
if (likely(ses->tcon_ipc)) {
1142+
if (ses->tcon_ipc->need_reconnect) {
1143+
ret = false;
1144+
goto out;
1145+
}
1146+
} else {
1147+
spin_unlock(&ses->ses_lock);
1148+
spin_unlock(&cifs_tcp_ses_lock);
1149+
1150+
ipc = cifs_setup_ipc(ses, tcon->seal);
1151+
1152+
spin_lock(&cifs_tcp_ses_lock);
1153+
spin_lock(&ses->ses_lock);
1154+
if (!IS_ERR(ipc)) {
1155+
if (!ses->tcon_ipc) {
1156+
ses->tcon_ipc = ipc;
1157+
ipc = NULL;
1158+
}
1159+
} else {
1160+
ret = false;
1161+
ipc = NULL;
1162+
}
1163+
}
1164+
1165+
out:
11351166
spin_unlock(&ses->ses_lock);
1167+
spin_unlock(&cifs_tcp_ses_lock);
1168+
if (ipc && server->ops->tree_disconnect) {
1169+
unsigned int xid = get_xid();
1170+
1171+
(void)server->ops->tree_disconnect(xid, ipc);
1172+
_free_xid(xid);
1173+
}
1174+
tconInfoFree(ipc, netfs_trace_tcon_ref_free_ipc);
11361175
return ret;
11371176
}
11381177

11391178
/* Refresh dfs referral of @ses */
1140-
static void refresh_ses_referral(struct cifs_ses *ses)
1179+
static void refresh_ses_referral(struct cifs_tcon *tcon, struct cifs_ses *ses)
11411180
{
11421181
struct cache_entry *ce;
11431182
unsigned int xid;
@@ -1153,7 +1192,7 @@ static void refresh_ses_referral(struct cifs_ses *ses)
11531192
}
11541193

11551194
ses = CIFS_DFS_ROOT_SES(ses);
1156-
if (!is_ses_good(ses)) {
1195+
if (!is_ses_good(tcon, ses)) {
11571196
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n",
11581197
__func__);
11591198
goto out;
@@ -1241,7 +1280,7 @@ static void refresh_tcon_referral(struct cifs_tcon *tcon, bool force_refresh)
12411280
up_read(&htable_rw_lock);
12421281

12431282
ses = CIFS_DFS_ROOT_SES(ses);
1244-
if (!is_ses_good(ses)) {
1283+
if (!is_ses_good(tcon, ses)) {
12451284
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n",
12461285
__func__);
12471286
goto out;
@@ -1309,7 +1348,7 @@ void dfs_cache_refresh(struct work_struct *work)
13091348
tcon = container_of(work, struct cifs_tcon, dfs_cache_work.work);
13101349

13111350
list_for_each_entry(ses, &tcon->dfs_ses_list, dlist)
1312-
refresh_ses_referral(ses);
1351+
refresh_ses_referral(tcon, ses);
13131352
refresh_tcon_referral(tcon, false);
13141353

13151354
queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,

0 commit comments

Comments
 (0)