Commit 45db3ab7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '6.9-rc7-ksmbd-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:
 "Five ksmbd server fixes, all also for stable

   - Three fixes related to SMB3 leases (fixes two xfstests, and a
     locking issue)

   - Unitialized variable fix

   - Socket creation fix when bindv6only is set"

* tag '6.9-rc7-ksmbd-fixes' of git://git.samba.org/ksmbd:
  ksmbd: do not grant v2 lease if parent lease key and epoch are not set
  ksmbd: use rwsem instead of rwlock for lease break
  ksmbd: avoid to send duplicate lease break notifications
  ksmbd: off ipv6only for both ipv4/ipv6 binding
  ksmbd: fix uninitialized symbol 'share' in smb2_tree_connect()
parents 065a057a 691aae4f
Loading
Loading
Loading
Loading
+35 −30
Original line number Diff line number Diff line
@@ -207,9 +207,9 @@ static void opinfo_add(struct oplock_info *opinfo)
{
	struct ksmbd_inode *ci = opinfo->o_fp->f_ci;

	write_lock(&ci->m_lock);
	down_write(&ci->m_lock);
	list_add_rcu(&opinfo->op_entry, &ci->m_op_list);
	write_unlock(&ci->m_lock);
	up_write(&ci->m_lock);
}

static void opinfo_del(struct oplock_info *opinfo)
@@ -221,9 +221,9 @@ static void opinfo_del(struct oplock_info *opinfo)
		lease_del_list(opinfo);
		write_unlock(&lease_list_lock);
	}
	write_lock(&ci->m_lock);
	down_write(&ci->m_lock);
	list_del_rcu(&opinfo->op_entry);
	write_unlock(&ci->m_lock);
	up_write(&ci->m_lock);
}

static unsigned long opinfo_count(struct ksmbd_file *fp)
@@ -526,21 +526,18 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,
	 * Compare lease key and client_guid to know request from same owner
	 * of same client
	 */
	read_lock(&ci->m_lock);
	down_read(&ci->m_lock);
	list_for_each_entry(opinfo, &ci->m_op_list, op_entry) {
		if (!opinfo->is_lease || !opinfo->conn)
			continue;
		read_unlock(&ci->m_lock);
		lease = opinfo->o_lease;

		ret = compare_guid_key(opinfo, client_guid, lctx->lease_key);
		if (ret) {
			m_opinfo = opinfo;
			/* skip upgrading lease about breaking lease */
			if (atomic_read(&opinfo->breaking_cnt)) {
				read_lock(&ci->m_lock);
			if (atomic_read(&opinfo->breaking_cnt))
				continue;
			}

			/* upgrading lease */
			if ((atomic_read(&ci->op_count) +
@@ -570,9 +567,8 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,
				lease_none_upgrade(opinfo, lctx->req_state);
			}
		}
		read_lock(&ci->m_lock);
	}
	read_unlock(&ci->m_lock);
	up_read(&ci->m_lock);

	return m_opinfo;
}
@@ -613,14 +609,24 @@ static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level)

		if (opinfo->op_state == OPLOCK_CLOSING)
			return -ENOENT;
		else if (!opinfo->is_lease && opinfo->level <= req_op_level)
		else if (opinfo->level <= req_op_level) {
			if (opinfo->is_lease &&
			    opinfo->o_lease->state !=
			     (SMB2_LEASE_HANDLE_CACHING_LE |
			      SMB2_LEASE_READ_CACHING_LE))
				return 1;
		}
	}

	if (!opinfo->is_lease && opinfo->level <= req_op_level) {
	if (opinfo->level <= req_op_level) {
		if (opinfo->is_lease &&
		    opinfo->o_lease->state !=
		     (SMB2_LEASE_HANDLE_CACHING_LE |
		      SMB2_LEASE_READ_CACHING_LE)) {
			wake_up_oplock_break(opinfo);
			return 1;
		}
	}
	return 0;
}

@@ -887,7 +893,6 @@ static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level)
		struct lease *lease = brk_opinfo->o_lease;

		atomic_inc(&brk_opinfo->breaking_cnt);

		err = oplock_break_pending(brk_opinfo, req_op_level);
		if (err)
			return err < 0 ? err : 0;
