Skip to content

Commit

Permalink
Merge tag 'v6.12-rc-smb3-client-fixes-part2' of git://git.samba.org/s…
Browse files Browse the repository at this point in the history
…french/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
  • Loading branch information
torvalds committed Sep 26, 2024
2 parents 5159938 + 665db14 commit ac34bb4
Show file tree
Hide file tree
Showing 18 changed files with 282 additions and 224 deletions.
1 change: 1 addition & 0 deletions fs/netfs/buffered_write.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions fs/smb/client/cifsfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
3 changes: 3 additions & 0 deletions fs/smb/client/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand Down
12 changes: 2 additions & 10 deletions fs/smb/client/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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)
Expand Down
66 changes: 32 additions & 34 deletions fs/smb/client/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1873,13 +1873,15 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
}

/* 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;

/*
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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);

Expand Down Expand Up @@ -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
}

/**
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -3623,13 +3629,12 @@ int cifs_is_path_remote(struct cifs_mount_ctx *mnt_ctx)
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;

/*
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -4132,17 +4137,6 @@ __cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
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)
{
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
}
Expand All @@ -4262,8 +4256,9 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb)

/* 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))
Expand All @@ -4275,8 +4270,11 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
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;
Expand Down
Loading

0 comments on commit ac34bb4

Please sign in to comment.