Skip to content

Commit 5433c62

Browse files
Paulo Alcantarasmfrench
authored andcommitted
smb: client: optimize referral walk on failed link targets
If a link referral request sent to root server was successful but client failed to connect to all link targets, there is no need to retry same link referral on a different root server. Set an end marker for the DFS root referral so the client will not attempt to re-send link referrals to different root servers on failures. Signed-off-by: Paulo Alcantara (Red Hat) <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 4b1b4c8 commit 5433c62

File tree

2 files changed

+56
-57
lines changed

2 files changed

+56
-57
lines changed

fs/smb/client/dfs.c

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,16 @@ static inline int parse_dfs_target(struct smb3_fs_context *ctx,
9898
return rc;
9999
}
100100

101-
static int setup_dfs_ref(struct cifs_mount_ctx *mnt_ctx,
102-
struct dfs_info3_param *tgt,
103-
struct dfs_ref_walk *rw)
101+
static int setup_dfs_ref(struct dfs_info3_param *tgt, struct dfs_ref_walk *rw)
104102
{
105-
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
106-
struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
103+
struct cifs_sb_info *cifs_sb = rw->mnt_ctx->cifs_sb;
104+
struct smb3_fs_context *ctx = rw->mnt_ctx->fs_ctx;
107105
char *ref_path, *full_path;
108106
int rc;
109107

108+
set_root_smb_session(rw->mnt_ctx);
109+
ref_walk_ses(rw) = ctx->dfs_root_ses;
110+
110111
full_path = smb3_fs_context_fullpath(ctx, CIFS_DIR_SEP(cifs_sb));
111112
if (IS_ERR(full_path))
112113
return PTR_ERR(full_path);
@@ -123,35 +124,22 @@ static int setup_dfs_ref(struct cifs_mount_ctx *mnt_ctx,
123124
}
124125
ref_walk_path(rw) = ref_path;
125126
ref_walk_fpath(rw) = full_path;
126-
ref_walk_ses(rw) = ctx->dfs_root_ses;
127-
return 0;
127+
128+
return dfs_get_referral(rw->mnt_ctx,
129+
ref_walk_path(rw) + 1,
130+
ref_walk_tl(rw));
128131
}
129132

130-
static int __dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx,
131-
struct dfs_ref_walk *rw)
133+
static int __dfs_referral_walk(struct dfs_ref_walk *rw)
132134
{
133-
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
135+
struct smb3_fs_context *ctx = rw->mnt_ctx->fs_ctx;
136+
struct cifs_mount_ctx *mnt_ctx = rw->mnt_ctx;
134137
struct dfs_info3_param tgt = {};
135138
int rc = -ENOENT;
136139

137140
again:
138141
do {
139142
ctx->dfs_root_ses = ref_walk_ses(rw);
140-
if (ref_walk_empty(rw)) {
141-
rc = dfs_get_referral(mnt_ctx, ref_walk_path(rw) + 1,
142-
NULL, ref_walk_tl(rw));
143-
if (rc) {
144-
rc = cifs_mount_get_tcon(mnt_ctx);
145-
if (!rc)
146-
rc = cifs_is_path_remote(mnt_ctx);
147-
continue;
148-
}
149-
if (!ref_walk_num_tgts(rw)) {
150-
rc = -ENOENT;
151-
continue;
152-
}
153-
}
154-
155143
while (ref_walk_next_tgt(rw)) {
156144
rc = parse_dfs_target(ctx, rw, &tgt);
157145
if (rc)
@@ -162,32 +150,29 @@ static int __dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx,
162150
if (rc)
163151
continue;
164152

165-
ref_walk_set_tgt_hint(rw);
166153
if (tgt.flags & DFSREF_STORAGE_SERVER) {
167154
rc = cifs_mount_get_tcon(mnt_ctx);
168155
if (!rc)
169156
rc = cifs_is_path_remote(mnt_ctx);
170-
if (!rc)
157+
if (!rc) {
158+
ref_walk_set_tgt_hint(rw);
171159
break;
160+
}
172161
if (rc != -EREMOTE)
173162
continue;
174163
}
175164

176-
set_root_smb_session(mnt_ctx);
177165
rc = ref_walk_advance(rw);
178166
if (!rc) {
179-
rc = setup_dfs_ref(mnt_ctx, &tgt, rw);
180-
if (!rc) {
181-
rc = -EREMOTE;
182-
goto again;
183-
}
167+
rc = setup_dfs_ref(&tgt, rw);
168+
if (rc)
169+
break;
170+
ref_walk_mark_end(rw);
171+
goto again;
184172
}
185-
if (rc != -ELOOP)
186-
goto out;
187173
}
188174
} while (rc && ref_walk_descend(rw));
189175

190-
out:
191176
free_dfs_info_param(&tgt);
192177
return rc;
193178
}
@@ -204,10 +189,10 @@ static int dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx,
204189
return rc;
205190
}
206191

