mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
12 smb3 client fixes, and also an important netfs fix for cifs mtime write regression
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmb0mWUACgkQiiy9cAdy T1Fwbgv/Zoe5LZukUe4s87xO7IC73Wfn2UBUQmvDUtK1djRF3HrL1QOtXLnFfPb/ pFJTPiNljM/NPcpXAk+7qz1XFihkOwGNJOFFuQPNrwcDX4LLF35sqoeRij1qRkXn 06yLPQRBI2SQLehLqi/Avk4TEatber7uGZMXgOaLN54doiNY8kMYcsIgEQWoe15h muxCUoPopSokU5+s0H6ObDoXX10KS3ir/1ArmmZ8oh1be363ysye0bf6+mnVNr/P I5yiERdYrN+oo6ZzC0XjyYSp0SnCbu8jck2g5ydIKUyQ7gbiSE8XqCNVy6ALndxg URMlYtL+gVknmJk9NJcc8gVp79EZcdjUIbFSTQ1Pa8x++nQCBl9rge1AZ9G/zzY2 Ul6xIVoP5DNgcwXvMka+lJgAsoRgB5olcEBMdltaCpKCLjWNjyzvOzb+kP2L30IC /nPZJbVQSrdr3ropybapAlHLG57Jk1ad1QdaBEiu5ss528mSmKc+t288zPQKIhU5 Ogqr3CxB =nVf0 -----END PGP SIGNATURE----- Merge tag 'v6.12-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6 Pull smb client fixes from Steve French: "Most are from the recent SMB3.1.1 test event, and also an important netfs fix for a cifs mtime write regression - fix mode reported by stat of readonly directories and files - DFS (global namespace) related fixes - fixes for special file support via reparse points - mount improvement and reconnect fix - fix for noisy log message on umount - two netfs related fixes, one fixing a recent regression, and add new write tracepoint" * tag 'v6.12-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6: netfs, cifs: Fix mtime/ctime update for mmapped writes cifs: update internal version number smb: client: print failed session logoffs with FYI cifs: Fix reversion of the iter in cifs_readv_receive(). smb3: fix incorrect mode displayed for read-only files smb: client: fix parsing of device numbers smb: client: set correct device number on nfs reparse points smb: client: propagate error from cifs_construct_tcon() smb: client: fix DFS failover in multiuser mounts cifs: Make the write_{enter,done,err} tracepoints display netfs info smb: client: fix DFS interlink failover smb: client: improve purging of cached referrals smb: client: avoid unnecessary reconnects when refreshing referrals
This commit is contained in:
commit
ac34bb40f7
@ -552,6 +552,7 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr
|
||||
trace_netfs_folio(folio, netfs_folio_trace_mkwrite);
|
||||
netfs_set_group(folio, netfs_group);
|
||||
file_update_time(file);
|
||||
set_bit(NETFS_ICTX_MODIFIED_ATTR, &ictx->flags);
|
||||
if (ictx->ops->post_modify)
|
||||
ictx->ops->post_modify(inode);
|
||||
ret = VM_FAULT_LOCKED;
|
||||
|
@ -146,6 +146,6 @@ extern const struct export_operations cifs_export_ops;
|
||||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||
|
||||
/* when changing internal version - update following two lines at same time */
|
||||
#define SMB3_PRODUCT_BUILD 50
|
||||
#define CIFS_VERSION "2.50"
|
||||
#define SMB3_PRODUCT_BUILD 51
|
||||
#define CIFS_VERSION "2.51"
|
||||
#endif /* _CIFSFS_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 */
|
||||
|
@ -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)
|
||||
|
@ -811,13 +811,9 @@ cifs_read_iter_from_socket(struct TCP_Server_Info *server, struct iov_iter *iter
|
||||
unsigned int to_read)
|
||||
{
|
||||
struct msghdr smb_msg = { .msg_iter = *iter };
|
||||
int ret;
|
||||
|
||||
iov_iter_truncate(&smb_msg.msg_iter, to_read);
|
||||
ret = cifs_readv_from_socket(server, &smb_msg);
|
||||
if (ret > 0)
|
||||
iov_iter_advance(iter, ret);
|
||||
return ret;
|
||||
return cifs_readv_from_socket(server, &smb_msg);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1530,6 +1526,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 +1722,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 +1873,15 @@ out_err:
|
||||
}
|
||||
|
||||
/* 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 +2000,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;
|
||||
@ -2058,8 +2060,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);
|
||||
}
|
||||
@ -2382,8 +2383,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 +2457,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 +2482,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 +2512,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 +2898,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 +3629,12 @@ out:
|
||||
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 +4039,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 +4137,6 @@ out:
|
||||
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)
|
||||
{
|
||||
@ -4212,9 +4206,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));
|
||||
@ -4249,9 +4243,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);
|
||||
}
|
||||
@ -4262,8 +4256,9 @@ wait_for_construction:
|
||||
|
||||
/* 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))
|
||||
@ -4275,8 +4270,11 @@ wait_for_construction:
|
||||
wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING);
|
||||
|
||||
if (IS_ERR(tlink->tl_tcon)) {
|
||||
err = PTR_ERR(tlink->tl_tcon);
|
||||
if (err == -ENOKEY)
|
||||
err = -EACCES;
|
||||
cifs_put_tlink(tlink);
|
||||
return ERR_PTR(-EACCES);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
return tlink;
|
||||
|
@ -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 @@ again:
|
||||
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 @@ again:
|
||||
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 @@ out:
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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(&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 */
|
||||
|
@ -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);
|
||||
@ -1095,16 +1093,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};
|
||||
const char *host;
|
||||
size_t hostlen;
|
||||
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;
|
||||
char unc[sizeof("\\\\") + SERVER_NAME_LENGTH] = {0};
|
||||
bool match;
|
||||
int rc;
|
||||
|
||||
if (strcasecmp(s1, s2))
|
||||
if (strcasecmp(s2, s1))
|
||||
return false;
|
||||
|
||||
/*
|
||||
@ -1128,34 +1128,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,41 +1144,35 @@ 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)
|
||||
goto out;
|
||||
return path;
|
||||
}
|
||||
|
||||
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);
|
||||
/* 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;
|
||||
|
||||
if (!needs_refresh) {
|
||||
rc = 0;
|
||||
xid = get_xid();
|
||||
|
||||
path = get_ses_refpath(ses);
|
||||
if (IS_ERR(path)) {
|
||||
rc = PTR_ERR(path);
|
||||
path = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1217,29 +1183,106 @@ 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);
|
||||
ce = cache_refresh_path(xid, ses, path, false);
|
||||
if (!IS_ERR(ce))
|
||||
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);
|
||||
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 (!needs_refresh) {
|
||||
up_read(&htable_rw_lock);
|
||||
goto out;
|
||||
}
|
||||
up_read(&htable_rw_lock);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 +1323,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;
|
||||
}
|
||||
|
||||
@ -1292,8 +1335,9 @@ void dfs_cache_refresh(struct work_struct *work)
|
||||
|
||||
tcon = container_of(work, struct cifs_tcon, dfs_cache_work.work);
|
||||
|
||||
for (ses = tcon->ses; 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);
|
||||
|
||||
queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,
|
||||
atomic_read(&dfs_cache_ttl) * HZ);
|
||||
|
@ -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[];
|
||||
|
@ -834,10 +834,6 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
|
||||
fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_REG;
|
||||
|
||||
/* clear write bits if ATTR_READONLY is set */
|
||||
if (fattr->cf_cifsattrs & ATTR_READONLY)
|
||||
fattr->cf_mode &= ~(S_IWUGO);
|
||||
|
||||
/*
|
||||
* Don't accept zero nlink from non-unix servers unless
|
||||
* delete is pending. Instead mark it as unknown.
|
||||
@ -850,6 +846,10 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
|
||||
}
|
||||
}
|
||||
|
||||
/* clear write bits if ATTR_READONLY is set */
|
||||
if (fattr->cf_cifsattrs & ATTR_READONLY)
|
||||
fattr->cf_mode &= ~(S_IWUGO);
|
||||
|
||||
out_reparse:
|
||||
if (S_ISLNK(fattr->cf_mode)) {
|
||||
if (likely(data->symlink_target))
|
||||
@ -1267,11 +1267,14 @@ handle_mnt_opt:
|
||||
__func__, rc);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* fill in remaining high mode bits e.g. SUID, VTX */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
|
||||
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
|
||||
/* fill in remaining high mode bits e.g. SUID, VTX */
|
||||
cifs_sfu_mode(fattr, full_path, cifs_sb, xid);
|
||||
else if (!(tcon->posix_extensions))
|
||||
/* clear write bits if ATTR_READONLY is set */
|
||||
if (fattr->cf_cifsattrs & ATTR_READONLY)
|
||||
fattr->cf_mode &= ~(S_IWUGO);
|
||||
|
||||
|
||||
/* check for Minshall+French symlinks */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
|
||||
|
@ -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;
|
||||
}
|
||||
@ -1108,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))
|
||||
|
@ -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);
|
||||
|
||||
|
@ -108,8 +108,8 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
|
||||
buf->InodeType = cpu_to_le64(type);
|
||||
buf->ReparseDataLength = cpu_to_le16(len + dlen -
|
||||
sizeof(struct reparse_data_buffer));
|
||||
*(__le64 *)buf->DataBuffer = cpu_to_le64(((u64)MAJOR(dev) << 32) |
|
||||
MINOR(dev));
|
||||
*(__le64 *)buf->DataBuffer = cpu_to_le64(((u64)MINOR(dev) << 32) |
|
||||
MAJOR(dev));
|
||||
iov->iov_base = buf;
|
||||
iov->iov_len = len + dlen;
|
||||
return 0;
|
||||
@ -468,7 +468,7 @@ static void wsl_to_fattr(struct cifs_open_info_data *data,
|
||||
else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen))
|
||||
fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v);
|
||||
else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen))
|
||||
fattr->cf_rdev = wsl_mkdev(v);
|
||||
fattr->cf_rdev = reparse_mkdev(v);
|
||||
} while (next);
|
||||
out:
|
||||
fattr->cf_dtype = S_DT(fattr->cf_mode);
|
||||
@ -485,11 +485,11 @@ bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||
switch (le64_to_cpu(buf->InodeType)) {
|
||||
case NFS_SPECFILE_CHR:
|
||||
fattr->cf_mode |= S_IFCHR;
|
||||
fattr->cf_rdev = reparse_nfs_mkdev(buf);
|
||||
fattr->cf_rdev = reparse_mkdev(buf->DataBuffer);
|
||||
break;
|
||||
case NFS_SPECFILE_BLK:
|
||||
fattr->cf_mode |= S_IFBLK;
|
||||
fattr->cf_rdev = reparse_nfs_mkdev(buf);
|
||||
fattr->cf_rdev = reparse_mkdev(buf->DataBuffer);
|
||||
break;
|
||||
case NFS_SPECFILE_FIFO:
|
||||
fattr->cf_mode |= S_IFIFO;
|
||||
|
@ -18,14 +18,7 @@
|
||||
*/
|
||||
#define IO_REPARSE_TAG_INTERNAL ((__u32)~0U)
|
||||
|
||||
static inline dev_t reparse_nfs_mkdev(struct reparse_posix_data *buf)
|
||||
{
|
||||
u64 v = le64_to_cpu(*(__le64 *)buf->DataBuffer);
|
||||
|
||||
return MKDEV(v >> 32, v & 0xffffffff);
|
||||
}
|
||||
|
||||
static inline dev_t wsl_mkdev(void *ptr)
|
||||
static inline dev_t reparse_mkdev(void *ptr)
|
||||
{
|
||||
u64 v = le64_to_cpu(*(__le64 *)ptr);
|
||||
|
||||
|
@ -4869,9 +4869,12 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid,
|
||||
goto discard_data;
|
||||
|
||||
server->total_read += rc;
|
||||
if (rc < len)
|
||||
iov_iter_zero(len - rc, &iter);
|
||||
iov_iter_revert(&iter, len);
|
||||
if (rc < len) {
|
||||
struct iov_iter tmp = iter;
|
||||
|
||||
iov_iter_advance(&tmp, rc);
|
||||
iov_iter_zero(len - rc, &tmp);
|
||||
}
|
||||
iov_iter_truncate(&iter, dw->len);
|
||||
|
||||
rc = cifs_discard_remaining_data(server);
|
||||
|
@ -4866,7 +4866,9 @@ smb2_writev_callback(struct mid_q_entry *mid)
|
||||
#endif
|
||||
if (result) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
|
||||
trace_smb3_write_err(wdata->xid,
|
||||
trace_smb3_write_err(wdata->rreq->debug_id,
|
||||
wdata->subreq.debug_index,
|
||||
wdata->xid,
|
||||
wdata->req->cfile->fid.persistent_fid,
|
||||
tcon->tid, tcon->ses->Suid, wdata->subreq.start,
|
||||
wdata->subreq.len, wdata->result);
|
||||
@ -4874,7 +4876,9 @@ smb2_writev_callback(struct mid_q_entry *mid)
|
||||
pr_warn_once("Out of space writing to %s\n",
|
||||
tcon->tree_name);
|
||||
} else
|
||||
trace_smb3_write_done(0 /* no xid */,
|
||||
trace_smb3_write_done(wdata->rreq->debug_id,
|
||||
wdata->subreq.debug_index,
|
||||
wdata->xid,
|
||||
wdata->req->cfile->fid.persistent_fid,
|
||||
tcon->tid, tcon->ses->Suid,
|
||||
wdata->subreq.start, wdata->subreq.len);
|
||||
@ -4952,7 +4956,9 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
|
||||
offsetof(struct smb2_write_req, Buffer));
|
||||
req->RemainingBytes = 0;
|
||||
|
||||
trace_smb3_write_enter(wdata->xid,
|
||||
trace_smb3_write_enter(wdata->rreq->debug_id,
|
||||
wdata->subreq.debug_index,
|
||||
wdata->xid,
|
||||
io_parms->persistent_fid,
|
||||
io_parms->tcon->tid,
|
||||
io_parms->tcon->ses->Suid,
|
||||
@ -5032,7 +5038,9 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
|
||||
wdata, flags, &wdata->credits);
|
||||
/* Can't touch wdata if rc == 0 */
|
||||
if (rc) {
|
||||
trace_smb3_write_err(xid,
|
||||
trace_smb3_write_err(wdata->rreq->debug_id,
|
||||
wdata->subreq.debug_index,
|
||||
xid,
|
||||
io_parms->persistent_fid,
|
||||
io_parms->tcon->tid,
|
||||
io_parms->tcon->ses->Suid,
|
||||
@ -5112,7 +5120,7 @@ replay_again:
|
||||
offsetof(struct smb2_write_req, Buffer));
|
||||
req->RemainingBytes = 0;
|
||||
|
||||
trace_smb3_write_enter(xid, io_parms->persistent_fid,
|
||||
trace_smb3_write_enter(0, 0, xid, io_parms->persistent_fid,
|
||||
io_parms->tcon->tid, io_parms->tcon->ses->Suid,
|
||||
io_parms->offset, io_parms->length);
|
||||
|
||||
@ -5133,7 +5141,7 @@ replay_again:
|
||||
rsp = (struct smb2_write_rsp *)rsp_iov.iov_base;
|
||||
|
||||
if (rc) {
|
||||
trace_smb3_write_err(xid,
|
||||
trace_smb3_write_err(0, 0, xid,
|
||||
req->PersistentFileId,
|
||||
io_parms->tcon->tid,
|
||||
io_parms->tcon->ses->Suid,
|
||||
@ -5142,7 +5150,7 @@ replay_again:
|
||||
cifs_dbg(VFS, "Send error in write = %d\n", rc);
|
||||
} else {
|
||||
*nbytes = le32_to_cpu(rsp->DataLength);
|
||||
trace_smb3_write_done(xid,
|
||||
trace_smb3_write_done(0, 0, xid,
|
||||
req->PersistentFileId,
|
||||
io_parms->tcon->tid,
|
||||
io_parms->tcon->ses->Suid,
|
||||
|
@ -157,6 +157,7 @@ DEFINE_EVENT(smb3_rw_err_class, smb3_##name, \
|
||||
TP_ARGS(rreq_debug_id, rreq_debug_index, xid, fid, tid, sesid, offset, len, rc))
|
||||
|
||||
DEFINE_SMB3_RW_ERR_EVENT(read_err);
|
||||
DEFINE_SMB3_RW_ERR_EVENT(write_err);
|
||||
|
||||
/* For logging errors in other file I/O ops */
|
||||
DECLARE_EVENT_CLASS(smb3_other_err_class,
|
||||
@ -202,7 +203,6 @@ DEFINE_EVENT(smb3_other_err_class, smb3_##name, \
|
||||
int rc), \
|
||||
TP_ARGS(xid, fid, tid, sesid, offset, len, rc))
|
||||
|
||||
DEFINE_SMB3_OTHER_ERR_EVENT(write_err);
|
||||
DEFINE_SMB3_OTHER_ERR_EVENT(query_dir_err);
|
||||
DEFINE_SMB3_OTHER_ERR_EVENT(zero_err);
|
||||
DEFINE_SMB3_OTHER_ERR_EVENT(falloc_err);
|
||||
@ -370,6 +370,8 @@ DEFINE_EVENT(smb3_rw_done_class, smb3_##name, \
|
||||
|
||||
DEFINE_SMB3_RW_DONE_EVENT(read_enter);
|
||||
DEFINE_SMB3_RW_DONE_EVENT(read_done);
|
||||
DEFINE_SMB3_RW_DONE_EVENT(write_enter);
|
||||
DEFINE_SMB3_RW_DONE_EVENT(write_done);
|
||||
|
||||
/* For logging successful other op */
|
||||
DECLARE_EVENT_CLASS(smb3_other_done_class,
|
||||
@ -411,11 +413,9 @@ DEFINE_EVENT(smb3_other_done_class, smb3_##name, \
|
||||
__u32 len), \
|
||||
TP_ARGS(xid, fid, tid, sesid, offset, len))
|
||||
|
||||
DEFINE_SMB3_OTHER_DONE_EVENT(write_enter);
|
||||
DEFINE_SMB3_OTHER_DONE_EVENT(query_dir_enter);
|
||||
DEFINE_SMB3_OTHER_DONE_EVENT(zero_enter);
|
||||
DEFINE_SMB3_OTHER_DONE_EVENT(falloc_enter);
|
||||
DEFINE_SMB3_OTHER_DONE_EVENT(write_done);
|
||||
DEFINE_SMB3_OTHER_DONE_EVENT(query_dir_done);
|
||||
DEFINE_SMB3_OTHER_DONE_EVENT(zero_done);
|
||||
DEFINE_SMB3_OTHER_DONE_EVENT(falloc_done);
|
||||
|
@ -1817,11 +1817,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
length = data_len; /* An RDMA read is already done. */
|
||||
else
|
||||
#endif
|
||||
{
|
||||
length = cifs_read_iter_from_socket(server, &rdata->subreq.io_iter,
|
||||
data_len);
|
||||
iov_iter_revert(&rdata->subreq.io_iter, data_len);
|
||||
}
|
||||
if (length > 0)
|
||||
rdata->got_bytes += length;
|
||||
server->total_read += length;
|
||||
|
Loading…
Reference in New Issue
Block a user