@@ -1105,7 +1110,7 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
	if (!p_ci)
		return;

	read_lock(&p_ci->m_lock);
	down_read(&p_ci->m_lock);
	list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) {
		if (opinfo->conn == NULL || !opinfo->is_lease)
			continue;
@@ -1123,13 +1128,11 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
				continue;
			}

			read_unlock(&p_ci->m_lock);
			oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);
			opinfo_conn_put(opinfo);
			read_lock(&p_ci->m_lock);
		}
	}
	read_unlock(&p_ci->m_lock);
	up_read(&p_ci->m_lock);

	ksmbd_inode_put(p_ci);
}
@@ -1150,7 +1153,7 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
	if (!p_ci)
		return;

	read_lock(&p_ci->m_lock);
	down_read(&p_ci->m_lock);
	list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) {
		if (opinfo->conn == NULL || !opinfo->is_lease)
			continue;
@@ -1164,13 +1167,11 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
				atomic_dec(&opinfo->conn->r_count);
				continue;
			}
			read_unlock(&p_ci->m_lock);
			oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);
			opinfo_conn_put(opinfo);
			read_lock(&p_ci->m_lock);
		}
	}
	read_unlock(&p_ci->m_lock);
	up_read(&p_ci->m_lock);

	ksmbd_inode_put(p_ci);
}
@@ -1200,7 +1201,9 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,

	/* Only v2 leases handle the directory */
	if (S_ISDIR(file_inode(fp->filp)->i_mode)) {
		if (!lctx || lctx->version != 2)
		if (!lctx || lctx->version != 2 ||
		    (lctx->flags != SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE &&
		     !lctx->epoch))
			return 0;
	}

@@ -1465,6 +1468,7 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
		buf->lcontext.LeaseFlags = lease->flags;
		buf->lcontext.Epoch = cpu_to_le16(lease->epoch);
		buf->lcontext.LeaseState = lease->state;
		if (lease->flags == SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE)
			memcpy(buf->lcontext.ParentLeaseKey, lease->parent_lease_key,
			       SMB2_LEASE_KEY_SIZE);
		buf->ccontext.DataOffset = cpu_to_le16(offsetof
@@ -1525,6 +1529,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
		lreq->flags = lc->lcontext.LeaseFlags;
		lreq->epoch = lc->lcontext.Epoch;
		lreq->duration = lc->lcontext.LeaseDuration;
		if (lreq->flags == SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE)
			memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,
			       SMB2_LEASE_KEY_SIZE);
		lreq->version = 2;
+4 −4
Original line number Diff line number Diff line
@@ -1926,7 +1926,7 @@ int smb2_tree_connect(struct ksmbd_work *work)
	struct ksmbd_session *sess = work->sess;
	char *treename = NULL, *name = NULL;
	struct ksmbd_tree_conn_status status;
	struct ksmbd_share_config *share;
	struct ksmbd_share_config *share = NULL;
	int rc = -EINVAL;

	WORK_BUFFERS(work, req, rsp);
@@ -1988,7 +1988,7 @@ int smb2_tree_connect(struct ksmbd_work *work)
	write_unlock(&sess->tree_conns_lock);
	rsp->StructureSize = cpu_to_le16(16);
out_err1:
	if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE &&
	if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE && share &&
	    test_share_config_flag(share,
				   KSMBD_SHARE_FLAG_CONTINUOUS_AVAILABILITY))
		rsp->Capabilities = SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;