207-
ref_walk_init(*rw);
208-
rc = setup_dfs_ref(mnt_ctx, NULL, *rw);
192+
ref_walk_init(*rw, mnt_ctx);
193+
rc = setup_dfs_ref(NULL, *rw);
209194
if (!rc)
210-
rc = __dfs_referral_walk(mnt_ctx, *rw);
195+
rc = __dfs_referral_walk(*rw);
211196
return rc;
212197
}
213198

@@ -297,7 +282,7 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
297282
* to respond with PATH_NOT_COVERED to requests that include the prefix.
298283
*/
299284
if (!nodfs) {
300-
rc = dfs_get_referral(mnt_ctx, ctx->UNC + 1, NULL, NULL);
285+
rc = dfs_get_referral(mnt_ctx, ctx->UNC + 1, NULL);
301286
if (rc) {
302287
cifs_dbg(FYI, "%s: no dfs referral for %s: %d\n",
303288
__func__, ctx->UNC + 1, rc);
@@ -317,10 +302,8 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
317302
cifs_mount_put_conns(mnt_ctx);
318303
rc = get_session(mnt_ctx, NULL);
319304
}
320-
if (!rc) {
321-
set_root_smb_session(mnt_ctx);
305+
if (!rc)
322306
rc = __dfs_mount_share(mnt_ctx);
323-
}
324307
return rc;
325308
}
326309

fs/smb/client/dfs.h

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "dfs_cache.h"
1313
#include "cifs_unicode.h"
1414
#include <linux/namei.h>
15+
#include <linux/errno.h>
1516

