* [PATCH 1/9] smb: client: avoid unnecessary reconnects when refreshing referrals
@ 2024-09-18 5:15 Paulo Alcantara
2024-09-18 5:15 ` [PATCH 2/9] smb: client: improve purging of cached referrals Paulo Alcantara
` (7 more replies)
0 siblings, 8 replies; 11+ messages in thread
From: Paulo Alcantara @ 2024-09-18 5:15 UTC (permalink / raw)
To: smfrench; +Cc: linux-cifs, Paulo Alcantara
Do not mark tcons for reconnect when current connection matches any of
the targets returned by new referral even when there is no cached
entry.
Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
---
fs/smb/client/dfs_cache.c | 191 ++++++++++++++++++++++++--------------
1 file changed, 119 insertions(+), 72 deletions(-)
diff --git a/fs/smb/client/dfs_cache.c b/fs/smb/client/dfs_cache.c
index 11c8efecf7aa..3cf7c88489be 100644
--- a/fs/smb/client/dfs_cache.c
+++ b/fs/smb/client/dfs_cache.c
@@ -1095,16 +1095,18 @@ int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it,
return 0;
}
-static bool target_share_equal(struct TCP_Server_Info *server, const char *s1, const char *s2)
+static bool target_share_equal(struct cifs_tcon *tcon, const char *s1)
{
- char unc[sizeof("\\\\") + SERVER_NAME_LENGTH] = {0};
+ struct TCP_Server_Info *server = tcon->ses->server;
+ struct sockaddr_storage ss;
const char *host;
+ const char *s2 = &tcon->tree_name[1];
size_t hostlen;
- struct sockaddr_storage ss;
+ char unc[sizeof("\\\\") + SERVER_NAME_LENGTH] = {0};
bool match;
int rc;
- if (strcasecmp(s1, s2))
+ if (strcasecmp(s2, s1))
return false;
/*
@@ -1128,34 +1130,6 @@ static bool target_share_equal(struct TCP_Server_Info *server, const char *s1, c
return match;
}
-/*
- * Mark dfs tcon for reconnecting when the currently connected tcon does not match any of the new
- * 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)
-{
- struct dfs_cache_tgt_iterator *oit, *nit;
-
- for (oit = dfs_cache_get_tgt_iterator(old_tl); oit;
- oit = dfs_cache_get_next_tgt(old_tl, oit)) {
- for (nit = dfs_cache_get_tgt_iterator(new_tl); nit;
- 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_noreq_update_tgthint(path, nit);
- return;
- }
- }
- }
-
- cifs_dbg(FYI, "%s: no cached or matched targets. mark dfs share for reconnect.\n", __func__);
- cifs_signal_cifsd_for_reconnect(server, true);
-}
-
static bool is_ses_good(struct cifs_ses *ses)
{
struct TCP_Server_Info *server = ses->server;
@@ -1172,43 +1146,127 @@ static bool is_ses_good(struct cifs_ses *ses)
return ret;
}
-/* Refresh dfs referral of @ses and mark it for reconnect if needed */
-static void __refresh_ses_referral(struct cifs_ses *ses, bool force_refresh)
+static char *get_ses_refpath(struct cifs_ses *ses)
{
struct TCP_Server_Info *server = ses->server;
- DFS_CACHE_TGT_LIST(old_tl);
- DFS_CACHE_TGT_LIST(new_tl);
- bool needs_refresh = false;
- struct cache_entry *ce;
- unsigned int xid;
- char *path = NULL;
- int rc = 0;
-
- xid = get_xid();
+ char *path = ERR_PTR(-ENOENT);
mutex_lock(&server->refpath_lock);
if (server->leaf_fullpath) {
path = kstrdup(server->leaf_fullpath + 1, GFP_ATOMIC);
if (!path)
- rc = -ENOMEM;
+ path = ERR_PTR(-ENOMEM);
}
mutex_unlock(&server->refpath_lock);
- if (!path)
+ return path;
+}
+
+/* Refresh dfs referral of @ses */
+static void refresh_ses_referral(struct cifs_ses *ses)
+{
+ struct cache_entry *ce;
+ unsigned int xid;
+ char *path;
+ int rc = 0;
+
+ xid = get_xid();
+
+ path = get_ses_refpath(ses);
+ if (IS_ERR(path)) {
+ rc = PTR_ERR(path);
+ path = NULL;
goto out;
+ }
+
+ 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;
+ }
+
+ ce = cache_refresh_path(xid, ses, path, false);
+ if (!IS_ERR(ce))
+ up_read(&htable_rw_lock);
+ else
+ rc = PTR_ERR(ce);
+
+out:
+ free_xid(xid);
+ kfree(path);
+}
+
+static int __refresh_tcon_referral(struct cifs_tcon *tcon,
+ const char *path,
+ struct dfs_info3_param *refs,
+ int numrefs, bool force_refresh)
+{
+ struct cache_entry *ce;
+ bool reconnect = force_refresh;
+ int rc = 0;
+ int i;
+
+ if (unlikely(!numrefs))
+ return 0;
+
+ if (force_refresh) {
+ for (i = 0; i < numrefs; i++) {
+ /* TODO: include prefix paths in the matching */
+ if (target_share_equal(tcon, refs[i].node_name)) {
+ reconnect = false;
+ break;
+ }
+ }
+ }
+
+ down_write(&htable_rw_lock);
+ ce = lookup_cache_entry(path);
+ if (!IS_ERR(ce)) {
+ if (force_refresh || cache_entry_expired(ce))
+ rc = update_cache_entry_locked(ce, refs, numrefs);
+ } else if (PTR_ERR(ce) == -ENOENT) {
+ ce = add_cache_entry_locked(refs, numrefs);
+ }
+ up_write(&htable_rw_lock);
+
+ if (IS_ERR(ce))
+ rc = PTR_ERR(ce);
+ if (reconnect) {
+ cifs_tcon_dbg(FYI, "%s: mark for reconnect\n", __func__);
+ cifs_signal_cifsd_for_reconnect(tcon->ses->server, true);
+ }
+ return rc;
+}
+
+static void refresh_tcon_referral(struct cifs_tcon *tcon, bool force_refresh)
+{
+ struct dfs_info3_param *refs = NULL;
+ struct cache_entry *ce;
+ struct cifs_ses *ses;
+ unsigned int xid;
+ bool needs_refresh;
+ char *path;
+ int numrefs = 0;
+ int rc = 0;
+
+ xid = get_xid();
+ ses = tcon->ses;
+
+ path = get_ses_refpath(ses);
+ if (IS_ERR(path)) {
+ rc = PTR_ERR(path);
+ path = NULL;
+ goto out;
+ }
down_read(&htable_rw_lock);
ce = lookup_cache_entry(path);
needs_refresh = force_refresh || IS_ERR(ce) || cache_entry_expired(ce);
- if (!IS_ERR(ce)) {
- rc = get_targets(ce, &old_tl);
- cifs_dbg(FYI, "%s: get_targets: %d\n", __func__, rc);
- }
- up_read(&htable_rw_lock);
-
if (!needs_refresh) {
- rc = 0;
+ up_read(&htable_rw_lock);
goto out;
}
+ up_read(&htable_rw_lock);
ses = CIFS_DFS_ROOT_SES(ses);
if (!is_ses_good(ses)) {
@@ -1217,29 +1275,16 @@ static void __refresh_ses_referral(struct cifs_ses *ses, bool force_refresh)
goto out;
}
- 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(server, path, &old_tl, &new_tl);
+ rc = get_dfs_referral(xid, ses, path, &refs, &numrefs);
+ if (!rc) {
+ rc = __refresh_tcon_referral(tcon, path, refs,
+ numrefs, force_refresh);
}
out:
free_xid(xid);
- dfs_cache_free_tgts(&old_tl);
- dfs_cache_free_tgts(&new_tl);
kfree(path);
-}
-
-static inline void refresh_ses_referral(struct cifs_ses *ses)
-{
- __refresh_ses_referral(ses, false);
-}
-
-static inline void force_refresh_ses_referral(struct cifs_ses *ses)
-{
- __refresh_ses_referral(ses, true);
+ free_dfs_info_array(refs, numrefs);
}
/**
@@ -1280,7 +1325,7 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
*/
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
- force_refresh_ses_referral(tcon->ses);
+ refresh_tcon_referral(tcon, true);
return 0;
}
@@ -1291,9 +1336,11 @@ void dfs_cache_refresh(struct work_struct *work)
struct cifs_ses *ses;
tcon = container_of(work, struct cifs_tcon, dfs_cache_work.work);
+ ses = tcon->ses->dfs_root_ses;
- for (ses = tcon->ses; ses; ses = ses->dfs_root_ses)
+ for (; ses; ses = ses->dfs_root_ses)
refresh_ses_referral(ses);
+ refresh_tcon_referral(tcon, false);
queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,
atomic_read(&dfs_cache_ttl) * HZ);
--
2.46.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 2/9] smb: client: improve purging of cached referrals 2024-09-18 5:15 [PATCH 1/9] smb: client: avoid unnecessary reconnects when refreshing referrals Paulo Alcantara @ 2024-09-18 5:15 ` Paulo Alcantara 2024-09-18 5:15 ` [PATCH 3/9] smb: client: fix DFS interlink failover Paulo Alcantara ` (6 subsequent siblings) 7 siblings, 0 replies; 11+ messages in thread From: Paulo Alcantara @ 2024-09-18 5:15 UTC (permalink / raw) To: smfrench; +Cc: linux-cifs, Paulo Alcantara Purge cached referrals that have a single target when reaching maximum of cache size as the client won't need them to failover. Otherwise remove oldest cache entry. Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> --- fs/smb/client/dfs_cache.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/fs/smb/client/dfs_cache.c b/fs/smb/client/dfs_cache.c index 3cf7c88489be..e496dbf8c622 100644 --- a/fs/smb/client/dfs_cache.c +++ b/fs/smb/client/dfs_cache.c @@ -126,6 +126,7 @@ static inline void free_tgts(struct cache_entry *ce) static inline void flush_cache_ent(struct cache_entry *ce) { + cifs_dbg(FYI, "%s: %s\n", __func__, ce->path); hlist_del_init(&ce->hlist); kfree(ce->path); free_tgts(ce); @@ -441,34 +442,31 @@ static struct cache_entry *alloc_cache_entry(struct dfs_info3_param *refs, int n return ce; } -static void remove_oldest_entry_locked(void) +/* Remove all referrals that have a single target or oldest entry */ +static void purge_cache(void) { int i; struct cache_entry *ce; - struct cache_entry *to_del = NULL; - - WARN_ON(!rwsem_is_locked(&htable_rw_lock)); + struct cache_entry *oldest = NULL; for (i = 0; i < CACHE_HTABLE_SIZE; i++) { struct hlist_head *l = &cache_htable[i]; + struct hlist_node *n; - hlist_for_each_entry(ce, l, hlist) { + hlist_for_each_entry_safe(ce, n, l, hlist) { if (hlist_unhashed(&ce->hlist)) continue; - if (!to_del || timespec64_compare(&ce->etime, - &to_del->etime) < 0) - to_del = ce; + if (ce->numtgts == 1) + flush_cache_ent(ce); + else if (!oldest || + timespec64_compare(&ce->etime, + &oldest->etime) < 0) + oldest = ce; } } - if (!to_del) { - cifs_dbg(FYI, "%s: no entry to remove\n", __func__); - return; - } - - cifs_dbg(FYI, "%s: removing entry\n", __func__); - dump_ce(to_del); - flush_cache_ent(to_del); + if (atomic_read(&cache_count) >= CACHE_MAX_ENTRIES && oldest) + flush_cache_ent(oldest); } /* Add a new DFS cache entry */ @@ -484,7 +482,7 @@ static struct cache_entry *add_cache_entry_locked(struct dfs_info3_param *refs, if (atomic_read(&cache_count) >= CACHE_MAX_ENTRIES) { cifs_dbg(FYI, "%s: reached max cache size (%d)\n", __func__, CACHE_MAX_ENTRIES); - remove_oldest_entry_locked(); + purge_cache(); } rc = cache_entry_hash(refs[0].path_name, strlen(refs[0].path_name), &hash); -- 2.46.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/9] smb: client: fix DFS interlink failover 2024-09-18 5:15 [PATCH 1/9] smb: client: avoid unnecessary reconnects when refreshing referrals Paulo Alcantara 2024-09-18 5:15 ` [PATCH 2/9] smb: client: improve purging of cached referrals Paulo Alcantara @ 2024-09-18 5:15 ` Paulo Alcantara 2024-09-18 5:15 ` [PATCH 4/9] smb: client: stop flooding dmesg in smb2_calc_signature() Paulo Alcantara ` (5 subsequent siblings) 7 siblings, 0 replies; 11+ messages in thread From: Paulo Alcantara @ 2024-09-18 5:15 UTC (permalink / raw) To: smfrench; +Cc: linux-cifs, Paulo Alcantara The DFS interlinks point to different DFS namespaces so make sure to use the correct DFS root server to chase any DFS links under it by storing the SMB session in dfs_ref_walk structure and then using it on every referral walk. Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> --- fs/smb/client/cifsglob.h | 3 ++ fs/smb/client/cifsproto.h | 12 ++----- fs/smb/client/connect.c | 41 +++++++++++---------- fs/smb/client/dfs.c | 73 ++++++++++++++++++-------------------- fs/smb/client/dfs.h | 42 ++++++++++++++-------- fs/smb/client/dfs_cache.c | 3 +- fs/smb/client/fs_context.h | 1 + fs/smb/client/misc.c | 3 ++ fs/smb/client/namespace.c | 2 +- 9 files changed, 94 insertions(+), 86 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 939ef5844571..e969d1ae2498 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -821,6 +821,7 @@ struct TCP_Server_Info { * format: \\HOST\SHARE[\OPTIONAL PATH] */ char *leaf_fullpath; + bool dfs_conn:1; }; static inline bool is_smb1(struct TCP_Server_Info *server) @@ -1059,6 +1060,7 @@ struct cifs_ses { struct list_head smb_ses_list; struct list_head rlist; /* reconnect list */ struct list_head tcon_list; + struct list_head dlist; /* dfs list */ struct cifs_tcon *tcon_ipc; spinlock_t ses_lock; /* protect anything here that is not protected */ struct mutex session_mutex; @@ -1287,6 +1289,7 @@ struct cifs_tcon { /* BB add field for back pointer to sb struct(s)? */ #ifdef CONFIG_CIFS_DFS_UPCALL struct delayed_work dfs_cache_work; + struct list_head dfs_ses_list; #endif struct delayed_work query_interfaces; /* query interfaces workqueue job */ char *origin_fullpath; /* canonical copy of smb3_fs_context::source */ diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index c69e3f48a60c..68c716e6261b 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -724,15 +724,9 @@ static inline int cifs_create_options(struct cifs_sb_info *cifs_sb, int options) int cifs_wait_for_server_reconnect(struct TCP_Server_Info *server, bool retry); -/* Put references of @ses and its children */ static inline void cifs_put_smb_ses(struct cifs_ses *ses) { - struct cifs_ses *next; - - do { - next = ses->dfs_root_ses; - __cifs_put_smb_ses(ses); - } while ((ses = next)); + __cifs_put_smb_ses(ses); } /* Get an active reference of @ses and its children. @@ -746,9 +740,7 @@ static inline void cifs_put_smb_ses(struct cifs_ses *ses) static inline void cifs_smb_ses_inc_refcount(struct cifs_ses *ses) { lockdep_assert_held(&cifs_tcp_ses_lock); - - for (; ses; ses = ses->dfs_root_ses) - ses->ses_count++; + ses->ses_count++; } static inline bool dfs_src_pathname_equal(const char *s1, const char *s2) diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 08a41c7aaf72..76f02739dda5 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -1530,6 +1530,9 @@ static int match_server(struct TCP_Server_Info *server, if (server->nosharesock) return 0; + if (!match_super && (ctx->dfs_conn || server->dfs_conn)) + return 0; + /* If multidialect negotiation see if existing sessions match one */ if (strcmp(ctx->vals->version_string, SMB3ANY_VERSION_STRING) == 0) { if (server->vals->protocol_id < SMB30_PROT_ID) @@ -1723,6 +1726,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, if (ctx->nosharesock) tcp_ses->nosharesock = true; + tcp_ses->dfs_conn = ctx->dfs_conn; tcp_ses->ops = ctx->ops; tcp_ses->vals = ctx->vals; @@ -1873,13 +1877,15 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, } /* this function must be called with ses_lock and chan_lock held */ -static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx) +static int match_session(struct cifs_ses *ses, + struct smb3_fs_context *ctx, + bool match_super) { if (ctx->sectype != Unspecified && ctx->sectype != ses->sectype) return 0; - if (ctx->dfs_root_ses != ses->dfs_root_ses) + if (!match_super && ctx->dfs_root_ses != ses->dfs_root_ses) return 0; /* @@ -1998,7 +2004,7 @@ 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, false)) { spin_unlock(&ses->chan_lock); spin_unlock(&ses->ses_lock); ret = ses; @@ -2382,8 +2388,6 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) * need to lock before changing something in the session. */ spin_lock(&cifs_tcp_ses_lock); - if (ctx->dfs_root_ses) - cifs_smb_ses_inc_refcount(ctx->dfs_root_ses); ses->dfs_root_ses = ctx->dfs_root_ses; list_add(&ses->smb_ses_list, &server->smb_ses_list); spin_unlock(&cifs_tcp_ses_lock); @@ -2458,6 +2462,7 @@ cifs_put_tcon(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace) { unsigned int xid; struct cifs_ses *ses; + LIST_HEAD(ses_list); /* * IPC tcon share the lifetime of their session and are @@ -2482,6 +2487,9 @@ cifs_put_tcon(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace) list_del_init(&tcon->tcon_list); tcon->status = TID_EXITING; +#ifdef CONFIG_CIFS_DFS_UPCALL + list_replace_init(&tcon->dfs_ses_list, &ses_list); +#endif spin_unlock(&tcon->tc_lock); spin_unlock(&cifs_tcp_ses_lock); @@ -2509,6 +2517,9 @@ cifs_put_tcon(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace) cifs_fscache_release_super_cookie(tcon); tconInfoFree(tcon, netfs_trace_tcon_ref_free); cifs_put_smb_ses(ses); +#ifdef CONFIG_CIFS_DFS_UPCALL + dfs_put_root_smb_sessions(&ses_list); +#endif } /** @@ -2892,7 +2903,7 @@ cifs_match_super(struct super_block *sb, void *data) spin_lock(&ses->chan_lock); spin_lock(&tcon->tc_lock); if (!match_server(tcp_srv, ctx, true) || - !match_session(ses, ctx) || + !match_session(ses, ctx, true) || !match_tcon(tcon, ctx) || !match_prepath(sb, tcon, mnt_data)) { rc = 0; @@ -3623,13 +3634,12 @@ int cifs_is_path_remote(struct cifs_mount_ctx *mnt_ctx) int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) { struct cifs_mount_ctx mnt_ctx = { .cifs_sb = cifs_sb, .fs_ctx = ctx, }; - bool isdfs; int rc; - rc = dfs_mount_share(&mnt_ctx, &isdfs); + rc = dfs_mount_share(&mnt_ctx); if (rc) goto error; - if (!isdfs) + if (!ctx->dfs_conn) goto out; /* @@ -4034,7 +4044,7 @@ cifs_set_vol_auth(struct smb3_fs_context *ctx, struct cifs_ses *ses) } static struct cifs_tcon * -__cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) +cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) { int rc; struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb); @@ -4132,17 +4142,6 @@ __cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) return tcon; } -static struct cifs_tcon * -cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) -{ - struct cifs_tcon *ret; - - cifs_mount_lock(); - ret = __cifs_construct_tcon(cifs_sb, fsuid); - cifs_mount_unlock(); - return ret; -} - struct cifs_tcon * cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb) { diff --git a/fs/smb/client/dfs.c b/fs/smb/client/dfs.c index 3ec965547e3d..3f6077c68d68 100644 --- a/fs/smb/client/dfs.c +++ b/fs/smb/client/dfs.c @@ -69,7 +69,7 @@ static int get_session(struct cifs_mount_ctx *mnt_ctx, const char *full_path) * Get an active reference of @ses so that next call to cifs_put_tcon() won't * release it as any new DFS referrals must go through its IPC tcon. */ -static void add_root_smb_session(struct cifs_mount_ctx *mnt_ctx) +static void set_root_smb_session(struct cifs_mount_ctx *mnt_ctx) { struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; struct cifs_ses *ses = mnt_ctx->ses; @@ -95,7 +95,7 @@ static inline int parse_dfs_target(struct smb3_fs_context *ctx, return rc; } -static int set_ref_paths(struct cifs_mount_ctx *mnt_ctx, +static int setup_dfs_ref(struct cifs_mount_ctx *mnt_ctx, struct dfs_info3_param *tgt, struct dfs_ref_walk *rw) { @@ -120,6 +120,7 @@ static int set_ref_paths(struct cifs_mount_ctx *mnt_ctx, } ref_walk_path(rw) = ref_path; ref_walk_fpath(rw) = full_path; + ref_walk_ses(rw) = ctx->dfs_root_ses; return 0; } @@ -128,11 +129,11 @@ static int __dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx, { struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; struct dfs_info3_param tgt = {}; - bool is_refsrv; int rc = -ENOENT; again: do { + ctx->dfs_root_ses = ref_walk_ses(rw); if (ref_walk_empty(rw)) { rc = dfs_get_referral(mnt_ctx, ref_walk_path(rw) + 1, NULL, ref_walk_tl(rw)); @@ -158,10 +159,7 @@ static int __dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx, if (rc) continue; - is_refsrv = tgt.server_type == DFS_TYPE_ROOT || - DFS_INTERLINK(tgt.flags); ref_walk_set_tgt_hint(rw); - if (tgt.flags & DFSREF_STORAGE_SERVER) { rc = cifs_mount_get_tcon(mnt_ctx); if (!rc) @@ -172,12 +170,10 @@ static int __dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx, continue; } - if (is_refsrv) - add_root_smb_session(mnt_ctx); - + set_root_smb_session(mnt_ctx); rc = ref_walk_advance(rw); if (!rc) { - rc = set_ref_paths(mnt_ctx, &tgt, rw); + rc = setup_dfs_ref(mnt_ctx, &tgt, rw); if (!rc) { rc = -EREMOTE; goto again; @@ -193,20 +189,22 @@ static int __dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx, return rc; } -static int dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx) +static int dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx, + struct dfs_ref_walk **rw) { - struct dfs_ref_walk *rw; int rc; - rw = ref_walk_alloc(); - if (IS_ERR(rw)) - return PTR_ERR(rw); + *rw = ref_walk_alloc(); + if (IS_ERR(*rw)) { + rc = PTR_ERR(*rw); + *rw = NULL; + return rc; + } - ref_walk_init(rw); - rc = set_ref_paths(mnt_ctx, NULL, rw); + ref_walk_init(*rw); + rc = setup_dfs_ref(mnt_ctx, NULL, *rw); if (!rc) - rc = __dfs_referral_walk(mnt_ctx, rw); - ref_walk_free(rw); + rc = __dfs_referral_walk(mnt_ctx, *rw); return rc; } @@ -214,16 +212,16 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx) { struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb; struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; + struct dfs_ref_walk *rw = NULL; struct cifs_tcon *tcon; char *origin_fullpath; - bool new_tcon = true; int rc; origin_fullpath = dfs_get_path(cifs_sb, ctx->source); if (IS_ERR(origin_fullpath)) return PTR_ERR(origin_fullpath); - rc = dfs_referral_walk(mnt_ctx); + rc = dfs_referral_walk(mnt_ctx, &rw); if (!rc) { /* * Prevent superblock from being created with any missing @@ -241,21 +239,16 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx) tcon = mnt_ctx->tcon; spin_lock(&tcon->tc_lock); - if (!tcon->origin_fullpath) { - tcon->origin_fullpath = origin_fullpath; - origin_fullpath = NULL; - } else { - new_tcon = false; - } + tcon->origin_fullpath = origin_fullpath; + origin_fullpath = NULL; + ref_walk_set_tcon(rw, tcon); spin_unlock(&tcon->tc_lock); - - if (new_tcon) { - queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work, - dfs_cache_get_ttl() * HZ); - } + queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work, + dfs_cache_get_ttl() * HZ); out: kfree(origin_fullpath); + ref_walk_free(rw); return rc; } @@ -279,7 +272,7 @@ static int update_fs_context_dstaddr(struct smb3_fs_context *ctx) return rc; } -int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs) +int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx) { struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; bool nodfs = ctx->nodfs; @@ -289,7 +282,6 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs) if (rc) return rc; - *isdfs = false; rc = get_session(mnt_ctx, NULL); if (rc) return rc; @@ -317,10 +309,15 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs) return rc; } - *isdfs = true; - add_root_smb_session(mnt_ctx); - rc = __dfs_mount_share(mnt_ctx); - dfs_put_root_smb_sessions(mnt_ctx); + if (!ctx->dfs_conn) { + ctx->dfs_conn = true; + cifs_mount_put_conns(mnt_ctx); + rc = get_session(mnt_ctx, NULL); + } + if (!rc) { + set_root_smb_session(mnt_ctx); + rc = __dfs_mount_share(mnt_ctx); + } return rc; } diff --git a/fs/smb/client/dfs.h b/fs/smb/client/dfs.h index e5c4dcf83750..a23150676d9e 100644 --- a/fs/smb/client/dfs.h +++ b/fs/smb/client/dfs.h @@ -19,6 +19,7 @@ struct dfs_ref { char *path; char *full_path; + struct cifs_ses *ses; struct dfs_cache_tgt_list tl; struct dfs_cache_tgt_iterator *tit; }; @@ -38,6 +39,7 @@ struct dfs_ref_walk { #define ref_walk_path(w) (ref_walk_cur(w)->path) #define ref_walk_fpath(w) (ref_walk_cur(w)->full_path) #define ref_walk_tl(w) (&ref_walk_cur(w)->tl) +#define ref_walk_ses(w) (ref_walk_cur(w)->ses) static inline struct dfs_ref_walk *ref_walk_alloc(void) { @@ -60,14 +62,19 @@ static inline void __ref_walk_free(struct dfs_ref *ref) kfree(ref->path); kfree(ref->full_path); dfs_cache_free_tgts(&ref->tl); + if (ref->ses) + cifs_put_smb_ses(ref->ses); memset(ref, 0, sizeof(*ref)); } static inline void ref_walk_free(struct dfs_ref_walk *rw) { - struct dfs_ref *ref = ref_walk_start(rw); + struct dfs_ref *ref; - for (; ref <= ref_walk_end(rw); ref++) + if (!rw) + return; + + for (ref = ref_walk_start(rw); ref <= ref_walk_end(rw); ref++) __ref_walk_free(ref); kfree(rw); } @@ -116,9 +123,22 @@ static inline void ref_walk_set_tgt_hint(struct dfs_ref_walk *rw) ref_walk_tit(rw)); } +static inline void ref_walk_set_tcon(struct dfs_ref_walk *rw, + struct cifs_tcon *tcon) +{ + struct dfs_ref *ref = ref_walk_start(rw); + + for (; ref <= ref_walk_cur(rw); ref++) { + if (WARN_ON_ONCE(!ref->ses)) + continue; + list_add_tail(&ref->ses->dlist, &tcon->dfs_ses_list); + ref->ses = NULL; + } +} + int dfs_parse_target_referral(const char *full_path, const struct dfs_info3_param *ref, struct smb3_fs_context *ctx); -int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs); +int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx); static inline char *dfs_get_path(struct cifs_sb_info *cifs_sb, const char *path) { @@ -142,20 +162,14 @@ static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, const char *p * references of all DFS root sessions that were used across the mount process * in dfs_mount_share(). */ -static inline void dfs_put_root_smb_sessions(struct cifs_mount_ctx *mnt_ctx) +static inline void dfs_put_root_smb_sessions(struct list_head *head) { - const struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; - struct cifs_ses *ses = ctx->dfs_root_ses; - struct cifs_ses *cur; + struct cifs_ses *ses, *n; - if (!ses) - return; - - for (cur = ses; cur; cur = cur->dfs_root_ses) { - if (cur->dfs_root_ses) - cifs_put_smb_ses(cur->dfs_root_ses); + list_for_each_entry_safe(ses, n, head, dlist) { + list_del_init(&ses->dlist); + cifs_put_smb_ses(ses); } - cifs_put_smb_ses(ses); } #endif /* _CIFS_DFS_H */ diff --git a/fs/smb/client/dfs_cache.c b/fs/smb/client/dfs_cache.c index e496dbf8c622..110f03df012a 100644 --- a/fs/smb/client/dfs_cache.c +++ b/fs/smb/client/dfs_cache.c @@ -1334,9 +1334,8 @@ void dfs_cache_refresh(struct work_struct *work) struct cifs_ses *ses; tcon = container_of(work, struct cifs_tcon, dfs_cache_work.work); - ses = tcon->ses->dfs_root_ses; - for (; ses; ses = ses->dfs_root_ses) + list_for_each_entry(ses, &tcon->dfs_ses_list, dlist) refresh_ses_referral(ses); refresh_tcon_referral(tcon, false); diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h index cf577ec0dd0a..69f9d938b336 100644 --- a/fs/smb/client/fs_context.h +++ b/fs/smb/client/fs_context.h @@ -284,6 +284,7 @@ struct smb3_fs_context { struct cifs_ses *dfs_root_ses; bool dfs_automount:1; /* set for dfs automount only */ enum cifs_reparse_type reparse_type; + bool dfs_conn:1; /* set for dfs mounts */ }; extern const struct fs_parameter_spec smb3_fs_parameters[]; diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c index dab526191b07..47b861517bed 100644 --- a/fs/smb/client/misc.c +++ b/fs/smb/client/misc.c @@ -145,6 +145,9 @@ tcon_info_alloc(bool dir_leases_enabled, enum smb3_tcon_ref_trace trace) mutex_init(&ret_buf->fscache_lock); #endif trace_smb3_tcon_ref(ret_buf->debug_id, ret_buf->tc_count, trace); +#ifdef CONFIG_CIFS_DFS_UPCALL + INIT_LIST_HEAD(&ret_buf->dfs_ses_list); +#endif return ret_buf; } diff --git a/fs/smb/client/namespace.c b/fs/smb/client/namespace.c index 4a517b280f2b..0f788031b740 100644 --- a/fs/smb/client/namespace.c +++ b/fs/smb/client/namespace.c @@ -240,7 +240,7 @@ static struct vfsmount *cifs_do_automount(struct path *path) ctx->source = NULL; goto out; } - ctx->dfs_automount = is_dfs_mount(mntpt); + ctx->dfs_automount = ctx->dfs_conn = is_dfs_mount(mntpt); cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s dfs_automount=%d\n", __func__, ctx->source, ctx->UNC, ctx->prepath, ctx->dfs_automount); -- 2.46.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 4/9] smb: client: stop flooding dmesg in smb2_calc_signature() 2024-09-18 5:15 [PATCH 1/9] smb: client: avoid unnecessary reconnects when refreshing referrals Paulo Alcantara 2024-09-18 5:15 ` [PATCH 2/9] smb: client: improve purging of cached referrals Paulo Alcantara 2024-09-18 5:15 ` [PATCH 3/9] smb: client: fix DFS interlink failover Paulo Alcantara @ 2024-09-18 5:15 ` Paulo Alcantara 2024-09-25 2:23 ` Steve French 2024-09-18 5:15 ` [PATCH 5/9] smb: client: print failed session logoffs with FYI Paulo Alcantara ` (4 subsequent siblings) 7 siblings, 1 reply; 11+ messages in thread From: Paulo Alcantara @ 2024-09-18 5:15 UTC (permalink / raw) To: smfrench; +Cc: linux-cifs, Paulo Alcantara When having several mounts that share same credential and the client couldn't re-establish an SMB session due to an expired kerberos ticket or rotated password, smb2_calc_signature() will end up flooding dmesg when not finding SMB sessions to calculate signatures. Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> --- fs/smb/client/smb2transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index e4636fca821d..c8bf0000f73b 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -242,7 +242,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, ses = smb2_find_smb_ses(server, le64_to_cpu(shdr->SessionId)); if (unlikely(!ses)) { - cifs_server_dbg(VFS, "%s: Could not find session\n", __func__); + cifs_server_dbg(FYI, "%s: Could not find session\n", __func__); return -ENOENT; } -- 2.46.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 4/9] smb: client: stop flooding dmesg in smb2_calc_signature() 2024-09-18 5:15 ` [PATCH 4/9] smb: client: stop flooding dmesg in smb2_calc_signature() Paulo Alcantara @ 2024-09-25 2:23 ` Steve French 2024-09-25 14:30 ` Paulo Alcantara 0 siblings, 1 reply; 11+ messages in thread From: Steve French @ 2024-09-25 2:23 UTC (permalink / raw) To: Paulo Alcantara; +Cc: linux-cifs any thoughts on whether this should be at least a log once event? How to make it log at least once, but also something that could be turned on (doesn't seem like it makes sense to make it an dynamic trace point though ... right?) On Wed, Sep 18, 2024 at 12:16 AM Paulo Alcantara <pc@manguebit.com> wrote: > > When having several mounts that share same credential and the client > couldn't re-establish an SMB session due to an expired kerberos ticket > or rotated password, smb2_calc_signature() will end up flooding dmesg > when not finding SMB sessions to calculate signatures. > > Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> > --- > fs/smb/client/smb2transport.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c > index e4636fca821d..c8bf0000f73b 100644 > --- a/fs/smb/client/smb2transport.c > +++ b/fs/smb/client/smb2transport.c > @@ -242,7 +242,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, > > ses = smb2_find_smb_ses(server, le64_to_cpu(shdr->SessionId)); > if (unlikely(!ses)) { > - cifs_server_dbg(VFS, "%s: Could not find session\n", __func__); > + cifs_server_dbg(FYI, "%s: Could not find session\n", __func__); > return -ENOENT; > } > > -- > 2.46.0 > -- Thanks, Steve ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 4/9] smb: client: stop flooding dmesg in smb2_calc_signature() 2024-09-25 2:23 ` Steve French @ 2024-09-25 14:30 ` Paulo Alcantara 0 siblings, 0 replies; 11+ messages in thread From: Paulo Alcantara @ 2024-09-25 14:30 UTC (permalink / raw) To: Steve French; +Cc: linux-cifs Steve French <smfrench@gmail.com> writes: > any thoughts on whether this should be at least a log once event? How > to make it log at least once, but also something that could be turned > on (doesn't seem like it makes sense to make it an dynamic trace point > though ... right?) Yep, having it logged once with "VFS | ONCE" would be fine. Feel free to change it. A dynamic trace point would be great, too. This could be done in a separate patch. ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 5/9] smb: client: print failed session logoffs with FYI 2024-09-18 5:15 [PATCH 1/9] smb: client: avoid unnecessary reconnects when refreshing referrals Paulo Alcantara ` (2 preceding siblings ...) 2024-09-18 5:15 ` [PATCH 4/9] smb: client: stop flooding dmesg in smb2_calc_signature() Paulo Alcantara @ 2024-09-18 5:15 ` Paulo Alcantara 2024-09-18 5:15 ` [PATCH 6/9] smb: client: stop flooding dmesg on failed session setups Paulo Alcantara ` (3 subsequent siblings) 7 siblings, 0 replies; 11+ messages in thread From: Paulo Alcantara @ 2024-09-18 5:15 UTC (permalink / raw) To: smfrench; +Cc: linux-cifs, Paulo Alcantara Do not flood dmesg with failed session logoffs as kerberos tickets getting expired or passwords being rotated is a very common scenario. Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> --- fs/smb/client/connect.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 76f02739dda5..e1df9f093339 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -2064,8 +2064,7 @@ void __cifs_put_smb_ses(struct cifs_ses *ses) if (do_logoff) { xid = get_xid(); rc = server->ops->logoff(xid, ses); - if (rc) - cifs_server_dbg(VFS, "%s: Session Logoff failure rc=%d\n", + cifs_server_dbg(FYI, "%s: Session Logoff: rc=%d\n", __func__, rc); _free_xid(xid); } -- 2.46.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 6/9] smb: client: stop flooding dmesg on failed session setups 2024-09-18 5:15 [PATCH 1/9] smb: client: avoid unnecessary reconnects when refreshing referrals Paulo Alcantara ` (3 preceding siblings ...) 2024-09-18 5:15 ` [PATCH 5/9] smb: client: print failed session logoffs with FYI Paulo Alcantara @ 2024-09-18 5:15 ` Paulo Alcantara 2024-09-18 5:15 ` [PATCH 7/9] smb: client: stop flooding dmesg with automounts Paulo Alcantara ` (2 subsequent siblings) 7 siblings, 0 replies; 11+ messages in thread From: Paulo Alcantara @ 2024-09-18 5:15 UTC (permalink / raw) To: smfrench; +Cc: linux-cifs, Paulo Alcantara Stop flooding dmesg over failed session setups as kerberos tickets getting expired or passwords being rotated is a very common scenario. Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> --- fs/smb/client/connect.c | 4 +++- fs/smb/client/smb2pdu.c | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index e1df9f093339..a382f532974a 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -3390,6 +3390,8 @@ int cifs_mount_get_session(struct cifs_mount_ctx *mnt_ctx) ses = cifs_get_smb_ses(server, ctx); if (IS_ERR(ses)) { rc = PTR_ERR(ses); + if (rc == -ENOKEY && ctx->sectype == Kerberos) + cifs_dbg(VFS, "Verify user has a krb5 ticket and keyutils is installed\n"); ses = NULL; goto out; } @@ -4008,7 +4010,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, rc = server->ops->sess_setup(xid, ses, server, nls_info); if (rc) { - cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc); + cifs_server_dbg(FYI, "Send error in SessSetup = %d\n", rc); spin_lock(&ses->ses_lock); if (ses->ses_status == SES_IN_SETUP) ses->ses_status = SES_NEED_RECON; diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index f68746becd64..1f78b7368b00 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -1626,8 +1626,8 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data) spnego_key = cifs_get_spnego_key(ses, server); if (IS_ERR(spnego_key)) { rc = PTR_ERR(spnego_key); - if (rc == -ENOKEY) - cifs_dbg(VFS, "Verify user has a krb5 ticket and keyutils is installed\n"); + cifs_dbg(FYI, "%s: couldn't auth with kerberos: %d\n", + __func__, rc); spnego_key = NULL; goto out; } -- 2.46.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 7/9] smb: client: stop flooding dmesg with automounts 2024-09-18 5:15 [PATCH 1/9] smb: client: avoid unnecessary reconnects when refreshing referrals Paulo Alcantara ` (4 preceding siblings ...) 2024-09-18 5:15 ` [PATCH 6/9] smb: client: stop flooding dmesg on failed session setups Paulo Alcantara @ 2024-09-18 5:15 ` Paulo Alcantara 2024-09-18 5:15 ` [PATCH 8/9] smb: client: fix DFS failover in multiuser mounts Paulo Alcantara 2024-09-18 5:15 ` [PATCH 9/9] smb: client: propagate error from cifs_construct_tcon() Paulo Alcantara 7 siblings, 0 replies; 11+ messages in thread From: Paulo Alcantara @ 2024-09-18 5:15 UTC (permalink / raw) To: smfrench; +Cc: linux-cifs, Paulo Alcantara Avoid logging info and expected errors when automounting DFS links and reparse mount points as a share might contain hundreds of them and the client would end up flooding dmesg. Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> --- fs/smb/client/cifsfs.c | 4 ++-- fs/smb/client/connect.c | 3 ++- fs/smb/client/dfs.c | 3 +-- fs/smb/client/fs_context.h | 2 +- fs/smb/client/namespace.c | 5 +++-- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index 2a2523c93944..c91cf57f337c 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -910,7 +910,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, if (cifsFYI) { cifs_dbg(FYI, "%s: devname=%s flags=0x%x\n", __func__, old_ctx->source, flags); - } else { + } else if (!old_ctx->automount) { cifs_info("Attempting to mount %s\n", old_ctx->source); } @@ -937,7 +937,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, rc = cifs_mount(cifs_sb, cifs_sb->ctx); if (rc) { - if (!(flags & SB_SILENT)) + if (!(flags & SB_SILENT) && !old_ctx->automount) cifs_dbg(VFS, "cifs_mount failed w/return code = %d\n", rc); root = ERR_PTR(rc); diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index a382f532974a..e71b6933464a 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -3390,7 +3390,8 @@ int cifs_mount_get_session(struct cifs_mount_ctx *mnt_ctx) ses = cifs_get_smb_ses(server, ctx); if (IS_ERR(ses)) { rc = PTR_ERR(ses); - if (rc == -ENOKEY && ctx->sectype == Kerberos) + if (rc == -ENOKEY && ctx->sectype == Kerberos && + !ctx->automount) cifs_dbg(VFS, "Verify user has a krb5 ticket and keyutils is installed\n"); ses = NULL; goto out; diff --git a/fs/smb/client/dfs.c b/fs/smb/client/dfs.c index 3f6077c68d68..96db96062a8a 100644 --- a/fs/smb/client/dfs.c +++ b/fs/smb/client/dfs.c @@ -263,11 +263,10 @@ static int update_fs_context_dstaddr(struct smb3_fs_context *ctx) struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr; int rc = 0; - if (!ctx->nodfs && ctx->dfs_automount) { + if (!ctx->nodfs && ctx->automount && ctx->dfs_conn) { rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL); if (!rc) cifs_set_port(addr, ctx->port); - ctx->dfs_automount = false; } return rc; } diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h index 69f9d938b336..5135f7b2e8d3 100644 --- a/fs/smb/client/fs_context.h +++ b/fs/smb/client/fs_context.h @@ -282,7 +282,7 @@ struct smb3_fs_context { bool witness:1; /* use witness protocol */ char *leaf_fullpath; struct cifs_ses *dfs_root_ses; - bool dfs_automount:1; /* set for dfs automount only */ + bool automount:1; /* set for automounts */ enum cifs_reparse_type reparse_type; bool dfs_conn:1; /* set for dfs mounts */ }; diff --git a/fs/smb/client/namespace.c b/fs/smb/client/namespace.c index 0f788031b740..9bfc0a592d27 100644 --- a/fs/smb/client/namespace.c +++ b/fs/smb/client/namespace.c @@ -220,6 +220,7 @@ static struct vfsmount *cifs_do_automount(struct path *path) tmp.leaf_fullpath = NULL; tmp.UNC = tmp.prepath = NULL; tmp.dfs_root_ses = NULL; + tmp.automount = true; fs_context_set_ids(&tmp); rc = smb3_fs_context_dup(ctx, &tmp); @@ -240,9 +241,9 @@ static struct vfsmount *cifs_do_automount(struct path *path) ctx->source = NULL; goto out; } - ctx->dfs_automount = ctx->dfs_conn = is_dfs_mount(mntpt); + ctx->dfs_conn = is_dfs_mount(mntpt); cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s dfs_automount=%d\n", - __func__, ctx->source, ctx->UNC, ctx->prepath, ctx->dfs_automount); + __func__, ctx->source, ctx->UNC, ctx->prepath, ctx->dfs_conn); mnt = fc_mount(fc); out: -- 2.46.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 8/9] smb: client: fix DFS failover in multiuser mounts 2024-09-18 5:15 [PATCH 1/9] smb: client: avoid unnecessary reconnects when refreshing referrals Paulo Alcantara ` (5 preceding siblings ...) 2024-09-18 5:15 ` [PATCH 7/9] smb: client: stop flooding dmesg with automounts Paulo Alcantara @ 2024-09-18 5:15 ` Paulo Alcantara 2024-09-18 5:15 ` [PATCH 9/9] smb: client: propagate error from cifs_construct_tcon() Paulo Alcantara 7 siblings, 0 replies; 11+ messages in thread From: Paulo Alcantara @ 2024-09-18 5:15 UTC (permalink / raw) To: smfrench; +Cc: linux-cifs, Paulo Alcantara For sessions and tcons created on behalf of new users accessing a multiuser mount, matching their sessions in tcon_super_cb() with master tcon will always lead to false as every new user will have its own session and tcon. All multiuser sessions, however, will inherit ->dfs_root_ses from master tcon, so match it instead. Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> --- fs/smb/client/misc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c index 47b861517bed..054f10ebf65a 100644 --- a/fs/smb/client/misc.c +++ b/fs/smb/client/misc.c @@ -1111,7 +1111,8 @@ static void tcon_super_cb(struct super_block *sb, void *arg) t2 = cifs_sb_master_tcon(cifs_sb); spin_lock(&t2->tc_lock); - if (t1->ses == t2->ses && + if ((t1->ses == t2->ses || + t1->ses->dfs_root_ses == t2->ses->dfs_root_ses) && t1->ses->server == t2->ses->server && t2->origin_fullpath && dfs_src_pathname_equal(t2->origin_fullpath, t1->origin_fullpath)) -- 2.46.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 9/9] smb: client: propagate error from cifs_construct_tcon() 2024-09-18 5:15 [PATCH 1/9] smb: client: avoid unnecessary reconnects when refreshing referrals Paulo Alcantara ` (6 preceding siblings ...) 2024-09-18 5:15 ` [PATCH 8/9] smb: client: fix DFS failover in multiuser mounts Paulo Alcantara @ 2024-09-18 5:15 ` Paulo Alcantara 7 siblings, 0 replies; 11+ messages in thread From: Paulo Alcantara @ 2024-09-18 5:15 UTC (permalink / raw) To: smfrench; +Cc: linux-cifs, Paulo Alcantara Propagate error from cifs_construct_tcon() in cifs_sb_tlink() instead of always returning -EACCES. Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> --- fs/smb/client/connect.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index e71b6933464a..5dda17ed9c77 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -4213,9 +4213,9 @@ tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink) struct tcon_link * cifs_sb_tlink(struct cifs_sb_info *cifs_sb) { - int ret; - kuid_t fsuid = current_fsuid(); struct tcon_link *tlink, *newtlink; + kuid_t fsuid = current_fsuid(); + int err; if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); @@ -4250,9 +4250,9 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb) spin_unlock(&cifs_sb->tlink_tree_lock); } else { wait_for_construction: - ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING, + err = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING, TASK_INTERRUPTIBLE); - if (ret) { + if (err) { cifs_put_tlink(tlink); return ERR_PTR(-ERESTARTSYS); } @@ -4263,8 +4263,9 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb) /* return error if we tried this already recently */ if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) { + err = PTR_ERR(tlink->tl_tcon); cifs_put_tlink(tlink); - return ERR_PTR(-EACCES); + return ERR_PTR(err); } if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags)) @@ -4276,8 +4277,9 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb) wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING); if (IS_ERR(tlink->tl_tcon)) { + err = PTR_ERR(tlink->tl_tcon); cifs_put_tlink(tlink); - return ERR_PTR(-EACCES); + return ERR_PTR(err); } return tlink; -- 2.46.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2024-09-25 14:31 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-09-18 5:15 [PATCH 1/9] smb: client: avoid unnecessary reconnects when refreshing referrals Paulo Alcantara 2024-09-18 5:15 ` [PATCH 2/9] smb: client: improve purging of cached referrals Paulo Alcantara 2024-09-18 5:15 ` [PATCH 3/9] smb: client: fix DFS interlink failover Paulo Alcantara 2024-09-18 5:15 ` [PATCH 4/9] smb: client: stop flooding dmesg in smb2_calc_signature() Paulo Alcantara 2024-09-25 2:23 ` Steve French 2024-09-25 14:30 ` Paulo Alcantara 2024-09-18 5:15 ` [PATCH 5/9] smb: client: print failed session logoffs with FYI Paulo Alcantara 2024-09-18 5:15 ` [PATCH 6/9] smb: client: stop flooding dmesg on failed session setups Paulo Alcantara 2024-09-18 5:15 ` [PATCH 7/9] smb: client: stop flooding dmesg with automounts Paulo Alcantara 2024-09-18 5:15 ` [PATCH 8/9] smb: client: fix DFS failover in multiuser mounts Paulo Alcantara 2024-09-18 5:15 ` [PATCH 9/9] smb: client: propagate error from cifs_construct_tcon() Paulo Alcantara
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox