Commit ac34bb40 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents 5159938e 665db14d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;
+2 −2
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
@@ -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 */
+2 −10
Original line number Diff line number Diff line
@@ -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));
}

/* Get an active reference of @ses and its children.
@@ -746,8 +740,6 @@ 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++;
}

+32 −34
Original line number Diff line number Diff line
@@ -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 @@ 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;

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

	/*
@@ -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 @@ __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)
{
@@ -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 @@ 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))
@@ -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;
Loading