1617
#define DFS_INTERLINK(v) \
1718
(((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER))
@@ -25,8 +26,9 @@ struct dfs_ref {
2526
};
2627

2728
struct dfs_ref_walk {
28-
struct dfs_ref *ref;
29-
struct dfs_ref refs[MAX_NESTED_LINKS];
29+
struct cifs_mount_ctx *mnt_ctx;
30+
struct dfs_ref *ref;
31+
struct dfs_ref refs[MAX_NESTED_LINKS];
3032
};
3133

3234
#define ref_walk_start(w) ((w)->refs)
@@ -35,7 +37,6 @@ struct dfs_ref_walk {
3537
#define ref_walk_descend(w) (--ref_walk_cur(w) >= ref_walk_start(w))
3638

3739
#define ref_walk_tit(w) (ref_walk_cur(w)->tit)
38-
#define ref_walk_empty(w) (!ref_walk_tit(w))
3940
#define ref_walk_path(w) (ref_walk_cur(w)->path)
4041
#define ref_walk_fpath(w) (ref_walk_cur(w)->full_path)
4142
#define ref_walk_tl(w) (&ref_walk_cur(w)->tl)
@@ -51,9 +52,11 @@ static inline struct dfs_ref_walk *ref_walk_alloc(void)
5152
return rw;
5253
}
5354

54-
static inline void ref_walk_init(struct dfs_ref_walk *rw)
55+
static inline void ref_walk_init(struct dfs_ref_walk *rw,
56+
struct cifs_mount_ctx *mnt_ctx)
5557
{
5658
memset(rw, 0, sizeof(*rw));
59+
rw->mnt_ctx = mnt_ctx;
5760
ref_walk_cur(rw) = ref_walk_start(rw);
5861
}
5962

@@ -93,15 +96,23 @@ static inline int ref_walk_advance(struct dfs_ref_walk *rw)
9396
static inline struct dfs_cache_tgt_iterator *
9497
ref_walk_next_tgt(struct dfs_ref_walk *rw)
9598
{
96-
struct dfs_cache_tgt_iterator *tit;
9799
struct dfs_ref *ref = ref_walk_cur(rw);
100+
struct dfs_cache_tgt_iterator *tit;
101+
102+
if (IS_ERR(ref->tit))
103+
return NULL;
98104

99105
if (!ref->tit)
100106
tit = dfs_cache_get_tgt_iterator(&ref->tl);
101107
else
102108
tit = dfs_cache_get_next_tgt(&ref->tl, ref->tit);
109+
110+
if (!tit) {
111+
ref->tit = ERR_PTR(-ENOENT);
112+
return NULL;
113+
}
103114
ref->tit = tit;
104-
return tit;
115+
return ref->tit;
105116
}
106117

107118
static inline int ref_walk_get_tgt(struct dfs_ref_walk *rw,
@@ -112,11 +123,6 @@ static inline int ref_walk_get_tgt(struct dfs_ref_walk *rw,
112123
ref_walk_tit(rw), tgt);
113124
}
114125

115-
static inline int ref_walk_num_tgts(struct dfs_ref_walk *rw)
116-
{
117-
return dfs_cache_get_nr_tgts(ref_walk_tl(rw));
118-
}
119-
120126
static inline void ref_walk_set_tgt_hint(struct dfs_ref_walk *rw)
121127
{
122128
dfs_cache_noreq_update_tgthint(ref_walk_path(rw) + 1,
@@ -136,6 +142,15 @@ static inline void ref_walk_set_tcon(struct dfs_ref_walk *rw,
136142
}
137143
}
138144

145+
static inline void ref_walk_mark_end(struct dfs_ref_walk *rw)
146+
{
147+
struct dfs_ref *ref = ref_walk_cur(rw) - 1;
148+
149+
WARN_ON_ONCE(ref < ref_walk_start(rw));
150+
dfs_cache_noreq_update_tgthint(ref->path + 1, ref->tit);
151+
ref->tit = ERR_PTR(-ENOENT); /* end marker */
152+
}
153+
139154
int dfs_parse_target_referral(const char *full_path, const struct dfs_info3_param *ref,
140155
struct smb3_fs_context *ctx);
141156
int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx);
@@ -145,15 +160,16 @@ static inline char *dfs_get_path(struct cifs_sb_info *cifs_sb, const char *path)
145160
return dfs_cache_canonical_path(path, cifs_sb->local_nls, cifs_remap(cifs_sb));
146161
}
147162

148-
static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, const char *path,
149-
struct dfs_info3_param *ref, struct dfs_cache_tgt_list *tl)
163+
static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx,
164+
const char *path,
165+
struct dfs_cache_tgt_list *tl)
150166
{
151167
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
152168
struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
153169
struct cifs_ses *rses = ctx->dfs_root_ses ?: mnt_ctx->ses;
154170

155171
return dfs_cache_find(mnt_ctx->xid, rses, cifs_sb->local_nls,
156-
cifs_remap(cifs_sb), path, ref, tl);
172+
cifs_remap(cifs_sb), path, NULL, tl);
157173
}
158174

159175
/*

0 commit comments

Comments
 (0)