Commit 38e04b3e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '6.3-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/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()
parents 0ddc84d2 6284e46b
......@@ -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 ");
......
......@@ -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) {
......
......@@ -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.
......
......@@ -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 */
};
......@@ -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)
......
......@@ -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);
......@@ -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;
......@@ -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);
......@@ -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);
......@@ -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);
}
......
......@@ -95,25 +95,31 @@ 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,
......@@ -121,7 +127,8 @@ 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 = {};
int rc;
bool is_refsrv = false;
int rc, rc2;
rc = dfs_cache_get_tgt_referral(ref_path + 1, tit, &ref);
if (rc)
......@@ -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) {
......@@ -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;
......@@ -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;
......@@ -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:
......@@ -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.
......@@ -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);
}
......
......@@ -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);
......@@ -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);
}
......@@ -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 */
......@@ -49,17 +49,6 @@ struct cache_entry {
struct cache_dfs_tgt *tgthint;
};
/* List of referral server sessions per dfs mount */
struct mount_group {
struct list_head list;
uuid_t id;
struct cifs_ses *sessions[CACHE_MAX_ENTRIES];
int num_sessions;
spinlock_t lock;
struct list_head refresh_list;
struct kref refcount;
};
static struct kmem_cache *cache_slab __read_mostly;
static struct workqueue_struct *dfscache_wq __read_mostly;
......@@ -76,85 +65,10 @@ static atomic_t cache_count;
static struct hlist_head cache_htable[CACHE_HTABLE_SIZE];
static DECLARE_RWSEM(htable_rw_lock);
static LIST_HEAD(mount_group_list);
static DEFINE_MUTEX(mount_group_list_lock);
static void refresh_cache_worker(struct work_struct *work);
static DECLARE_DELAYED_WORK(refresh_task, refresh_cache_worker);
static void __mount_group_release(struct mount_group *mg)
{
int i;
for (i = 0; i < mg->num_sessions; i++)
cifs_put_smb_ses(mg->sessions[i]);
kfree(mg);
}
static void mount_group_release(struct kref *kref)
{
struct mount_group *mg = container_of(kref, struct mount_group, refcount);
mutex_lock(&mount_group_list_lock);
list_del(&mg->list);
mutex_unlock(&mount_group_list_lock);
__mount_group_release(mg);
}
static struct mount_group *find_mount_group_locked(const uuid_t *id)
{
struct mount_group *mg;
list_for_each_entry(mg, &mount_group_list, list) {
if (uuid_equal(&mg->id, id))
return mg;
}
return ERR_PTR(-ENOENT);
}
static struct mount_group *__get_mount_group_locked(const uuid_t *id)
{
struct mount_group *mg;
mg = find_mount_group_locked(id);
if (!IS_ERR(mg))
return mg;
mg = kmalloc(sizeof(*mg), GFP_KERNEL);
if (!mg)
return ERR_PTR(-ENOMEM);
kref_init(&mg->refcount);
uuid_copy(&mg->id, id);
mg->num_sessions = 0;
spin_lock_init(&mg->lock);
list_add(&mg->list, &mount_group_list);
return mg;
}
static struct mount_group *get_mount_group(const uuid_t *id)
{
struct mount_group *mg;
mutex_lock(&mount_group_list_lock);
mg = __get_mount_group_locked(id);
if (!IS_ERR(mg))
kref_get(&mg->refcount);
mutex_unlock(&mount_group_list_lock);
return mg;
}
static void free_mount_group_list(void)
{
struct mount_group *mg, *tmp_mg;
list_for_each_entry_safe(mg, tmp_mg, &mount_group_list, list) {
list_del_init(&mg->list);
__mount_group_release(mg);
}
}
/**
* dfs_cache_canonical_path - get a canonical DFS path
*
......@@ -704,7 +618,6 @@ void dfs_cache_destroy(void)
{
cancel_delayed_work_sync(&refresh_task);
unload_nls(cache_cp);
free_mount_group_list();
flush_cache_ents();
kmem_cache_destroy(cache_slab);
destroy_workqueue(dfscache_wq);
......@@ -1111,54 +1024,6 @@ int dfs_cache_get_tgt_referral(const char *path, const struct dfs_cache_tgt_iter
return rc;
}
/**
* dfs_cache_add_refsrv_session - add SMB session of referral server
*
* @mount_id: mount group uuid to lookup.
* @ses: reference counted SMB session of referral server.
*/
void dfs_cache_add_refsrv_session(const uuid_t *mount_id, struct cifs_ses *ses)
{
struct mount_group *mg;
if (WARN_ON_ONCE(!mount_id || uuid_is_null(mount_id) || !ses))
return;
mg = get_mount_group(mount_id);
if (WARN_ON_ONCE(IS_ERR(mg)))
return;
spin_lock(&mg->lock);
if (mg->num_sessions < ARRAY_SIZE(mg->sessions))
mg->sessions[mg->num_sessions++] = ses;
spin_unlock(&mg->lock);
kref_put(&mg->refcount, mount_group_release);
}
/**
* dfs_cache_put_refsrv_sessions - put all referral server sessions
*
* Put all SMB sessions from the given mount group id.
*
* @mount_id: mount group uuid to lookup.
*/
void dfs_cache_put_refsrv_sessions(const uuid_t *mount_id)
{
struct mount_group *mg;
if (!mount_id || uuid_is_null(mount_id))
return;
mutex_lock(&mount_group_list_lock);
mg = find_mount_group_locked(mount_id);
if (IS_ERR(mg)) {
mutex_unlock(&mount_group_list_lock);
return;
}
mutex_unlock(&mount_group_list_lock);
kref_put(&mg->refcount, mount_group_release);
}
/* Extract share from DFS target and return a pointer to prefix path or NULL */
static const char *parse_target_share(const char *target, char **share)
{
......@@ -1384,11 +1249,6 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
cifs_dbg(FYI, "%s: not a dfs mount\n", __func__);
return 0;
}
if (uuid_is_null(&cifs_sb->dfs_mount_id)) {
cifs_dbg(FYI, "%s: no dfs mount group id\n", __func__);
return -EINVAL;
}
/*
* After reconnecting to a different server, unique ids won't match anymore, so we disable
* serverino. This prevents dentry revalidation to think the dentry are stale (ESTALE).
......
......@@ -40,8 +40,6 @@ int dfs_cache_get_tgt_referral(const char *path, const struct dfs_cache_tgt_iter
struct dfs_info3_param *ref);
int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it, char **share,
char **prefix);
void dfs_cache_put_refsrv_sessions(const uuid_t *mount_id);
void dfs_cache_add_refsrv_session(const uuid_t *mount_id, struct cifs_ses *ses);
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);
......
......@@ -265,6 +265,7 @@ struct smb3_fs_context {
bool rootfs:1; /* if it's a SMB root file system */
bool witness:1; /* use witness protocol */
char *leaf_fullpath;
struct cifs_ses *dfs_root_ses;
};
extern const struct fs_parameter_spec smb3_fs_parameters[];
......
......@@ -22,6 +22,7 @@
#ifdef CONFIG_CIFS_DFS_UPCALL
#include "dns_resolve.h"
#include "dfs_cache.h"
#include "dfs.h"
#endif
#include "fs_context.h"
#include "cached_dir.h"
......@@ -134,6 +135,9 @@ tconInfoAlloc(void)
spin_lock_init(&ret_buf->stat_lock);
atomic_set(&ret_buf->num_local_opens, 0);
atomic_set(&ret_buf->num_remote_opens, 0);
#ifdef CONFIG_CIFS_DFS_UPCALL
INIT_LIST_HEAD(&ret_buf->dfs_ses_list);
#endif
return ret_buf;
}
......@@ -149,6 +153,9 @@ tconInfoFree(struct cifs_tcon *tcon)
atomic_dec(&tconInfoAllocCount);
kfree(tcon->nativeFileSystem);
kfree_sensitive(tcon->password);
#ifdef CONFIG_CIFS_DFS_UPCALL
dfs_put_root_smb_sessions(&tcon->dfs_ses_list);
#endif
kfree(tcon);
}
......@@ -1255,6 +1262,7 @@ int cifs_inval_name_dfs_link_error(const unsigned int xid,
* removing cached DFS targets that the client would eventually
* need during failover.
*/
ses = CIFS_DFS_ROOT_SES(ses);
if (ses->server->ops->get_dfs_refer &&
!ses->server->ops->get_dfs_refer(xid, ses, ref_path, &refs,
&num_refs, cifs_sb->local_nls,
......
......@@ -234,15 +234,32 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
size[0] = 8; /* sizeof __le64 */
data[0] = ptr;
rc = SMB2_set_info_init(tcon, server,
&rqst[num_rqst], COMPOUND_FID,
COMPOUND_FID, current->tgid,
FILE_END_OF_FILE_INFORMATION,
SMB2_O_INFO_FILE, 0, data, size);
if (cfile) {
rc = SMB2_set_info_init(tcon, server,
&rqst[num_rqst],
cfile->fid.persistent_fid,
cfile->fid.volatile_fid,
current->tgid,
FILE_END_OF_FILE_INFORMATION,
SMB2_O_INFO_FILE, 0,
data, size);
} else {
rc = SMB2_set_info_init(tcon, server,
&rqst[num_rqst],
COMPOUND_FID,
COMPOUND_FID,
current->tgid,
FILE_END_OF_FILE_INFORMATION,
SMB2_O_INFO_FILE, 0,
data, size);
if (!rc) {
smb2_set_next_command(tcon, &rqst[num_rqst]);
smb2_set_related(&rqst[num_rqst]);
}
}
if (rc)
goto finished;
smb2_set_next_command(tcon, &rqst[num_rqst]);
smb2_set_related(&rqst[num_rqst++]);
num_rqst++;
trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
break;
case SMB2_OP_SET_INFO:
......
......@@ -425,7 +425,7 @@ generate_smb3signingkey(struct cifs_ses *ses,
/* safe to access primary channel, since it will never go away */
spin_lock(&ses->chan_lock);
memcpy(ses->chans[0].signkey, ses->smb3signingkey,
memcpy(ses->chans[chan_index].signkey, ses->smb3signingkey,
SMB3_SIGN_KEY_SIZE);
spin_unlock(&ses->chan_lock);
......
......@@ -278,7 +278,7 @@ static int
__smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
struct smb_rqst *rqst)
{
int rc = 0;
int rc;
struct kvec *iov;
int n_vec;
unsigned int send_length = 0;
......@@ -289,6 +289,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
struct msghdr smb_msg = {};
__be32 rfc1002_marker;
cifs_in_send_inc(server);
if (cifs_rdma_enabled(server)) {
/* return -EAGAIN when connecting or reconnecting */
rc = -EAGAIN;
......@@ -297,14 +298,17 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
goto smbd_done;
}
rc = -EAGAIN;
if (ssocket == NULL)
return -EAGAIN;
goto out;
rc = -ERESTARTSYS;
if (fatal_signal_pending(current)) {
cifs_dbg(FYI, "signal pending before send request\n");
return -ERESTARTSYS;
goto out;
}
rc = 0;
/* cork the socket */
tcp_sock_set_cork(ssocket->sk, true);
......@@ -407,7 +411,8 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
rc);
else if (rc > 0)
rc = 0;
out:
cifs_in_send_dec(server);
return rc;
}
......@@ -826,9 +831,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
* I/O response may come back and free the mid entry on another thread.
*/
cifs_save_when_sent(mid);
cifs_in_send_inc(server);
rc = smb_send_rqst(server, 1, rqst, flags);
cifs_in_send_dec(server);
if (rc < 0) {
revert_current_mid(server, mid->credits);
......@@ -1144,9 +1147,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
else
midQ[i]->callback = cifs_compound_last_callback;
}
cifs_in_send_inc(server);
rc = smb_send_rqst(server, num_rqst, rqst, flags);
cifs_in_send_dec(server);
for (i = 0; i < num_rqst; i++)
cifs_save_when_sent(midQ[i]);
......@@ -1396,9 +1397,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
midQ->mid_state = MID_REQUEST_SUBMITTED;
cifs_in_send_inc(server);
rc = smb_send(server, in_buf, len);
cifs_in_send_dec(server);
cifs_save_when_sent(midQ);
if (rc < 0)
......@@ -1539,9 +1538,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
}
midQ->mid_state = MID_REQUEST_SUBMITTED;
cifs_in_send_inc(server);
rc = smb_send(server, in_buf, len);
cifs_in_send_dec(server);
cifs_save_when_sent(midQ);
if (rc < 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment