Commit 44b550d8 authored by Nan Li's avatar Nan Li Committed by Paolo Abeni
Browse files

net/rds: handle zerocopy send cleanup before the message is queued



A zerocopy send can fail after user pages have been pinned but before
the message is attached to the sending socket.

The purge path currently infers zerocopy state from rm->m_rs, so an
unqueued message can be cleaned up as if it owned normal payload pages.
However, zerocopy ownership is really determined by the presence of
op_mmp_znotifier, regardless of whether the message has reached the
socket queue.

Capture op_mmp_znotifier up front in rds_message_purge() and use it as
the cleanup discriminator. If the message is already associated with a
socket, keep the existing completion path. Otherwise, drop the pinned
page accounting directly and release the notifier before putting the
payload pages.

This keeps early send failure cleanup consistent with the zerocopy
lifetime rules without changing the normal queued completion path.

Fixes: 0cebacce ("rds: zerocopy Tx support.")
Cc: stable@kernel.org
Reported-by: default avatarYuan Tan <yuantan098@gmail.com>
Reported-by: default avatarYifan Wu <yifanwucs@gmail.com>
Reported-by: default avatarJuefei Pu <tomapufckgml@gmail.com>
Reported-by: default avatarXin Liu <bird@lzu.edu.cn>
Co-developed-by: default avatarXiao Liu <lx24@stu.ynu.edu.cn>
Signed-off-by: default avatarXiao Liu <lx24@stu.ynu.edu.cn>
Signed-off-by: default avatarNan Li <tonanli66@gmail.com>
Signed-off-by: default avatarRen Wei <n05ec@lzu.edu.cn>
Reviewed-by: default avatarAllison Henderson <achender@kernel.org>
Link: https://patch.msgid.link/d2ea98a6313d5467bac00f7c9fef8c7acddb9258.1777550074.git.tonanli66@gmail.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 0c21517a
Loading
Loading
Loading
Loading
+15 −5
Original line number Diff line number Diff line
@@ -131,24 +131,34 @@ static void rds_rm_zerocopy_callback(struct rds_sock *rs,
 */
static void rds_message_purge(struct rds_message *rm)
{
	struct rds_znotifier *znotifier;
	unsigned long i, flags;
	bool zcopy = false;
	bool zcopy;

	if (unlikely(test_bit(RDS_MSG_PAGEVEC, &rm->m_flags)))
		return;

	spin_lock_irqsave(&rm->m_rs_lock, flags);
	znotifier = rm->data.op_mmp_znotifier;
	rm->data.op_mmp_znotifier = NULL;
	zcopy = !!znotifier;

	if (rm->m_rs) {
		struct rds_sock *rs = rm->m_rs;

		if (rm->data.op_mmp_znotifier) {
			zcopy = true;
			rds_rm_zerocopy_callback(rs, rm->data.op_mmp_znotifier);
		if (znotifier) {
			rds_rm_zerocopy_callback(rs, znotifier);
			rds_wake_sk_sleep(rs);
			rm->data.op_mmp_znotifier = NULL;
		}
		sock_put(rds_rs_to_sk(rs));
		rm->m_rs = NULL;
	} else if (znotifier) {
		/*
		 * Zerocopy can fail before the message is queued on the
		 * socket, so there is no rs to carry the notification.
		 */
		mm_unaccount_pinned_pages(&znotifier->z_mmp);
		kfree(rds_info_from_znotifier(znotifier));
	}
	spin_unlock_irqrestore(&rm->m_rs_lock, flags);