Skip to content

Commit

Permalink
Merge tag '6.3-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/…
Browse files Browse the repository at this point in the history
…cifs-2.6

Pull cifs client fixes from Steve French:
 "Seven cifs/smb3 client fixes, all also for stable:

   - four DFS fixes

   - multichannel reconnect fix

   - fix smb1 stats for cancel command

   - fix for set file size error path"

* tag '6.3-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: use DFS root session instead of tcon ses
  cifs: return DFS root session id in DebugData
  cifs: fix use-after-free bug in refresh_cache_worker()
  cifs: set DFS root session in cifs_get_smb_ses()
  cifs: generate signkey for the channel that's reconnecting
  cifs: Fix smb2_set_path_size()
  cifs: Move the in_send statistic to __smb_send_rqst()
  • Loading branch information
torvalds committed Mar 16, 2023
2 parents 0ddc84d + 6284e46 commit 38e04b3
Show file tree
Hide file tree
Showing 14 changed files with 118 additions and 195 deletions.
5 changes: 5 additions & 0 deletions fs/cifs/cifs_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
from_kuid(&init_user_ns, ses->linux_uid),
from_kuid(&init_user_ns, ses->cred_uid));

if (ses->dfs_root_ses) {
seq_printf(m, "\n\tDFS root session id: 0x%llx",
ses->dfs_root_ses->Suid);
}

spin_lock(&ses->chan_lock);
if (CIFS_CHAN_NEEDS_RECONNECT(ses, 0))
seq_puts(m, "\tPrimary channel: DISCONNECTED ");
Expand Down
1 change: 1 addition & 0 deletions fs/cifs/cifs_dfs_ref.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
tmp.source = full_path;
tmp.leaf_fullpath = NULL;
tmp.UNC = tmp.prepath = NULL;
tmp.dfs_root_ses = NULL;

rc = smb3_fs_context_dup(ctx, &tmp);
if (rc) {
Expand Down
2 changes: 0 additions & 2 deletions fs/cifs/cifs_fs_sb.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ struct cifs_sb_info {
/* only used when CIFS_MOUNT_USE_PREFIX_PATH is set */
char *prepath;

/* randomly generated 128-bit number for indexing dfs mount groups in referral cache */
uuid_t dfs_mount_id;
/*
* Indicate whether serverino option was turned off later
* (cifs_autodisable_serverino) in order to match new mounts.
Expand Down
4 changes: 2 additions & 2 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,7 @@ struct cifs_tcon {
/* 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;
#endif
struct delayed_work query_interfaces; /* query interfaces workqueue job */
};
Expand Down Expand Up @@ -1749,9 +1750,8 @@ struct cifs_mount_ctx {
struct TCP_Server_Info *server;
struct cifs_ses *ses;
struct cifs_tcon *tcon;
struct cifs_ses *root_ses;
uuid_t mount_id;
char *origin_fullpath, *leaf_fullpath;
struct list_head dfs_ses_list;
};

static inline void free_dfs_info_param(struct dfs_info3_param *param)
Expand Down
10 changes: 4 additions & 6 deletions fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2229,6 +2229,7 @@ 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);
ses->dfs_root_ses = ctx->dfs_root_ses;
list_add(&ses->smb_ses_list, &server->smb_ses_list);
spin_unlock(&cifs_tcp_ses_lock);

Expand Down Expand Up @@ -3407,7 +3408,8 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
bool isdfs;
int rc;

uuid_gen(&mnt_ctx.mount_id);
INIT_LIST_HEAD(&mnt_ctx.dfs_ses_list);

rc = dfs_mount_share(&mnt_ctx, &isdfs);
if (rc)
goto error;
Expand All @@ -3427,7 +3429,6 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
kfree(cifs_sb->prepath);
cifs_sb->prepath = ctx->prepath;
ctx->prepath = NULL;
uuid_copy(&cifs_sb->dfs_mount_id, &mnt_ctx.mount_id);

out:
cifs_try_adding_channels(cifs_sb, mnt_ctx.ses);
Expand All @@ -3439,7 +3440,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
return rc;

error:
dfs_cache_put_refsrv_sessions(&mnt_ctx.mount_id);
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);
Expand Down Expand Up @@ -3637,9 +3638,6 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
spin_unlock(&cifs_sb->tlink_tree_lock);

kfree(cifs_sb->prepath);
#ifdef CONFIG_CIFS_DFS_UPCALL
dfs_cache_put_refsrv_sessions(&cifs_sb->dfs_mount_id);
#endif
call_rcu(&cifs_sb->rcu, delayed_free);
}

Expand Down
67 changes: 45 additions & 22 deletions fs/cifs/dfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,33 +95,40 @@ static int get_session(struct cifs_mount_ctx *mnt_ctx, const char *full_path)
ctx->leaf_fullpath = (char *)full_path;
rc = cifs_mount_get_session(mnt_ctx);
ctx->leaf_fullpath = NULL;
if (!rc) {
struct cifs_ses *ses = mnt_ctx->ses;

mutex_lock(&ses->session_mutex);
ses->dfs_root_ses = mnt_ctx->root_ses;
mutex_unlock(&ses->session_mutex);
}
return rc;
}

