Skip to content

Commit 3786f4b

Browse files
Paulo Alcantarasmfrench
authored andcommitted
cifs: ensure correct super block for DFS reconnect
This patch is basically fixing the lookup of tcons (DFS specific) during reconnect (smb2pdu.c:__smb2_reconnect) to update their prefix paths. Previously, we relied on the TCP_Server_Info pointer (misc.c:tcp_super_cb) to determine which tcon to update the prefix path We could not rely on TCP server pointer to determine which super block to update the prefix path when reconnecting tcons since it might map to different tcons that share same TCP connection. Instead, walk through all cifs super blocks and compare their DFS full paths with the tcon being updated to. Signed-off-by: Paulo Alcantara (SUSE) <[email protected]> Signed-off-by: Steve French <[email protected]> Reviewed-by: Ronnie Sahlberg <[email protected]>
1 parent 65303de commit 3786f4b

File tree

1 file changed

+65
-17
lines changed

1 file changed

+65
-17
lines changed

fs/cifs/misc.c

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,59 +1025,107 @@ int copy_path_name(char *dst, const char *src)
10251025
}
10261026

10271027
struct super_cb_data {
1028-
struct TCP_Server_Info *server;
1028+
void *data;
10291029
struct super_block *sb;
10301030
};
10311031

1032-
static void super_cb(struct super_block *sb, void *arg)
1032+
static void tcp_super_cb(struct super_block *sb, void *arg)
10331033
{
1034-
struct super_cb_data *d = arg;
1034+
struct super_cb_data *sd = arg;
1035+
struct TCP_Server_Info *server = sd->data;
10351036
struct cifs_sb_info *cifs_sb;
10361037
struct cifs_tcon *tcon;
10371038

1038-
if (d->sb)
1039+
if (sd->sb)
10391040
return;
10401041

10411042
cifs_sb = CIFS_SB(sb);
10421043
tcon = cifs_sb_master_tcon(cifs_sb);
1043-
if (tcon->ses->server == d->server)
1044-
d->sb = sb;
1044+
if (tcon->ses->server == server)
1045+
sd->sb = sb;
10451046
}
10461047

1047-
struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server)
1048+
static struct super_block *__cifs_get_super(void (*f)(struct super_block *, void *),
1049+
void *data)
10481050
{
1049-
struct super_cb_data d = {
1050-
.server = server,
1051+
struct super_cb_data sd = {
1052+
.data = data,
10511053
.sb = NULL,
10521054
};
10531055

1054-
iterate_supers_type(&cifs_fs_type, super_cb, &d);
1056+
iterate_supers_type(&cifs_fs_type, f, &sd);
10551057

1056-
if (unlikely(!d.sb))
1057-
return ERR_PTR(-ENOENT);
1058+
if (!sd.sb)
1059+
return ERR_PTR(-EINVAL);
10581060
/*
10591061
* Grab an active reference in order to prevent automounts (DFS links)
10601062
* of expiring and then freeing up our cifs superblock pointer while
10611063
* we're doing failover.
10621064
*/
1063-
cifs_sb_active(d.sb);
1064-
return d.sb;
1065+
cifs_sb_active(sd.sb);
1066+
return sd.sb;
10651067
}
10661068

1067-
void cifs_put_tcp_super(struct super_block *sb)
1069+
static void __cifs_put_super(struct super_block *sb)
10681070
{
10691071
if (!IS_ERR_OR_NULL(sb))
10701072
cifs_sb_deactive(sb);
10711073
}
10721074

1075+
struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server)
1076+
{
1077+
return __cifs_get_super(tcp_super_cb, server);
1078+
}
1079+
1080+
void cifs_put_tcp_super(struct super_block *sb)
1081+
{
1082+
__cifs_put_super(sb);
1083+
}
1084+
1085+
#ifdef CONFIG_CIFS_DFS_UPCALL
1086+
static void tcon_super_cb(struct super_block *sb, void *arg)
1087+
{
1088+
struct super_cb_data *sd = arg;
1089+
struct cifs_tcon *tcon = sd->data;
1090+
struct cifs_sb_info *cifs_sb;
1091+
1092+
if (sd->sb)
1093+
return;
1094+
1095+
cifs_sb = CIFS_SB(sb);
1096+
if (tcon->dfs_path && cifs_sb->origin_fullpath &&
1097+
!strcasecmp(tcon->dfs_path, cifs_sb->origin_fullpath))
1098+
sd->sb = sb;
1099+
}
1100+
1101+
static inline struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon)
1102+
{
1103+
return __cifs_get_super(tcon_super_cb, tcon);
1104+
}
1105+
1106+
static inline void cifs_put_tcon_super(struct super_block *sb)
1107+
{
1108+
__cifs_put_super(sb);
1109+
}
1110+
#else
1111+
static inline struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon)
1112+
{
1113+
return ERR_PTR(-EOPNOTSUPP);
1114+
}
1115+
1116+
static inline void cifs_put_tcon_super(struct super_block *sb)
1117+
{
1118+
}
1119+
#endif
1120+
10731121
int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
10741122
size_t prefix_len)
10751123
{
10761124
struct super_block *sb;
10771125
struct cifs_sb_info *cifs_sb;
10781126
int rc = 0;
10791127

1080-
sb = cifs_get_tcp_super(tcon->ses->server);
1128+
sb = cifs_get_tcon_super(tcon);
10811129
if (IS_ERR(sb))
10821130
return PTR_ERR(sb);
10831131

@@ -1099,6 +1147,6 @@ int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
10991147
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
11001148

11011149
out:
1102-
cifs_put_tcp_super(sb);
1150+
cifs_put_tcon_super(sb);
11031151
return rc;
11041152
}

0 commit comments

Comments
 (0)