@@ -3376,9 +3376,9 @@ int smb2_open(struct ksmbd_work *work)
	 * after daccess, saccess, attrib_only, and stream are
	 * initialized.
	 */
	write_lock(&fp->f_ci->m_lock);
	down_write(&fp->f_ci->m_lock);
	list_add(&fp->node, &fp->f_ci->m_fp_list);
	write_unlock(&fp->f_ci->m_lock);
	up_write(&fp->f_ci->m_lock);

	/* Check delete pending among previous fp before oplock break */
	if (ksmbd_inode_pending_delete(fp)) {
+2 −2
Original line number Diff line number Diff line
@@ -646,7 +646,7 @@ int ksmbd_smb_check_shared_mode(struct file *filp, struct ksmbd_file *curr_fp)
	 * Lookup fp in master fp list, and check desired access and
	 * shared mode between previous open and current open.
	 */
	read_lock(&curr_fp->f_ci->m_lock);
	down_read(&curr_fp->f_ci->m_lock);
	list_for_each_entry(prev_fp, &curr_fp->f_ci->m_fp_list, node) {
		if (file_inode(filp) != file_inode(prev_fp->filp))
			continue;
@@ -722,7 +722,7 @@ int ksmbd_smb_check_shared_mode(struct file *filp, struct ksmbd_file *curr_fp)
			break;
		}
	}
	read_unlock(&curr_fp->f_ci->m_lock);
	up_read(&curr_fp->f_ci->m_lock);

	return rc;
}
+4 −0
Original line number Diff line number Diff line
@@ -448,6 +448,10 @@ static int create_socket(struct interface *iface)
		sin6.sin6_family = PF_INET6;
		sin6.sin6_addr = in6addr_any;
		sin6.sin6_port = htons(server_conf.tcp_port);

		lock_sock(ksmbd_socket->sk);
		ksmbd_socket->sk->sk_ipv6only = false;
		release_sock(ksmbd_socket->sk);
	}

	ksmbd_tcp_nodelay(ksmbd_socket);
+14 −14
Original line number Diff line number Diff line
@@ -165,7 +165,7 @@ static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp)
	ci->m_fattr = 0;
	INIT_LIST_HEAD(&ci->m_fp_list);
	INIT_LIST_HEAD(&ci->m_op_list);
	rwlock_init(&ci->m_lock);
	init_rwsem(&ci->m_lock);
	ci->m_de = fp->filp->f_path.dentry;
	return 0;
}
@@ -261,14 +261,14 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp)
	}

	if (atomic_dec_and_test(&ci->m_count)) {
		write_lock(&ci->m_lock);
		down_write(&ci->m_lock);
		if (ci->m_flags & (S_DEL_ON_CLS | S_DEL_PENDING)) {
			ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING);
			write_unlock(&ci->m_lock);
			up_write(&ci->m_lock);
			ksmbd_vfs_unlink(filp);
			write_lock(&ci->m_lock);
			down_write(&ci->m_lock);
		}
		write_unlock(&ci->m_lock);
		up_write(&ci->m_lock);

		ksmbd_inode_free(ci);
	}
@@ -289,9 +289,9 @@ static void __ksmbd_remove_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp
	if (!has_file_id(fp->volatile_id))
		return;

	write_lock(&fp->f_ci->m_lock);
	down_write(&fp->f_ci->m_lock);
	list_del_init(&fp->node);
	write_unlock(&fp->f_ci->m_lock);
	up_write(&fp->f_ci->m_lock);

	write_lock(&ft->lock);
	idr_remove(ft->idr, fp->volatile_id);
@@ -523,17 +523,17 @@ struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry)
	if (!ci)
		return NULL;

	read_lock(&ci->m_lock);
	down_read(&ci->m_lock);
	list_for_each_entry(lfp, &ci->m_fp_list, node) {
		if (inode == file_inode(lfp->filp)) {
			atomic_dec(&ci->m_count);
			lfp = ksmbd_fp_get(lfp);
			read_unlock(&ci->m_lock);
			up_read(&ci->m_lock);
			return lfp;
		}
	}
	atomic_dec(&ci->m_count);
	read_unlock(&ci->m_lock);
	up_read(&ci->m_lock);
	return NULL;
}

@@ -705,13 +705,13 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,

	conn = fp->conn;
	ci = fp->f_ci;
	write_lock(&ci->m_lock);
	down_write(&ci->m_lock);
	list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) {
		if (op->conn != conn)
			continue;
		op->conn = NULL;
	}
	write_unlock(&ci->m_lock);
	up_write(&ci->m_lock);

	fp->conn = NULL;
	fp->tcon = NULL;
@@ -801,13 +801,13 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
	fp->tcon = work->tcon;

	ci = fp->f_ci;
	write_lock(&ci->m_lock);
	down_write(&ci->m_lock);
	list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) {
		if (op->conn)
			continue;
		op->conn = fp->conn;
	}
	write_unlock(&ci->m_lock);
	up_write(&ci->m_lock);

	__open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID);
	if (!has_file_id(fp->volatile_id)) {
Loading