static void set_root_ses(struct cifs_mount_ctx *mnt_ctx)
static int get_root_smb_session(struct cifs_mount_ctx *mnt_ctx)
{
if (mnt_ctx->ses) {
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
struct dfs_root_ses *root_ses;
struct cifs_ses *ses = mnt_ctx->ses;

if (ses) {
root_ses = kmalloc(sizeof(*root_ses), GFP_KERNEL);
if (!root_ses)
return -ENOMEM;

INIT_LIST_HEAD(&root_ses->list);

spin_lock(&cifs_tcp_ses_lock);
mnt_ctx->ses->ses_count++;
ses->ses_count++;
spin_unlock(&cifs_tcp_ses_lock);
dfs_cache_add_refsrv_session(&mnt_ctx->mount_id, mnt_ctx->ses);
root_ses->ses = ses;
list_add_tail(&root_ses->list, &mnt_ctx->dfs_ses_list);
}
mnt_ctx->root_ses = mnt_ctx->ses;
ctx->dfs_root_ses = ses;
return 0;
}

static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, const char *full_path,
const struct dfs_cache_tgt_iterator *tit)
{
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
struct dfs_info3_param ref = {};
int rc;
bool is_refsrv = false;
int rc, rc2;

rc = dfs_cache_get_tgt_referral(ref_path + 1, tit, &ref);
if (rc)
Expand All @@ -136,8 +143,7 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co
if (rc)
goto out;

if (ref.flags & DFSREF_REFERRAL_SERVER)
set_root_ses(mnt_ctx);
is_refsrv = !!(ref.flags & DFSREF_REFERRAL_SERVER);

rc = -EREMOTE;
if (ref.flags & DFSREF_STORAGE_SERVER) {
Expand All @@ -146,13 +152,17 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co
goto out;

/* some servers may not advertise referral capability under ref.flags */
if (!(ref.flags & DFSREF_REFERRAL_SERVER) &&
is_tcon_dfs(mnt_ctx->tcon))
set_root_ses(mnt_ctx);
is_refsrv |= is_tcon_dfs(mnt_ctx->tcon);

rc = cifs_is_path_remote(mnt_ctx);
}

if (rc == -EREMOTE && is_refsrv) {
rc2 = get_root_smb_session(mnt_ctx);
if (rc2)
rc = rc2;
}

out:
free_dfs_info_param(&ref);
return rc;
Expand All @@ -165,6 +175,7 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
char *ref_path = NULL, *full_path = NULL;
struct dfs_cache_tgt_iterator *tit;
struct TCP_Server_Info *server;
struct cifs_tcon *tcon;
char *origin_fullpath = NULL;
int num_links = 0;
int rc;
Expand Down Expand Up @@ -234,12 +245,22 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)

if (!rc) {
server = mnt_ctx->server;
tcon = mnt_ctx->tcon;

mutex_lock(&server->refpath_lock);
server->origin_fullpath = origin_fullpath;
server->current_fullpath = server->leaf_fullpath;
if (!server->origin_fullpath) {
server->origin_fullpath = origin_fullpath;
server->current_fullpath = server->leaf_fullpath;
origin_fullpath = NULL;
}
mutex_unlock(&server->refpath_lock);
origin_fullpath = NULL;

if (list_empty(&tcon->dfs_ses_list)) {
list_replace_init(&mnt_ctx->dfs_ses_list,
&tcon->dfs_ses_list);
} else {
dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list);
}
}

out:
Expand All @@ -260,7 +281,7 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
rc = get_session(mnt_ctx, NULL);
if (rc)
return rc;
mnt_ctx->root_ses = mnt_ctx->ses;
ctx->dfs_root_ses = mnt_ctx->ses;
/*
* If called with 'nodfs' mount option, then skip DFS resolving. Otherwise unconditionally
* try to get an DFS referral (even cached) to determine whether it is an DFS mount.
Expand All @@ -280,7 +301,9 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
}

*isdfs = true;
set_root_ses(mnt_ctx);
rc = get_root_smb_session(mnt_ctx);
if (rc)
return rc;

return __dfs_mount_share(mnt_ctx);
}
Expand Down
19 changes: 18 additions & 1 deletion fs/cifs/dfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
#include "fs_context.h"
#include "cifs_unicode.h"

struct dfs_root_ses {
struct list_head list;
struct cifs_ses *ses;
};

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);
Expand All @@ -22,9 +27,10 @@ static inline char *dfs_get_path(struct cifs_sb_info *cifs_sb, const char *path)
static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, const char *path,
struct dfs_info3_param *ref, struct dfs_cache_tgt_list *tl)
{
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;

return dfs_cache_find(mnt_ctx->xid, mnt_ctx->root_ses, cifs_sb->local_nls,
return dfs_cache_find(mnt_ctx->xid, ctx->dfs_root_ses, cifs_sb->local_nls,
cifs_remap(cifs_sb), path, ref, tl);
}

Expand All @@ -43,4 +49,15 @@ static inline char *dfs_get_automount_devname(struct dentry *dentry, void *page)
true);
}

static inline void dfs_put_root_smb_sessions(struct list_head *head)
{
struct dfs_root_ses *root, *tmp;

list_for_each_entry_safe(root, tmp, head, list) {
list_del_init(&root->list);
cifs_put_smb_ses(root->ses);
kfree(root);
}
}

#endif /* _CIFS_DFS_H */
Loading

0 comments on commit 38e04b3

Please sign in to comment.