From patchwork Wed May 3 22:21:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paulo Alcantara X-Patchwork-Id: 13230594 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1E094C7EE22 for ; Wed, 3 May 2023 22:21:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229698AbjECWVv (ORCPT ); Wed, 3 May 2023 18:21:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35508 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229559AbjECWVt (ORCPT ); Wed, 3 May 2023 18:21:49 -0400 Received: from mx.manguebit.com (mx.manguebit.com [IPv6:2a01:4f8:1c1e:a2ae::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C38238692; Wed, 3 May 2023 15:21:43 -0700 (PDT) From: Paulo Alcantara DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=manguebit.com; s=dkim; t=1683152502; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3gI/91qtA5iwgjzI2yC9NwpCVjUdMgAvpLzhHmundRI=; b=rE8n7f8rdDxMoVg+6QC/8LZZa8J7w37O5HyWDM7PqG+qyXbqm+l0d+vHhOANnE7TUk/YMx PvyiUjAuTjRNg+l30gvOT74WKQ3r0mkqNlYTxgBDL3Lskkm12ycoov5gl5HsXmpl1n6yP2 eD6VRHcJzS61lvhjbp41Ab0KTpd+45mSvaltFXXqGnVGpVKceWfep5nzLRzH8Gqs+NyK3D ynuto4ksxrQveEJbQlebxNfRGJw+QvuvpnoN2NjneiqJlsFPGYDnEDavTXQMeaB2bkElNk 7YqZ1xapg0ONIzmezYd6gUZW/aZal4hvAeF+Epq3rguVKiTsFFTitYziXKjPBQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=manguebit.com; s=dkim; t=1683152502; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3gI/91qtA5iwgjzI2yC9NwpCVjUdMgAvpLzhHmundRI=; b=e9/HzlZvqNBXgP3NWXBMAx7cr4pGYMAZz/DsKD8w+yS3psJ7ryjX++flVU0GAd0ytjSU5g Trl52TOV+iRZvzOEANSbbCNopJ/rBp/kKmlCGati+SkoGp5I2SAb0glronXhUH6hFNS0Ht gZnAfycUSv2LbyRFGzoGSyjDL14p1KTNuB4JN1l+oirB6KuReKk1A7lQ5WE5pz+Gl1Wkoe uRrpI8h35pZKfLdCV+u7H/Ie/kOcZtB58hhj7l5hxqA4ujDtkdFVh7RGyqswxN12iB3v+B ZsFtn7aqaT/28bjIJM55p52KNxsVEy3TA19saG+7orb54NSvElMyueAQl6rrZg== ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pc@manguebit.com smtp.mailfrom=pc@manguebit.com ARC-Seal: i=1; s=dkim; d=manguebit.com; t=1683152502; a=rsa-sha256; cv=none; b=Hr7fcUD2AvwCwsNMvo89L9bVXdsY1NM0LOUwZ8bDzMcKPy3KH0YCtWMpPrbMPGNja5v0nw LWaw8Q9UJi03qpoFF8kkV++uYXXCeFGRh5pZqD8p3I/6Gkt1zRfYv0QYkw4LXC74XVjOz8 AzAoQetJ/SLPOUSF0Dh57JoQp7GFIFfbOwvmL28BJ83OkPgdAt5KZr0YDCv3SMdbcLA7hc nsTl8hUVAtTk3S34XEZdDqpsnyNqKUJgVzcWlNTl/CCYhL7UfqM6RlLQQKlgXZTbU01yjl WnwGinZk+Z+05ys83CM9jL5FCbM2LNhK+q1eE+kgbwrkOePzBfJ4O6DgG875WQ== To: smfrench@gmail.com Cc: linux-cifs@vger.kernel.org, Paulo Alcantara , stable@vger.kernel.org Subject: [PATCH 1/7] cifs: fix potential race when tree connecting ipc Date: Wed, 3 May 2023 19:21:11 -0300 Message-Id: <20230503222117.7609-2-pc@manguebit.com> In-Reply-To: <20230503222117.7609-1-pc@manguebit.com> References: <20230503222117.7609-1-pc@manguebit.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Protect access of TCP_Server_Info::hostname when building the ipc tree name as it might get freed in cifsd thread and thus causing an use-after-free bug in __tree_connect_dfs_target(). Also, while at it, update status of IPC tcon on success and then avoid any extra tree connects. Cc: stable@vger.kernel.org # v6.2+ Signed-off-by: Paulo Alcantara (SUSE) --- fs/cifs/dfs.c | 57 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/fs/cifs/dfs.c b/fs/cifs/dfs.c index 3a11716b6e13..37f7da4f5c8b 100644 --- a/fs/cifs/dfs.c +++ b/fs/cifs/dfs.c @@ -374,6 +374,54 @@ static int target_share_matches_server(struct TCP_Server_Info *server, char *sha return rc; } +static void __tree_connect_ipc(const unsigned int xid, char *tree, + struct cifs_sb_info *cifs_sb, + struct cifs_ses *ses) +{ + struct TCP_Server_Info *server = ses->server; + struct cifs_tcon *tcon = ses->tcon_ipc; + int rc; + + spin_lock(&ses->ses_lock); + spin_lock(&ses->chan_lock); + if (cifs_chan_needs_reconnect(ses, server) || + ses->ses_status != SES_GOOD) { + spin_unlock(&ses->chan_lock); + spin_unlock(&ses->ses_lock); + cifs_server_dbg(FYI, "%s: skipping ipc reconnect due to disconnected ses\n", + __func__); + return; + } + spin_unlock(&ses->chan_lock); + spin_unlock(&ses->ses_lock); + + cifs_server_lock(server); + scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname); + cifs_server_unlock(server); + + rc = server->ops->tree_connect(xid, ses, tree, tcon, + cifs_sb->local_nls); + cifs_server_dbg(FYI, "%s: tree_reconnect %s: %d\n", __func__, tree, rc); + spin_lock(&tcon->tc_lock); + if (rc) { + tcon->status = TID_NEED_TCON; + } else { + tcon->status = TID_GOOD; + tcon->need_reconnect = false; + } + spin_unlock(&tcon->tc_lock); +} + +static void tree_connect_ipc(const unsigned int xid, char *tree, + struct cifs_sb_info *cifs_sb, + struct cifs_tcon *tcon) +{ + struct cifs_ses *ses = tcon->ses; + + __tree_connect_ipc(xid, tree, cifs_sb, ses); + __tree_connect_ipc(xid, tree, cifs_sb, CIFS_DFS_ROOT_SES(ses)); +} + static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, char *tree, bool islink, struct dfs_cache_tgt_list *tl) @@ -382,7 +430,6 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t struct TCP_Server_Info *server = tcon->ses->server; const struct smb_version_operations *ops = server->ops; struct cifs_ses *root_ses = CIFS_DFS_ROOT_SES(tcon->ses); - struct cifs_tcon *ipc = root_ses->tcon_ipc; char *share = NULL, *prefix = NULL; struct dfs_cache_tgt_iterator *tit; bool target_match; @@ -418,18 +465,14 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t } dfs_cache_noreq_update_tgthint(server->current_fullpath + 1, tit); - - if (ipc->need_reconnect) { - scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname); - rc = ops->tree_connect(xid, ipc->ses, tree, ipc, cifs_sb->local_nls); - cifs_dbg(FYI, "%s: reconnect ipc: %d\n", __func__, rc); - } + tree_connect_ipc(xid, tree, cifs_sb, tcon); scnprintf(tree, MAX_TREE_SIZE, "\\%s", share); if (!islink) { rc = ops->tree_connect(xid, tcon->ses, tree, tcon, cifs_sb->local_nls); break; } + /* * If no dfs referrals were returned from link target, then just do a TREE_CONNECT * to it. Otherwise, cache the dfs referral and then mark current tcp ses for From patchwork Wed May 3 22:21:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paulo Alcantara X-Patchwork-Id: 13230593 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 40779C77B78 for ; Wed, 3 May 2023 22:21:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229660AbjECWVu (ORCPT ); Wed, 3 May 2023 18:21:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35510 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229698AbjECWVt (ORCPT ); Wed, 3 May 2023 18:21:49 -0400 Received: from mx.manguebit.com (mx.manguebit.com [IPv6:2a01:4f8:1c1e:a2ae::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 803BF86AF; Wed, 3 May 2023 15:21:46 -0700 (PDT) From: Paulo Alcantara DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=manguebit.com; s=dkim; t=1683152504; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3g5IO8InvMRPr8FhO3Z+GAsFOn6xR+kM33bQtusDEGA=; b=XUnRbY/fejBRrAI+D9bVY5LjhQq4SESW9jNEj4FEYXdQU6LfZzVdBOSo8vyUr6ggMfym7D 1rJZjHmtY2NDg33lZuoQTs01yHgIWWGDaD/FXmkpX5zA4NoE8NE8/Jrx1HEaV4kS+UG0Aq jezXKHSiEDo6mYt1tgjrfYa/JX3AtcuK0k7K4dsYJZJwLEusTebnTeD0JjVDDlYy+fZRhZ nPO/g0oHmLKiIPSIIsnNfZxjC958a+8L578l+Ui/Jtk9u8KAx3V7EkKDZ3Htv34QGa7tM8 XEfPzmURoxtV+rzcGhAB+rC9Qc1QC4D7dFopbt1A0upPKTcxVZfjM1Q+jVR2Pw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=manguebit.com; s=dkim; t=1683152504; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3g5IO8InvMRPr8FhO3Z+GAsFOn6xR+kM33bQtusDEGA=; b=XUapIKSV1g7hpVaJTlfZZ1Tr+NaXYSqwG9wgZcFeCVxt6+O9zr8r593aD2k7q6t5JZ9/xm rEtqX+wl0M+j0RgQ5PMybaGypT2yQE4aTuTCaoHtFSA8EU/Y84Ii4vHBf1jF8UxVrIafNF IFa5H9XkS4m/v9/3z1F49+Gm73227orzDg30j9sEw6qbt+tE03j8dbvel2K7Dq+jW48TjB d15pvMCS3bCG197cplYXTKX24dhSBD+MHuTXrs7iOnModtHG2/3z0vAoygSKOTfYCFcOc8 GO8RAZ6bC0aLNylkrwYQxC76ym57FZbcDUT/q79C7jtv+gcWfSaTzlI+j+E/1g== ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pc@manguebit.com smtp.mailfrom=pc@manguebit.com ARC-Seal: i=1; s=dkim; d=manguebit.com; t=1683152504; a=rsa-sha256; cv=none; b=HQSj3YemaLvGNBZ6h7JQX+7/2Ajkmml5OO5/quPlyBubnNvXOOvQhZhW3HsYOjpDU0HyGH rzl/E1rP1z1kv6esfgnyITpBMTv41XUadlHne5NcYLo/okzGM4ILwfjlJVeuEfIcEAtYJ2 Kj2afI/y8Iygy1kCR5jrxNgKu5abCf5D1xJwpfGRbO0WGJ6I2h65qpMm02FGvMQ/WFPoXo fJcSms2+j2A9dJw1uNhdKspVYybtk9+/LQ29clySXhlbT6ySyniDikdIQmCdZbCTDTcHCw KYkDCWVnPiw8nHaBf8beCUW7KmtHj/TE8PrPOSeJ4k03IO+L0btNKCi9fd4whg== To: smfrench@gmail.com Cc: linux-cifs@vger.kernel.org, Paulo Alcantara , stable@vger.kernel.org Subject: [PATCH 2/7] cifs: fix potential use-after-free bugs in TCP_Server_Info::hostname Date: Wed, 3 May 2023 19:21:12 -0300 Message-Id: <20230503222117.7609-3-pc@manguebit.com> In-Reply-To: <20230503222117.7609-1-pc@manguebit.com> References: <20230503222117.7609-1-pc@manguebit.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org TCP_Server_Info::hostname may be updated once or many times during reconnect, so protect its access outside reconnect path as well and then prevent any potential use-after-free bugs. Cc: stable@vger.kernel.org Signed-off-by: Paulo Alcantara (SUSE) --- fs/cifs/cifs_debug.c | 7 ++++++- fs/cifs/cifs_debug.h | 12 ++++++------ fs/cifs/connect.c | 10 +++++++--- fs/cifs/sess.c | 7 ++++--- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index e9c8c088d948..d4ed200a9471 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -280,8 +280,10 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) seq_printf(m, "\n%d) ConnectionId: 0x%llx ", c, server->conn_id); + spin_lock(&server->srv_lock); if (server->hostname) seq_printf(m, "Hostname: %s ", server->hostname); + spin_unlock(&server->srv_lock); #ifdef CONFIG_CIFS_SMB_DIRECT if (!server->rdma) goto skip_rdma; @@ -623,10 +625,13 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) server->fastest_cmd[j], server->slowest_cmd[j]); for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++) - if (atomic_read(&server->smb2slowcmd[j])) + if (atomic_read(&server->smb2slowcmd[j])) { + spin_lock(&server->srv_lock); seq_printf(m, " %d slow responses from %s for command %d\n", atomic_read(&server->smb2slowcmd[j]), server->hostname, j); + spin_unlock(&server->srv_lock); + } #endif /* STATS2 */ list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h index d44808263cfb..ce5cfd236fdb 100644 --- a/fs/cifs/cifs_debug.h +++ b/fs/cifs/cifs_debug.h @@ -81,19 +81,19 @@ do { \ #define cifs_server_dbg_func(ratefunc, type, fmt, ...) \ do { \ - const char *sn = ""; \ - if (server && server->hostname) \ - sn = server->hostname; \ + spin_lock(&server->srv_lock); \ if ((type) & FYI && cifsFYI & CIFS_INFO) { \ pr_debug_ ## ratefunc("%s: \\\\%s " fmt, \ - __FILE__, sn, ##__VA_ARGS__); \ + __FILE__, server->hostname, \ + ##__VA_ARGS__); \ } else if ((type) & VFS) { \ pr_err_ ## ratefunc("VFS: \\\\%s " fmt, \ - sn, ##__VA_ARGS__); \ + server->hostname, ##__VA_ARGS__); \ } else if ((type) & NOISY && (NOISY != 0)) { \ pr_debug_ ## ratefunc("\\\\%s " fmt, \ - sn, ##__VA_ARGS__); \ + server->hostname, ##__VA_ARGS__); \ } \ + spin_unlock(&server->srv_lock); \ } while (0) #define cifs_server_dbg(type, fmt, ...) \ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 1cbb90587995..eee8b31c1eaf 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -403,8 +403,10 @@ static int __reconnect_target_unlocked(struct TCP_Server_Info *server, const cha if (server->hostname != target) { hostname = extract_hostname(target); if (!IS_ERR(hostname)) { + spin_lock(&server->srv_lock); kfree(server->hostname); server->hostname = hostname; + spin_unlock(&server->srv_lock); } else { cifs_dbg(FYI, "%s: couldn't extract hostname or address from dfs target: %ld\n", __func__, PTR_ERR(hostname)); @@ -561,9 +563,7 @@ cifs_echo_request(struct work_struct *work) goto requeue_echo; rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS; - if (rc) - cifs_dbg(FYI, "Unable to send echo request to server: %s\n", - server->hostname); + cifs_server_dbg(FYI, "send echo request: rc = %d\n", rc); /* Check witness registrations */ cifs_swn_check(); @@ -1404,6 +1404,8 @@ static int match_server(struct TCP_Server_Info *server, struct smb3_fs_context * { struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr; + lockdep_assert_held(&server->srv_lock); + if (ctx->nosharesock) return 0; @@ -1810,7 +1812,9 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx) if (tcon == NULL) return -ENOMEM; + spin_lock(&server->srv_lock); scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname); + spin_unlock(&server->srv_lock); xid = get_xid(); tcon->ses = ses; diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index d2cbae4b5d21..335c078c42fb 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -159,6 +159,7 @@ cifs_chan_is_iface_active(struct cifs_ses *ses, /* returns number of channels added */ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) { + struct TCP_Server_Info *server = ses->server; int old_chan_count, new_chan_count; int left; int rc = 0; @@ -178,16 +179,16 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) return 0; } - if (ses->server->dialect < SMB30_PROT_ID) { + if (server->dialect < SMB30_PROT_ID) { spin_unlock(&ses->chan_lock); cifs_dbg(VFS, "multichannel is not supported on this protocol version, use 3.0 or above\n"); return 0; } - if (!(ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) { + if (!(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) { ses->chan_max = 1; spin_unlock(&ses->chan_lock); - cifs_dbg(VFS, "server %s does not support multichannel\n", ses->server->hostname); + cifs_server_dbg(VFS, "no multichannel support\n"); return 0; } spin_unlock(&ses->chan_lock); From patchwork Wed May 3 22:21:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paulo Alcantara X-Patchwork-Id: 13230595 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 93931C7EE2C for ; Wed, 3 May 2023 22:21:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229559AbjECWVv (ORCPT ); Wed, 3 May 2023 18:21:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35492 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229713AbjECWVt (ORCPT ); Wed, 3 May 2023 18:21:49 -0400 Received: from mx.manguebit.com (mx.manguebit.com [IPv6:2a01:4f8:1c1e:a2ae::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D80267D8E; Wed, 3 May 2023 15:21:48 -0700 (PDT) From: Paulo Alcantara DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=manguebit.com; s=dkim; t=1683152507; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rDyRVZwOQAjEEnKyBT8vMShxV4eGFJEG2e1sZvcJu8M=; b=s9+8pfyGDIb/WMrgKFw+x1wg8VgWieU7Jy9NquSrK5K3HKPNasLW+JFsn3MG5/q78TqXYI aW5/jY5ccqppB5tO0PdY9Apq9Lfz+B9BVbaIrVbg3VtqX6R5SjwDBcgSS7QtLgbAw+qEq8 T+znweb0lFPkmu90EEM1CXJBN3uWl/g06RFwOq8zVscwZ3lG8fJFBwoyIjQF1oesFMxbIf 2H126HBjDBp/gmVrIDqr7hZwGG8ULqxiFneJfty876TulVVypnw7QZPQuUWN+WrnL4pZRw Ncn62sO/rqqlGN6gzD4g/wA2y9gePvkr6Em410rozDy0osuSdvbpIGkNLgm8TA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=manguebit.com; s=dkim; t=1683152507; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rDyRVZwOQAjEEnKyBT8vMShxV4eGFJEG2e1sZvcJu8M=; b=G841ZMZ4otPDl7nODSv/KKKJsXYo0vtDz4HeYa0QOifkcR9V97h0idKU/hgZOQE7BEPx7b UPO/8BBA/SSGYg4OQvENMY7HwGScKKgriWHH+15l391ofVF2UCoswsnKEfYvGfA3NYGrEB cGPyrzMzIlpUg6P56kQboj1fvVynZG4eqwccwI9ZvDICRZof6EC160H85RzFyaOlyqisbM 5TedUNOt3Mprtixqy44knTc82rLMtcKdbOszRsJNrH+dqwn6tWx00aSFSYScePNZnKyj/Q rMZY0wIZuRYy9AT2JI4Dgq229UYIznY1XNmb8OmtVWKb2ueVbgh1mfVVOpfRyA== ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pc@manguebit.com smtp.mailfrom=pc@manguebit.com ARC-Seal: i=1; s=dkim; d=manguebit.com; t=1683152507; a=rsa-sha256; cv=none; b=pRSBdtcylnArF6uaa/FKlbOWANdDU+/Mui/qjN8OQJRWuYrF4Rc8jt94Pul0PSLIQngnpk IrhfYkhcdgEgYxtq0N8FOUp99J/j3ZifD6LhDemDcSLUQ2x/pFkPW8E2vZO343evlz4Scr qPcstIpbe7tt8VfHjFj6ac7bSlIDDcOikhCdWJcb8aW0kz0Vb4GpP/wQtDRS3cflPMsWUQ 8fPsa3zzlCl4kgSQI9uCmdDXiyInDq7p/mQAXNDcDMkR3onoywhp+JbCJ86dZyE3IaOKS+ XzIHDSSN4eNHOQYBaJIHDHS7O9lq74/ABiI2tmFUEx7puIiLFCuf74jPRiAZ3Q== To: smfrench@gmail.com Cc: linux-cifs@vger.kernel.org, Paulo Alcantara , stable@vger.kernel.org Subject: [PATCH 3/7] cifs: protect session status check in smb2_reconnect() Date: Wed, 3 May 2023 19:21:13 -0300 Message-Id: <20230503222117.7609-4-pc@manguebit.com> In-Reply-To: <20230503222117.7609-1-pc@manguebit.com> References: <20230503222117.7609-1-pc@manguebit.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Use @ses->ses_lock to protect access of @ses->ses_status. Cc: stable@vger.kernel.org Signed-off-by: Paulo Alcantara (SUSE) --- fs/cifs/smb2pdu.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 4245249dbba8..6a9661f3d324 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -175,8 +175,17 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, } } spin_unlock(&tcon->tc_lock); - if ((!tcon->ses) || (tcon->ses->ses_status == SES_EXITING) || - (!tcon->ses->server) || !server) + + ses = tcon->ses; + if (!ses) + return -EIO; + spin_lock(&ses->ses_lock); + if (ses->ses_status == SES_EXITING) { + spin_unlock(&ses->ses_lock); + return -EIO; + } + spin_unlock(&ses->ses_lock); + if (!ses->server || !server) return -EIO; spin_lock(&server->srv_lock); @@ -204,8 +213,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, if (rc) return rc; - ses = tcon->ses; - spin_lock(&ses->chan_lock); if (!cifs_chan_needs_reconnect(ses, server) && !tcon->need_reconnect) { spin_unlock(&ses->chan_lock); From patchwork Wed May 3 22:21:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paulo Alcantara X-Patchwork-Id: 13230596 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A70A5C77B75 for ; Wed, 3 May 2023 22:21:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229719AbjECWVy (ORCPT ); Wed, 3 May 2023 18:21:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35582 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229713AbjECWVx (ORCPT ); Wed, 3 May 2023 18:21:53 -0400 Received: from mx.manguebit.com (mx.manguebit.com [167.235.159.17]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7F38483F5 for ; Wed, 3 May 2023 15:21:51 -0700 (PDT) From: Paulo Alcantara DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=manguebit.com; s=dkim; t=1683152509; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9Vd/hSgy1EF/FYLB8WYUS62wsU2EuSqXp/511/3d0Zw=; b=fTUXJcRoBw8i5+i9XKarp7rQHf0nQLOLMZH3OGFBThi9YegOpej2WdkQ9L09VmFLJfvmHb 6w0n86l0Wv00jd2aPMAvjTTAsbW0SIIONzU1GyplqeMtL7lIAQZNLUAm0HAwfp1Nu83Ypt zrp3xp0tAF2BEadeLGKoWB18pOsGBOKC4EjFupkntZDj83DxnSRu6vlvGljg2VbnQ0Lscs mqS1BQ0xP4/yFFBih8jlc9qh0SEXa6YCfygd54jvbZSA6rMDLmQ0VXFtwOx2DIceE8dEyQ WMwk+lCrYHs3/n208Q3Ez5O3M4v15VHDIOzYlt+rBTtlxlwcIP930/TAmmPcHQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=manguebit.com; s=dkim; t=1683152509; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9Vd/hSgy1EF/FYLB8WYUS62wsU2EuSqXp/511/3d0Zw=; b=aXyOUfP6PQY0fTuByZC8ZaB8n4wab6+OSmfEvI7mqtDEUGel6fucuPmrqpeqvqyNv04mk6 jddsLOCsF8i1fwsBrRhaefmcnwwdhheqHCY4oy6dPv7qfLuDQTwMgHFvVJpH1HuTMcme/f A8cuZVvZDWrE2ffDEefcinkSDWdGHGnt7IydsMyuQyBabJ5vwe50Rm+YWrOc5k112RveY9 chOtOaOCLxS+vvY3LYZV6mFUdAYlHGSObwF7yli4Eo2+XkQJVULVOwIfpgktoXBL+d+58O +cC5Xrx7aEcK5wZqQxkqUPldHaWFLLXk+nCo1VBwEEe05TWMMbySxy5mybfbIw== ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pc@manguebit.com smtp.mailfrom=pc@manguebit.com ARC-Seal: i=1; s=dkim; d=manguebit.com; t=1683152509; a=rsa-sha256; cv=none; b=lkeJPKHHUj77c5PQxZhd1Oqn3A1P9B6dvwq2z+KmHxXcN0Oum5Z59QE1F0dWpYw2mUaBCq Ur4acAMqbUaJMzz26k1sU2gZDko2rCQyWrcM7G0uhpA7GY5RTSEV/JO4ITm3RGu9ILwpgR vNLslmwC+Lyl8cnBdySLT+DoglryadU5AzhHHQmvtnbh9mKhGOsWTtuKWeXeknw533/tta q5/vus+HtO8Jv2suGpGwGaO7sErjvcESnvUj//12J4Vj58gF22yLHCBMdZ0r9f1pJIciJN GOhcSHtEuHiaef3HqFNbxXTRRLJsKW1uyAzQ4eJPOojJRegNHTMK53X8jyZrhQ== To: smfrench@gmail.com Cc: linux-cifs@vger.kernel.org, Paulo Alcantara , stable@vger.kernel.org Subject: [PATCH 4/7] cifs: protect access of TCP_Server_Info::{origin,leaf}_fullpath Date: Wed, 3 May 2023 19:21:14 -0300 Message-Id: <20230503222117.7609-5-pc@manguebit.com> In-Reply-To: <20230503222117.7609-1-pc@manguebit.com> References: <20230503222117.7609-1-pc@manguebit.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Protect access of TCP_Server_Info::{origin,leaf}_fullpath when matching DFS connections, and get rid of TCP_Server_Info::current_fullpath while we're at it. Cc: stable@vger.kernel.org # v6.2+ Signed-off-by: Paulo Alcantara (SUSE) --- fs/cifs/cifsglob.h | 20 +++++++++++++------- fs/cifs/connect.c | 10 ++++++---- fs/cifs/dfs.c | 14 ++++++++------ fs/cifs/dfs.h | 13 +++++++++++-- fs/cifs/dfs_cache.c | 6 +++++- 5 files changed, 43 insertions(+), 20 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 08a73dcb7786..a62447404851 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -736,17 +736,23 @@ struct TCP_Server_Info { #endif struct mutex refpath_lock; /* protects leaf_fullpath */ /* - * Canonical DFS full paths that were used to chase referrals in mount and reconnect. + * origin_fullpath: Canonical copy of smb3_fs_context::source. + * It is used for matching existing DFS tcons. * - * origin_fullpath: first or original referral path - * leaf_fullpath: last referral path (might be changed due to nested links in reconnect) + * leaf_fullpath: Canonical DFS referral path related to this + * connection. + * It is used in DFS cache refresher, reconnect and may + * change due to nested DFS links. * - * current_fullpath: pointer to either origin_fullpath or leaf_fullpath - * NOTE: cannot be accessed outside cifs_reconnect() and smb2_reconnect() + * Both protected by @refpath_lock and @srv_lock. The @refpath_lock is + * mosly used for not requiring a copy of @leaf_fullpath when getting + * cached or new DFS referrals (which might also sleep during I/O). + * While @srv_lock is held for making string and NULL comparions against + * both fields as in mount(2) and cache refresh. * - * format: \\HOST\SHARE\[OPTIONAL PATH] + * format: \\HOST\SHARE[\OPTIONAL PATH] */ - char *origin_fullpath, *leaf_fullpath, *current_fullpath; + char *origin_fullpath, *leaf_fullpath; }; static inline bool is_smb1(struct TCP_Server_Info *server) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index eee8b31c1eaf..340bd7cf64f3 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -454,7 +454,6 @@ static int reconnect_target_unlocked(struct TCP_Server_Info *server, struct dfs_ static int reconnect_dfs_server(struct TCP_Server_Info *server) { int rc = 0; - const char *refpath = server->current_fullpath + 1; struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl); struct dfs_cache_tgt_iterator *target_hint = NULL; int num_targets = 0; @@ -467,8 +466,10 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server) * through /proc/fs/cifs/dfscache or the target list is empty due to server settings after * refreshing the referral, so, in this case, default it to 1. */ - if (!dfs_cache_noreq_find(refpath, NULL, &tl)) + mutex_lock(&server->refpath_lock); + if (!dfs_cache_noreq_find(server->leaf_fullpath + 1, NULL, &tl)) num_targets = dfs_cache_get_nr_tgts(&tl); + mutex_unlock(&server->refpath_lock); if (!num_targets) num_targets = 1; @@ -512,7 +513,9 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server) mod_delayed_work(cifsiod_wq, &server->reconnect, 0); } while (server->tcpStatus == CifsNeedReconnect); - dfs_cache_noreq_update_tgthint(refpath, target_hint); + mutex_lock(&server->refpath_lock); + dfs_cache_noreq_update_tgthint(server->leaf_fullpath + 1, target_hint); + mutex_unlock(&server->refpath_lock); dfs_cache_free_tgts(&tl); /* Need to set up echo worker again once connection has been established */ @@ -1582,7 +1585,6 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, rc = -ENOMEM; goto out_err; } - tcp_ses->current_fullpath = tcp_ses->leaf_fullpath; } if (ctx->nosharesock) diff --git a/fs/cifs/dfs.c b/fs/cifs/dfs.c index 37f7da4f5c8b..c4ec5c67087b 100644 --- a/fs/cifs/dfs.c +++ b/fs/cifs/dfs.c @@ -248,11 +248,12 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx) tcon = mnt_ctx->tcon; mutex_lock(&server->refpath_lock); + spin_lock(&server->srv_lock); if (!server->origin_fullpath) { server->origin_fullpath = origin_fullpath; - server->current_fullpath = server->leaf_fullpath; origin_fullpath = NULL; } + spin_unlock(&server->srv_lock); mutex_unlock(&server->refpath_lock); if (list_empty(&tcon->dfs_ses_list)) { @@ -342,10 +343,11 @@ static int update_server_fullpath(struct TCP_Server_Info *server, struct cifs_sb rc = PTR_ERR(npath); } else { mutex_lock(&server->refpath_lock); + spin_lock(&server->srv_lock); kfree(server->leaf_fullpath); server->leaf_fullpath = npath; + spin_unlock(&server->srv_lock); mutex_unlock(&server->refpath_lock); - server->current_fullpath = server->leaf_fullpath; } return rc; } @@ -450,7 +452,7 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t share = prefix = NULL; /* Check if share matches with tcp ses */ - rc = dfs_cache_get_tgt_share(server->current_fullpath + 1, tit, &share, &prefix); + rc = dfs_cache_get_tgt_share(server->leaf_fullpath + 1, tit, &share, &prefix); if (rc) { cifs_dbg(VFS, "%s: failed to parse target share: %d\n", __func__, rc); break; @@ -464,7 +466,7 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t continue; } - dfs_cache_noreq_update_tgthint(server->current_fullpath + 1, tit); + dfs_cache_noreq_update_tgthint(server->leaf_fullpath + 1, tit); tree_connect_ipc(xid, tree, cifs_sb, tcon); scnprintf(tree, MAX_TREE_SIZE, "\\%s", share); @@ -582,8 +584,8 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru cifs_sb = CIFS_SB(sb); /* If it is not dfs or there was no cached dfs referral, then reconnect to same share */ - if (!server->current_fullpath || - dfs_cache_noreq_find(server->current_fullpath + 1, &ref, &tl)) { + if (!server->leaf_fullpath || + dfs_cache_noreq_find(server->leaf_fullpath + 1, &ref, &tl)) { rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name, tcon, cifs_sb->local_nls); goto out; } diff --git a/fs/cifs/dfs.h b/fs/cifs/dfs.h index 0b8cbf721fff..1c90df5ecfbd 100644 --- a/fs/cifs/dfs.h +++ b/fs/cifs/dfs.h @@ -43,8 +43,12 @@ static inline char *dfs_get_automount_devname(struct dentry *dentry, void *page) size_t len; char *s; - if (unlikely(!server->origin_fullpath)) + spin_lock(&server->srv_lock); + if (unlikely(!server->origin_fullpath)) { + spin_unlock(&server->srv_lock); return ERR_PTR(-EREMOTE); + } + spin_unlock(&server->srv_lock); s = dentry_path_raw(dentry, page, PATH_MAX); if (IS_ERR(s)) @@ -53,13 +57,18 @@ static inline char *dfs_get_automount_devname(struct dentry *dentry, void *page) if (!s[1]) s++; + spin_lock(&server->srv_lock); len = strlen(server->origin_fullpath); - if (s < (char *)page + len) + if (s < (char *)page + len) { + spin_unlock(&server->srv_lock); return ERR_PTR(-ENAMETOOLONG); + } s -= len; memcpy(s, server->origin_fullpath, len); + spin_unlock(&server->srv_lock); convert_delimiter(s, '/'); + return s; } diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c index 30cbdf8514a5..6557d7b2798a 100644 --- a/fs/cifs/dfs_cache.c +++ b/fs/cifs/dfs_cache.c @@ -1278,8 +1278,12 @@ static void refresh_cache_worker(struct work_struct *work) spin_lock(&cifs_tcp_ses_lock); list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { - if (!server->leaf_fullpath) + spin_lock(&server->srv_lock); + if (!server->leaf_fullpath) { + spin_unlock(&server->srv_lock); continue; + } + spin_unlock(&server->srv_lock); list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { if (ses->tcon_ipc) { From patchwork Wed May 3 22:21:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paulo Alcantara X-Patchwork-Id: 13230597 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A6B84C7EE22 for ; Wed, 3 May 2023 22:21:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229746AbjECWVz (ORCPT ); Wed, 3 May 2023 18:21:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35604 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229730AbjECWVy (ORCPT ); Wed, 3 May 2023 18:21:54 -0400 Received: from mx.manguebit.com (mx.manguebit.com [IPv6:2a01:4f8:1c1e:a2ae::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4EFD18A7E for ; Wed, 3 May 2023 15:21:53 -0700 (PDT) From: Paulo Alcantara DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=manguebit.com; s=dkim; t=1683152512; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=jPvQ89mKtQVhXNu4PeLmuaUsl7Gms2IweZvA/FA8NkQ=; b=MJAKPXNdVzUGHCC1aVgJAR8JQLwAA5/Z4uBo11vDowKEUcNJVtdnf1ycBmkZ3mSHiKwgh8 V79YaZMAgoAs15lVFBBzQ9AJamXlo1hBxVpwTeO3RkMecT7ETO1//RtdwfqzJqmWmA84MY whRmXoIpA2+RjWYVB57cuKV54frA8OhBUh3GXL8ySulnYcPCLWyUsui/VaSCtAODEYyycM EodiQpzOToVPRDVp7W/xc79f/gymIlu9yBAj17FdxGI89aCBlwopMtJkiz+e/55ju901cZ 7VH9ypUfSQbOjSvbsFMscLapLWRHzx+BafWKMXyfPdMwnszi1qQXoAMyRGIhxw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=manguebit.com; s=dkim; t=1683152512; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=jPvQ89mKtQVhXNu4PeLmuaUsl7Gms2IweZvA/FA8NkQ=; b=HWkcjK2ThzOZKhHLQvV3YF5mIAsFn+3sfSnb4ruddEzp7IL6FMqjTSq4NtNqO5Q5zh5mFH Y2BCswt+dfLW4AlQCf4vDw4wpwxQTfyGWXlq5lHZRn5HrPNeRg2qlpEopqIQ96ZH65fhLp 8qV00/wc72tan0XYdsOx4AaadrCXz4P+ZEDdI2IKWV60U0W+m00diW60dAR5Fj5Gi5c5A+ Lt4rkcbfjcmdjPJw1yrV79FMebNVLH3DNf9nD49iqwMI+zRDGJxNdkUDdPN66aSdv110+7 Yp/5IjZeWc+Ju93qvXXUppDCfKmml7aE4QprkU4f7SYjGcFh9MxVIe92MhchEA== ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pc@manguebit.com smtp.mailfrom=pc@manguebit.com ARC-Seal: i=1; s=dkim; d=manguebit.com; t=1683152512; a=rsa-sha256; cv=none; b=nWM2KJVhjDRP56+iE7l8WnOLZQoYliJ6TwfSgLk0jFoIda3smIOcl158bPmfTa1lEiOoc1 UE9ie+VBIfxseGFHYyogkJmh2XTuVC/3DJ3MS5T/kvd1IvOOVJ/L9Dscib/9o77zY7ZKnF eNZYVa/sTRRu/kr1/kqTzXtVqqbP4MCOZv78UBFUtLISBFd0Z4lxuWtD/Nfmy9HEHR0qBW yoA+o10WEPyFqIhrweO7xWZZMUk3DfxfY3BrAAVpDQk7PRFVoqvZcU2NCrksE2XbFRtEs3 JrZLtn5kPpMaF6UYhdCZA4kMyl1lWu47dJjREpG+vndHfdZV7fBXuFaJSQER+w== To: smfrench@gmail.com Cc: linux-cifs@vger.kernel.org, Paulo Alcantara Subject: [PATCH 5/7] cifs: print smb3_fs_context::source when mounting Date: Wed, 3 May 2023 19:21:15 -0300 Message-Id: <20230503222117.7609-6-pc@manguebit.com> In-Reply-To: <20230503222117.7609-1-pc@manguebit.com> References: <20230503222117.7609-1-pc@manguebit.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Print full device name (UNC + optional prefix) from @old_ctx->source when printing info about mount. Before patch mount.cifs //srv/share/dir /mnt -o ... dmesg ... CIFS: Attempting to mount \\srv\share After patch mount.cifs //srv/share/dir /mnt -o ... dmesg ... CIFS: Attempting to mount //srv/share/dir Signed-off-by: Paulo Alcantara (SUSE) --- fs/cifs/cifsfs.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ac9034fce409..32f7c81a7b89 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -874,14 +874,12 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, struct cifs_mnt_data mnt_data; struct dentry *root; - /* - * Prints in Kernel / CIFS log the attempted mount operation - * If CIFS_DEBUG && cifs_FYI - */ - if (cifsFYI) - cifs_dbg(FYI, "Devname: %s flags: %d\n", old_ctx->UNC, flags); - else - cifs_info("Attempting to mount %s\n", old_ctx->UNC); + if (cifsFYI) { + cifs_dbg(FYI, "%s: devname=%s flags=0x%x\n", __func__, + old_ctx->source, flags); + } else { + cifs_info("Attempting to mount %s\n", old_ctx->source); + } cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL); if (cifs_sb == NULL) { From patchwork Wed May 3 22:21:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paulo Alcantara X-Patchwork-Id: 13230598 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CC627C7EE22 for ; Wed, 3 May 2023 22:21:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229713AbjECWV6 (ORCPT ); Wed, 3 May 2023 18:21:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35646 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229678AbjECWV6 (ORCPT ); Wed, 3 May 2023 18:21:58 -0400 Received: from mx.manguebit.com (mx.manguebit.com [167.235.159.17]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2C2727D8E for ; Wed, 3 May 2023 15:21:56 -0700 (PDT) From: Paulo Alcantara DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=manguebit.com; s=dkim; t=1683152514; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Cew9aSXO8xlKxZFIdAKFcmnCym/o3WCRV0czPEY5S+0=; b=UCPvDgMcZAodZBwz6nqxsO7RLRWaTbsfnYyFjSB4mLY0XQiuMaZ7+qHTAGpjETdydFaK+X Nk51Sv5LaufT+uJEG3TrM2dOqoQXFhHoQBoUS094K4YH8rK5pdj1WWUe91DqoAolHZs3zo d793E/TumXZxZ9Vm3S7KU698gLryxWtd0e8g1BsElPX3ljmviQNZqOOrwMrDKzpshJ3Rdv zsJARY8I55Ufyxx4eaxB7x4AvpbYjkOd5trjx/ODPP188IkIHpu/+KlOYYWIPZ3Jrw8/lJ TKwHWKDPaLD47HeeDTn1eFxvgjG/Ugmgk1PIsatMh+91u2YYV2jXaRxMgAnwZQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=manguebit.com; s=dkim; t=1683152514; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Cew9aSXO8xlKxZFIdAKFcmnCym/o3WCRV0czPEY5S+0=; b=NMuSQ51CNw9r0tqA3nGC3m7MWYHOOScGg9MFGlFTixkjuv6CkPvXRTOKJRkGtYJtzS1p0G r0IVroHMU75Fa0Nlqukfvo18aX/1qeF9Nl6B6DsGM4xo6eO11X0X1bsXD8L9MkFoKt/b/f 8Nbu98JghdjVG+d6+uziDbNwYt3D9lUQuqZed/RgDHG96LP4uSaOz1r9FJrndByshEHR8U HFAAZi6MY7FfRI6ov4IuCVyL62x3BeLlAyB4KLXk+81dKMVm78wHWEDkcT9iLU+vqo53kE 8GLK0yBo9nyTTx+SyRUaFwirmXTKlgZo+4+o/2k/cZQ6R/U1p0CKL14wXUJ54A== ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pc@manguebit.com smtp.mailfrom=pc@manguebit.com ARC-Seal: i=1; s=dkim; d=manguebit.com; t=1683152514; a=rsa-sha256; cv=none; b=OSb2aDgxOhd1PRR4qPQlxrCfZdMlBNoEQPulrJnUECo0Y3LqMDBXxpoNB/7A0e7aWAny7/ 1iHfP54k4iXjWBNEThawXnioDaA1CyCJ5le1RnWrqyiGl78BwdPRBu3l9Ce7XpOUqbwQ+A VwSQ20hBfEbWOoxuz4SAQUq6TBx+e5odE6IOcXaLxjgGvZdM8+7L6Rzb/dU1ZB/QdSzcTn BVnoIU2lUbS55+LciZyu5KJPL4MlPmVtuMafSomC1JEx0WzsWbC5Q8+RAi7qCFZafbZ+AU MENXwytbd8NcMcvPOuA1PMt6j+2q4Q3qDB5wCL36Br7/Kuhmkyk35YahZTrzcg== To: smfrench@gmail.com Cc: linux-cifs@vger.kernel.org, Paulo Alcantara , stable@vger.kernel.org Subject: [PATCH 6/7] cifs: avoid potential races when handling multiple dfs tcons Date: Wed, 3 May 2023 19:21:16 -0300 Message-Id: <20230503222117.7609-7-pc@manguebit.com> In-Reply-To: <20230503222117.7609-1-pc@manguebit.com> References: <20230503222117.7609-1-pc@manguebit.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Now that a DFS tcon manages its own list of DFS referrals and sessions, there is no point in having a single worker to refresh referrals of all DFS tcons. Make it faster and less prone to race conditions when having several mounts by queueing a worker per DFS tcon that will take care of refreshing only the DFS referrals related to it. Cc: stable@vger.kernel.org # v6.2+ Signed-off-by: Paulo Alcantara (SUSE) --- fs/cifs/cifsglob.h | 2 +- fs/cifs/connect.c | 7 ++- fs/cifs/dfs.c | 4 ++ fs/cifs/dfs_cache.c | 141 +++++++++++++++++++------------------------- fs/cifs/dfs_cache.h | 9 +++ 5 files changed, 82 insertions(+), 81 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a62447404851..9c5cd332ce14 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1238,8 +1238,8 @@ struct cifs_tcon { struct cached_fids *cfids; /* BB add field for back pointer to sb struct(s)? */ #ifdef CONFIG_CIFS_DFS_UPCALL - struct list_head ulist; /* cache update list */ struct list_head dfs_ses_list; + struct delayed_work dfs_cache_work; #endif struct delayed_work query_interfaces; /* query interfaces workqueue job */ }; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 340bd7cf64f3..71966db89b6a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2336,6 +2336,9 @@ cifs_put_tcon(struct cifs_tcon *tcon) /* cancel polling of interfaces */ cancel_delayed_work_sync(&tcon->query_interfaces); +#ifdef CONFIG_CIFS_DFS_UPCALL + cancel_delayed_work_sync(&tcon->dfs_cache_work); +#endif if (tcon->use_witness) { int rc; @@ -2583,7 +2586,9 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) queue_delayed_work(cifsiod_wq, &tcon->query_interfaces, (SMB_INTERFACE_POLL_INTERVAL * HZ)); } - +#ifdef CONFIG_CIFS_DFS_UPCALL + INIT_DELAYED_WORK(&tcon->dfs_cache_work, dfs_cache_refresh); +#endif spin_lock(&cifs_tcp_ses_lock); list_add(&tcon->tcon_list, &ses->tcon_list); spin_unlock(&cifs_tcp_ses_lock); diff --git a/fs/cifs/dfs.c b/fs/cifs/dfs.c index c4ec5c67087b..da4e083b1ab4 100644 --- a/fs/cifs/dfs.c +++ b/fs/cifs/dfs.c @@ -157,6 +157,8 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co rc = cifs_is_path_remote(mnt_ctx); } + dfs_cache_noreq_update_tgthint(ref_path + 1, tit); + if (rc == -EREMOTE && is_refsrv) { rc2 = get_root_smb_session(mnt_ctx); if (rc2) @@ -259,6 +261,8 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx) if (list_empty(&tcon->dfs_ses_list)) { list_replace_init(&mnt_ctx->dfs_ses_list, &tcon->dfs_ses_list); + queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work, + dfs_cache_get_ttl() * HZ); } else { dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list); } diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c index 6557d7b2798a..1513b2709889 100644 --- a/fs/cifs/dfs_cache.c +++ b/fs/cifs/dfs_cache.c @@ -20,12 +20,14 @@ #include "cifs_unicode.h" #include "smb2glob.h" #include "dns_resolve.h" +#include "dfs.h" #include "dfs_cache.h" -#define CACHE_HTABLE_SIZE 32 -#define CACHE_MAX_ENTRIES 64 -#define CACHE_MIN_TTL 120 /* 2 minutes */ +#define CACHE_HTABLE_SIZE 32 +#define CACHE_MAX_ENTRIES 64 +#define CACHE_MIN_TTL 120 /* 2 minutes */ +#define CACHE_DEFAULT_TTL 300 /* 5 minutes */ #define IS_DFS_INTERLINK(v) (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER)) @@ -50,10 +52,9 @@ struct cache_entry { }; static struct kmem_cache *cache_slab __read_mostly; -static struct workqueue_struct *dfscache_wq __read_mostly; +struct workqueue_struct *dfscache_wq; -static int cache_ttl; -static DEFINE_SPINLOCK(cache_ttl_lock); +atomic_t dfs_cache_ttl; static struct nls_table *cache_cp; @@ -65,10 +66,6 @@ static atomic_t cache_count; static struct hlist_head cache_htable[CACHE_HTABLE_SIZE]; static DECLARE_RWSEM(htable_rw_lock); -static void refresh_cache_worker(struct work_struct *work); - -static DECLARE_DELAYED_WORK(refresh_task, refresh_cache_worker); - /** * dfs_cache_canonical_path - get a canonical DFS path * @@ -290,7 +287,9 @@ int dfs_cache_init(void) int rc; int i; - dfscache_wq = alloc_workqueue("cifs-dfscache", WQ_FREEZABLE | WQ_UNBOUND, 1); + dfscache_wq = alloc_workqueue("cifs-dfscache", + WQ_UNBOUND|WQ_FREEZABLE|WQ_MEM_RECLAIM, + 0); if (!dfscache_wq) return -ENOMEM; @@ -306,6 +305,7 @@ int dfs_cache_init(void) INIT_HLIST_HEAD(&cache_htable[i]); atomic_set(&cache_count, 0); + atomic_set(&dfs_cache_ttl, CACHE_DEFAULT_TTL); cache_cp = load_nls("utf8"); if (!cache_cp) cache_cp = load_nls_default(); @@ -480,6 +480,7 @@ static struct cache_entry *add_cache_entry_locked(struct dfs_info3_param *refs, int rc; struct cache_entry *ce; unsigned int hash; + int ttl; WARN_ON(!rwsem_is_locked(&htable_rw_lock)); @@ -496,15 +497,8 @@ static struct cache_entry *add_cache_entry_locked(struct dfs_info3_param *refs, if (IS_ERR(ce)) return ce; - spin_lock(&cache_ttl_lock); - if (!cache_ttl) { - cache_ttl = ce->ttl; - queue_delayed_work(dfscache_wq, &refresh_task, cache_ttl * HZ); - } else { - cache_ttl = min_t(int, cache_ttl, ce->ttl); - mod_delayed_work(dfscache_wq, &refresh_task, cache_ttl * HZ); - } - spin_unlock(&cache_ttl_lock); + ttl = min_t(int, atomic_read(&dfs_cache_ttl), ce->ttl); + atomic_set(&dfs_cache_ttl, ttl); hlist_add_head(&ce->hlist, &cache_htable[hash]); dump_ce(ce); @@ -616,7 +610,6 @@ static struct cache_entry *lookup_cache_entry(const char *path) */ void dfs_cache_destroy(void) { - cancel_delayed_work_sync(&refresh_task); unload_nls(cache_cp); flush_cache_ents(); kmem_cache_destroy(cache_slab); @@ -1142,6 +1135,7 @@ static bool target_share_equal(struct TCP_Server_Info *server, const char *s1, c * target shares in @refs. */ static void mark_for_reconnect_if_needed(struct TCP_Server_Info *server, + const char *path, struct dfs_cache_tgt_list *old_tl, struct dfs_cache_tgt_list *new_tl) { @@ -1153,8 +1147,10 @@ static void mark_for_reconnect_if_needed(struct TCP_Server_Info *server, nit = dfs_cache_get_next_tgt(new_tl, nit)) { if (target_share_equal(server, dfs_cache_get_tgt_name(oit), - dfs_cache_get_tgt_name(nit))) + dfs_cache_get_tgt_name(nit))) { + dfs_cache_noreq_update_tgthint(path, nit); return; + } } } @@ -1162,13 +1158,28 @@ static void mark_for_reconnect_if_needed(struct TCP_Server_Info *server, cifs_signal_cifsd_for_reconnect(server, true); } +static bool is_ses_good(struct cifs_ses *ses) +{ + struct TCP_Server_Info *server = ses->server; + struct cifs_tcon *tcon = ses->tcon_ipc; + bool ret; + + spin_lock(&ses->ses_lock); + spin_lock(&ses->chan_lock); + ret = !cifs_chan_needs_reconnect(ses, server) && + ses->ses_status == SES_GOOD && + !tcon->need_reconnect; + spin_unlock(&ses->chan_lock); + spin_unlock(&ses->ses_lock); + return ret; +} + /* Refresh dfs referral of tcon and mark it for reconnect if needed */ -static int __refresh_tcon(const char *path, struct cifs_tcon *tcon, bool force_refresh) +static int __refresh_tcon(const char *path, struct cifs_ses *ses, bool force_refresh) { struct dfs_cache_tgt_list old_tl = DFS_CACHE_TGT_LIST_INIT(old_tl); struct dfs_cache_tgt_list new_tl = DFS_CACHE_TGT_LIST_INIT(new_tl); - struct cifs_ses *ses = CIFS_DFS_ROOT_SES(tcon->ses); - struct cifs_tcon *ipc = ses->tcon_ipc; + struct TCP_Server_Info *server = ses->server; bool needs_refresh = false; struct cache_entry *ce; unsigned int xid; @@ -1190,20 +1201,19 @@ static int __refresh_tcon(const char *path, struct cifs_tcon *tcon, bool force_r goto out; } - spin_lock(&ipc->tc_lock); - if (ipc->status != TID_GOOD) { - spin_unlock(&ipc->tc_lock); - cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n", __func__); + ses = CIFS_DFS_ROOT_SES(ses); + if (!is_ses_good(ses)) { + cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n", + __func__); goto out; } - spin_unlock(&ipc->tc_lock); ce = cache_refresh_path(xid, ses, path, true); if (!IS_ERR(ce)) { rc = get_targets(ce, &new_tl); up_read(&htable_rw_lock); cifs_dbg(FYI, "%s: get_targets: %d\n", __func__, rc); - mark_for_reconnect_if_needed(tcon->ses->server, &old_tl, &new_tl); + mark_for_reconnect_if_needed(server, path, &old_tl, &new_tl); } out: @@ -1216,10 +1226,11 @@ static int __refresh_tcon(const char *path, struct cifs_tcon *tcon, bool force_r static int refresh_tcon(struct cifs_tcon *tcon, bool force_refresh) { struct TCP_Server_Info *server = tcon->ses->server; + struct cifs_ses *ses = tcon->ses; mutex_lock(&server->refpath_lock); if (server->leaf_fullpath) - __refresh_tcon(server->leaf_fullpath + 1, tcon, force_refresh); + __refresh_tcon(server->leaf_fullpath + 1, ses, force_refresh); mutex_unlock(&server->refpath_lock); return 0; } @@ -1263,60 +1274,32 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb) return refresh_tcon(tcon, true); } -/* - * Worker that will refresh DFS cache from all active mounts based on lowest TTL value - * from a DFS referral. - */ -static void refresh_cache_worker(struct work_struct *work) +/* Refresh all DFS referrals related to DFS tcon */ +void dfs_cache_refresh(struct work_struct *work) { struct TCP_Server_Info *server; - struct cifs_tcon *tcon, *ntcon; - struct list_head tcons; + struct dfs_root_ses *rses; + struct cifs_tcon *tcon; struct cifs_ses *ses; - INIT_LIST_HEAD(&tcons); - - spin_lock(&cifs_tcp_ses_lock); - list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { - spin_lock(&server->srv_lock); - if (!server->leaf_fullpath) { - spin_unlock(&server->srv_lock); - continue; - } - spin_unlock(&server->srv_lock); - - list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { - if (ses->tcon_ipc) { - ses->ses_count++; - list_add_tail(&ses->tcon_ipc->ulist, &tcons); - } - list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { - if (!tcon->ipc) { - tcon->tc_count++; - list_add_tail(&tcon->ulist, &tcons); - } - } - } - } - spin_unlock(&cifs_tcp_ses_lock); - - list_for_each_entry_safe(tcon, ntcon, &tcons, ulist) { - struct TCP_Server_Info *server = tcon->ses->server; - - list_del_init(&tcon->ulist); - + tcon = container_of(work, struct cifs_tcon, dfs_cache_work.work); + ses = tcon->ses; + server = ses->server; + + mutex_lock(&server->refpath_lock); + if (server->leaf_fullpath) + __refresh_tcon(server->leaf_fullpath + 1, ses, false); + mutex_unlock(&server->refpath_lock); + + list_for_each_entry(rses, &tcon->dfs_ses_list, list) { + ses = rses->ses; + server = ses->server; mutex_lock(&server->refpath_lock); if (server->leaf_fullpath) - __refresh_tcon(server->leaf_fullpath + 1, tcon, false); + __refresh_tcon(server->leaf_fullpath + 1, ses, false); mutex_unlock(&server->refpath_lock); - - if (tcon->ipc) - cifs_put_smb_ses(tcon->ses); - else - cifs_put_tcon(tcon); } - spin_lock(&cache_ttl_lock); - queue_delayed_work(dfscache_wq, &refresh_task, cache_ttl * HZ); - spin_unlock(&cache_ttl_lock); + queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work, + atomic_read(&dfs_cache_ttl) * HZ); } diff --git a/fs/cifs/dfs_cache.h b/fs/cifs/dfs_cache.h index e0d39393035a..c6d89cd6d4fd 100644 --- a/fs/cifs/dfs_cache.h +++ b/fs/cifs/dfs_cache.h @@ -13,6 +13,9 @@ #include #include "cifsglob.h" +extern struct workqueue_struct *dfscache_wq; +extern atomic_t dfs_cache_ttl; + #define DFS_CACHE_TGT_LIST_INIT(var) { .tl_numtgts = 0, .tl_list = LIST_HEAD_INIT((var).tl_list), } struct dfs_cache_tgt_list { @@ -42,6 +45,7 @@ int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it, char **prefix); char *dfs_cache_canonical_path(const char *path, const struct nls_table *cp, int remap); int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb); +void dfs_cache_refresh(struct work_struct *work); static inline struct dfs_cache_tgt_iterator * dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl, @@ -89,4 +93,9 @@ dfs_cache_get_nr_tgts(const struct dfs_cache_tgt_list *tl) return tl ? tl->tl_numtgts : 0; } +static inline int dfs_cache_get_ttl(void) +{ + return atomic_read(&dfs_cache_ttl); +} + #endif /* _CIFS_DFS_CACHE_H */ From patchwork Wed May 3 22:21:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paulo Alcantara X-Patchwork-Id: 13230599 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 51445C7EE22 for ; Wed, 3 May 2023 22:22:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229459AbjECWWD (ORCPT ); Wed, 3 May 2023 18:22:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35700 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229678AbjECWWC (ORCPT ); Wed, 3 May 2023 18:22:02 -0400 Received: from mx.manguebit.com (mx.manguebit.com [IPv6:2a01:4f8:1c1e:a2ae::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 90A587D8E; Wed, 3 May 2023 15:21:58 -0700 (PDT) From: Paulo Alcantara DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=manguebit.com; s=dkim; t=1683152517; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Ep9s90pSLXshI0xZy/YXg0rPz4K8PKNb6ZVynztGc7Y=; b=eYfI4p9Z+W3IvqQkxdbmGniLvwF/bRDnCzeOGgA4JH+VbKvBAtx3DCla1WoCVcCZWDthmb IgGnhDaK8iwp+mxpGdPSnuIQU/RRQKJ5lIKLENVLP+/dx1dUrvK06BIpWmSPhWekpy/YcY cymE8I5YmLEd5ixebUAbGO+zY7No8T3Gn4GufSx3Ecm+sYgD3VkIqi6i+2VpTUP+/4mYlS kw50nuLCzbgnm/z97tYsKONvyRqaU4f4hOJ/m2BxG2zFeGLd0ncBpmk/v5dI4RdnEJDxzE oDUzWBESsDk5X2FoeaInM5RVuT6Ry+iKIA1D+jJ4udW6VARSjblmNerACZTHgw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=manguebit.com; s=dkim; t=1683152517; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Ep9s90pSLXshI0xZy/YXg0rPz4K8PKNb6ZVynztGc7Y=; b=ehpYLsbCemv4I968WgGIjvI1TzPGG44R7TZHrBLQkowEsILinqT49FcGx1pe2k+lgLpd1T /z4beNNd4S8NjlkmrvGk73uvg1GjcXrUl/MjuPpFrd30nwb5Js8/NZVfMqPXZzSZtZny2f IYU0dN5EYc40/8Bq1zHU8zjFHW689OlOSboNvpC1m3XRBJr/Pqr5ER9oKMgVKbMWddV39E pNe/yIdWSHOouwvOiaNwvwb7lLLGAFCoP2zgeRlCb/J+qkbTafvulJXvb+P5c7iKgSydyC RPXzGaEVjQ8DauIROEcTAZ7VnI67gdkK2260bWKeOO36ShRGdQAiZAiNi3K53A== ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pc@manguebit.com smtp.mailfrom=pc@manguebit.com ARC-Seal: i=1; s=dkim; d=manguebit.com; t=1683152517; a=rsa-sha256; cv=none; b=Tn1gAVEKkGDqzJmclaD2NwMKGDf1yg0g6xhOvCKjZ7BCRgWkcYsf4kDSN8yqlZgtcSCAXY F+bAF9R8+A8oPb4GnFZmhf9PDRFzPJFqUsEiGejZVMDlcBvn22sepptBK6GB8v96cVQjv5 boWI5AEezdjj8XKkzdlhOAc7XlyNoMAqDM1zeUFCl2iCGytisH8/AId5pGBrjnlueaRsqT S8784X6RvdHb4ZIiWazmqZ0I+De2pTruh8jVwcQj7Iu9LOyJMA8mvGliJ3OW2lRGYCiz/H zQy2qssceUpibtTZpLeBugymDyBCYZpJg5fXJQdnfH6xscdc3rmWfarbML99yA== To: smfrench@gmail.com Cc: linux-cifs@vger.kernel.org, Paulo Alcantara , stable@vger.kernel.org Subject: [PATCH 7/7] cifs: fix sharing of DFS connections Date: Wed, 3 May 2023 19:21:17 -0300 Message-Id: <20230503222117.7609-8-pc@manguebit.com> In-Reply-To: <20230503222117.7609-1-pc@manguebit.com> References: <20230503222117.7609-1-pc@manguebit.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org When matching DFS connections, we can't rely on the values set in cifs_sb_info::prepath and cifs_tcon::tree_name as they might change during DFS failover. The DFS referrals related to a specific DFS tcon are already matched earlier in match_server(), therefore we can safely skip those checks altogether as the connection is guaranteed to be unique for the DFS tcon. Besides, when creating or finding an SMB session, make sure to also refcount any DFS root session related to it (cifs_ses::dfs_root_ses), so if a new DFS mount ends up reusing the connection from the old mount while there was an umount(2) still in progress (e.g. umount(2) -> cifs_umount() -> reconnect -> cifs_put_tcon()), the connection could potentially be put right after the umount(2) finished. Cc: stable@vger.kernel.org # v6.2+ Signed-off-by: Paulo Alcantara (SUSE) --- fs/cifs/cifsglob.h | 1 - fs/cifs/cifsproto.h | 44 ++++++++++++++++- fs/cifs/connect.c | 118 +++++++++++++++++++++++--------------------- fs/cifs/dfs.c | 62 ++++++++++++++++------- fs/cifs/ioctl.c | 2 +- fs/cifs/smb2pdu.c | 4 +- 6 files changed, 150 insertions(+), 81 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 9c5cd332ce14..414685c5d530 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1756,7 +1756,6 @@ struct cifs_mount_ctx { struct TCP_Server_Info *server; struct cifs_ses *ses; struct cifs_tcon *tcon; - char *origin_fullpath, *leaf_fullpath; struct list_head dfs_ses_list; }; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e2eff66eefab..c1c704990b98 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -8,6 +8,7 @@ #ifndef _CIFSPROTO_H #define _CIFSPROTO_H #include +#include #include "trace.h" #ifdef CONFIG_CIFS_DFS_UPCALL #include "dfs_cache.h" @@ -572,7 +573,7 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16, extern struct TCP_Server_Info * cifs_find_tcp_session(struct smb3_fs_context *ctx); -extern void cifs_put_smb_ses(struct cifs_ses *ses); +void __cifs_put_smb_ses(struct cifs_ses *ses); extern struct cifs_ses * cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx); @@ -696,4 +697,45 @@ struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon); void cifs_put_tcon_super(struct super_block *sb); int cifs_wait_for_server_reconnect(struct TCP_Server_Info *server, bool retry); +/* Put references of @ses and @ses->dfs_root_ses */ +static inline void cifs_put_smb_ses(struct cifs_ses *ses) +{ + struct cifs_ses *rses = ses->dfs_root_ses; + + __cifs_put_smb_ses(ses); + if (rses) + __cifs_put_smb_ses(rses); +} + +/* Get an active reference of @ses and @ses->dfs_root_ses. + * + * NOTE: make sure to call this function when incrementing reference count of + * @ses to ensure that any DFS root session attached to it (@ses->dfs_root_ses) + * will also get its reference count incremented. + * + * cifs_put_smb_ses() will put both references, so call it when you're done. + */ +static inline void cifs_smb_ses_inc_refcount(struct cifs_ses *ses) +{ + lockdep_assert_held(&cifs_tcp_ses_lock); + + ses->ses_count++; + if (ses->dfs_root_ses) + ses->dfs_root_ses->ses_count++; +} + +static inline bool dfs_src_pathname_equal(const char *s1, const char *s2) +{ + if (strlen(s1) != strlen(s2)) + return false; + for (; *s1; s1++, s2++) { + if (*s1 == '/' || *s1 == '\\') { + if (*s2 != '/' && *s2 != '\\') + return false; + } else if (tolower(*s1) != tolower(*s2)) + return false; + } + return true; +} + #endif /* _CIFSPROTO_H */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 71966db89b6a..9a9d1b561175 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -996,10 +996,8 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server) */ } -#ifdef CONFIG_CIFS_DFS_UPCALL kfree(server->origin_fullpath); kfree(server->leaf_fullpath); -#endif kfree(server); length = atomic_dec_return(&tcpSesAllocCount); @@ -1387,23 +1385,8 @@ match_security(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) return true; } -static bool dfs_src_pathname_equal(const char *s1, const char *s2) -{ - if (strlen(s1) != strlen(s2)) - return false; - for (; *s1; s1++, s2++) { - if (*s1 == '/' || *s1 == '\\') { - if (*s2 != '/' && *s2 != '\\') - return false; - } else if (tolower(*s1) != tolower(*s2)) - return false; - } - return true; -} - /* this function must be called with srv_lock held */ -static int match_server(struct TCP_Server_Info *server, struct smb3_fs_context *ctx, - bool dfs_super_cmp) +static int match_server(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) { struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr; @@ -1434,27 +1417,41 @@ static int match_server(struct TCP_Server_Info *server, struct smb3_fs_context * (struct sockaddr *)&server->srcaddr)) return 0; /* - * When matching DFS superblocks, we only check for original source pathname as the - * currently connected target might be different than the one parsed earlier in i.e. - * mount.cifs(8). + * - Match for an DFS tcon (@server->origin_fullpath). + * - Match for an DFS root server connection (@server->leaf_fullpath). + * - If none of the above and @ctx->leaf_fullpath is set, then + * it is a new DFS connection. + * - If 'nodfs' mount option was passed, then match only connections + * that have no DFS referrals set + * (e.g. can't failover to other targets). */ - if (dfs_super_cmp) { - if (!ctx->source || !server->origin_fullpath || - !dfs_src_pathname_equal(server->origin_fullpath, ctx->source)) - return 0; - } else { - /* Skip addr, hostname and port matching for DFS connections */ - if (server->leaf_fullpath) { + if (!ctx->nodfs) { + if (ctx->source && server->origin_fullpath) { + if (!dfs_src_pathname_equal(ctx->source, + server->origin_fullpath)) + return 0; + } else if (server->leaf_fullpath) { if (!ctx->leaf_fullpath || - strcasecmp(server->leaf_fullpath, ctx->leaf_fullpath)) + strcasecmp(server->leaf_fullpath, + ctx->leaf_fullpath)) return 0; - } else if (strcasecmp(server->hostname, ctx->server_hostname) || - !match_server_address(server, addr) || - !match_port(server, addr)) { + } else if (ctx->leaf_fullpath) { return 0; } + } else if (server->origin_fullpath || server->leaf_fullpath) { + return 0; } + /* + * Match for a regular connection (address/hostname/port) which has no + * DFS referrals set. + */ + if (!server->origin_fullpath && !server->leaf_fullpath && + (strcasecmp(server->hostname, ctx->server_hostname) || + !match_server_address(server, addr) || + !match_port(server, addr))) + return 0; + if (!match_security(server, ctx)) return 0; @@ -1485,7 +1482,7 @@ cifs_find_tcp_session(struct smb3_fs_context *ctx) * Skip ses channels since they're only handled in lower layers * (e.g. cifs_send_recv). */ - if (CIFS_SERVER_IS_CHAN(server) || !match_server(server, ctx, false)) { + if (CIFS_SERVER_IS_CHAN(server) || !match_server(server, ctx)) { spin_unlock(&server->srv_lock); continue; } @@ -1869,7 +1866,7 @@ cifs_free_ipc(struct cifs_ses *ses) static struct cifs_ses * cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) { - struct cifs_ses *ses; + struct cifs_ses *ses, *ret = NULL; spin_lock(&cifs_tcp_ses_lock); list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { @@ -1879,23 +1876,22 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) continue; } spin_lock(&ses->chan_lock); - if (!match_session(ses, ctx)) { + if (match_session(ses, ctx)) { spin_unlock(&ses->chan_lock); spin_unlock(&ses->ses_lock); - continue; + ret = ses; + break; } spin_unlock(&ses->chan_lock); spin_unlock(&ses->ses_lock); - - ++ses->ses_count; - spin_unlock(&cifs_tcp_ses_lock); - return ses; } + if (ret) + cifs_smb_ses_inc_refcount(ret); spin_unlock(&cifs_tcp_ses_lock); - return NULL; + return ret; } -void cifs_put_smb_ses(struct cifs_ses *ses) +void __cifs_put_smb_ses(struct cifs_ses *ses) { unsigned int rc, xid; unsigned int chan_count; @@ -2246,6 +2242,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) */ spin_lock(&cifs_tcp_ses_lock); ses->dfs_root_ses = ctx->dfs_root_ses; + if (ses->dfs_root_ses) + ses->dfs_root_ses->ses_count++; list_add(&ses->smb_ses_list, &server->smb_ses_list); spin_unlock(&cifs_tcp_ses_lock); @@ -2262,12 +2260,15 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) } /* this function must be called with tc_lock held */ -static int match_tcon(struct cifs_tcon *tcon, struct smb3_fs_context *ctx, bool dfs_super_cmp) +static int match_tcon(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) { + struct TCP_Server_Info *server = tcon->ses->server; + if (tcon->status == TID_EXITING) return 0; - /* Skip UNC validation when matching DFS superblocks */ - if (!dfs_super_cmp && strncmp(tcon->tree_name, ctx->UNC, MAX_TREE_SIZE)) + /* Skip UNC validation when matching DFS connections or superblocks */ + if (!server->origin_fullpath && !server->leaf_fullpath && + strncmp(tcon->tree_name, ctx->UNC, MAX_TREE_SIZE)) return 0; if (tcon->seal != ctx->seal) return 0; @@ -2290,7 +2291,7 @@ cifs_find_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) spin_lock(&cifs_tcp_ses_lock); list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { spin_lock(&tcon->tc_lock); - if (!match_tcon(tcon, ctx, false)) { + if (!match_tcon(tcon, ctx)) { spin_unlock(&tcon->tc_lock); continue; } @@ -2306,8 +2307,9 @@ cifs_find_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) void cifs_put_tcon(struct cifs_tcon *tcon) { - unsigned int xid; + struct TCP_Server_Info *server; struct cifs_ses *ses; + unsigned int xid; /* * IPC tcon share the lifetime of their session and are @@ -2317,6 +2319,7 @@ cifs_put_tcon(struct cifs_tcon *tcon) return; ses = tcon->ses; + server = ses->server; cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count); spin_lock(&cifs_tcp_ses_lock); spin_lock(&tcon->tc_lock); @@ -2666,9 +2669,11 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data) return 1; } -static int -match_prepath(struct super_block *sb, struct cifs_mnt_data *mnt_data) +static int match_prepath(struct super_block *sb, + struct TCP_Server_Info *server, + struct cifs_mnt_data *mnt_data) { + struct smb3_fs_context *ctx = mnt_data->ctx; struct cifs_sb_info *old = CIFS_SB(sb); struct cifs_sb_info *new = mnt_data->cifs_sb; bool old_set = (old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) && @@ -2676,6 +2681,10 @@ match_prepath(struct super_block *sb, struct cifs_mnt_data *mnt_data) bool new_set = (new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) && new->prepath; + if (server->origin_fullpath && + dfs_src_pathname_equal(server->origin_fullpath, ctx->source)) + return 1; + if (old_set && new_set && !strcmp(new->prepath, old->prepath)) return 1; else if (!old_set && !new_set) @@ -2694,7 +2703,6 @@ cifs_match_super(struct super_block *sb, void *data) struct cifs_ses *ses; struct cifs_tcon *tcon; struct tcon_link *tlink; - bool dfs_super_cmp; int rc = 0; spin_lock(&cifs_tcp_ses_lock); @@ -2709,18 +2717,16 @@ cifs_match_super(struct super_block *sb, void *data) ses = tcon->ses; tcp_srv = ses->server; - dfs_super_cmp = IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) && tcp_srv->origin_fullpath; - ctx = mnt_data->ctx; spin_lock(&tcp_srv->srv_lock); spin_lock(&ses->ses_lock); spin_lock(&ses->chan_lock); spin_lock(&tcon->tc_lock); - if (!match_server(tcp_srv, ctx, dfs_super_cmp) || + if (!match_server(tcp_srv, ctx) || !match_session(ses, ctx) || - !match_tcon(tcon, ctx, dfs_super_cmp) || - !match_prepath(sb, mnt_data)) { + !match_tcon(tcon, ctx) || + !match_prepath(sb, tcp_srv, mnt_data)) { rc = 0; goto out; } @@ -3465,8 +3471,6 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) error: dfs_put_root_smb_sessions(&mnt_ctx.dfs_ses_list); - kfree(mnt_ctx.origin_fullpath); - kfree(mnt_ctx.leaf_fullpath); cifs_mount_put_conns(&mnt_ctx); return rc; } diff --git a/fs/cifs/dfs.c b/fs/cifs/dfs.c index da4e083b1ab4..a93dbca1411b 100644 --- a/fs/cifs/dfs.c +++ b/fs/cifs/dfs.c @@ -99,7 +99,7 @@ static int get_session(struct cifs_mount_ctx *mnt_ctx, const char *full_path) return rc; } -static int get_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 dfs_root_ses *root_ses; @@ -127,7 +127,7 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co { struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; struct dfs_info3_param ref = {}; - bool is_refsrv = false; + bool is_refsrv; int rc, rc2; rc = dfs_cache_get_tgt_referral(ref_path + 1, tit, &ref); @@ -160,7 +160,7 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co dfs_cache_noreq_update_tgthint(ref_path + 1, tit); if (rc == -EREMOTE && is_refsrv) { - rc2 = get_root_smb_session(mnt_ctx); + rc2 = add_root_smb_session(mnt_ctx); if (rc2) rc = rc2; } @@ -277,15 +277,21 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx) int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs) { - struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb; struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; + struct cifs_ses *ses; + char *source = ctx->source; + bool nodfs = ctx->nodfs; int rc; *isdfs = false; - + /* Temporarily set @ctx->source to NULL as we're not matching DFS + * superblocks yet. See cifs_match_super() and match_server(). + */ + ctx->source = NULL; rc = get_session(mnt_ctx, NULL); if (rc) - return rc; + goto out; + ctx->dfs_root_ses = mnt_ctx->ses; /* * If called with 'nodfs' mount option, then skip DFS resolving. Otherwise unconditionally @@ -294,23 +300,41 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs) * Skip prefix path to provide support for DFS referrals from w2k8 servers which don't seem * to respond with PATH_NOT_COVERED to requests that include the prefix. */ - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) || - dfs_get_referral(mnt_ctx, ctx->UNC + 1, NULL, NULL)) { + if (!nodfs) { + rc = dfs_get_referral(mnt_ctx, ctx->UNC + 1, NULL, NULL); + if (rc) { + if (rc != -ENOENT && rc != -EOPNOTSUPP) + goto out; + nodfs = true; + } + } + if (nodfs) { rc = cifs_mount_get_tcon(mnt_ctx); - if (rc) - return rc; - - rc = cifs_is_path_remote(mnt_ctx); - if (!rc || rc != -EREMOTE) - return rc; + if (!rc) + rc = cifs_is_path_remote(mnt_ctx); + goto out; } *isdfs = true; - rc = get_root_smb_session(mnt_ctx); - if (rc) - return rc; - - return __dfs_mount_share(mnt_ctx); + /* + * Prevent DFS root session of being put in the first call to + * 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); +out: + /* + * Restore previous value of @ctx->source so DFS superblock can be + * matched in cifs_match_super(). + */ + ctx->source = source; + return rc; } /* Update dfs referral path of superblock */ diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 6419ec47c2a8..cb3be58cd55e 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -239,7 +239,7 @@ static int cifs_dump_full_key(struct cifs_tcon *tcon, struct smb3_full_key_debug * section, we need to make sure it won't be released * so increment its refcount */ - ses->ses_count++; + cifs_smb_ses_inc_refcount(ses); found = true; goto search_end; } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 6a9661f3d324..d24118917610 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -3856,7 +3856,7 @@ void smb2_reconnect_server(struct work_struct *work) if (ses->tcon_ipc && ses->tcon_ipc->need_reconnect) { list_add_tail(&ses->tcon_ipc->rlist, &tmp_list); tcon_selected = tcon_exist = true; - ses->ses_count++; + cifs_smb_ses_inc_refcount(ses); } /* * handle the case where channel needs to reconnect @@ -3867,7 +3867,7 @@ void smb2_reconnect_server(struct work_struct *work) if (!tcon_selected && cifs_chan_needs_reconnect(ses, server)) { list_add_tail(&ses->rlist, &tmp_ses_list); ses_exist = true; - ses->ses_count++; + cifs_smb_ses_inc_refcount(ses); } spin_unlock(&ses->chan_lock); }