Commit 4ec9c8e0 authored by ChenXiaoSong's avatar ChenXiaoSong Committed by Steve French
Browse files

smb/server: promote S_DEL_ON_CLS to S_DEL_PENDING when close

Reproducer:

  1. server: systemctl start ksmbd
  2. client: mount -t cifs //${server_ip}/export /mnt
  3. client: C program: openat(AT_FDCWD, "/mnt", O_RDWR | O_TMPFILE, 0600)

Do not treat `FILE_DELETE_ON_CLOSE_LE` as delete pending while files
remain open.

This patch fixes xfstests generic/004.

Cc: stable@vger.kernel.org
Link: https://chenxiaosong.com/en/smb-xfstests-generic-004.html


Co-developed-by: default avatarHuiwen He <hehuiwen@kylinos.cn>
Signed-off-by: default avatarHuiwen He <hehuiwen@kylinos.cn>
Signed-off-by: default avatarChenXiaoSong <chenxiaosong@kylinos.cn>
Tested-by: default avatarSteve French <stfrench@microsoft.com>
Acked-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 69f030cf
Loading
Loading
Loading
Loading
+12 −4
Original line number Diff line number Diff line
@@ -211,7 +211,7 @@ int ksmbd_query_inode_status(struct dentry *dentry)
		return ret;

	down_read(&ci->m_lock);
	if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS))
	if (ci->m_flags & S_DEL_PENDING)
		ret = KSMBD_INODE_STATUS_PENDING_DELETE;
	else
		ret = KSMBD_INODE_STATUS_OK;
@@ -227,7 +227,7 @@ bool ksmbd_inode_pending_delete(struct ksmbd_file *fp)
	int ret;

	down_read(&ci->m_lock);
	ret = (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS));
	ret = (ci->m_flags & S_DEL_PENDING);
	up_read(&ci->m_lock);

	return ret;
@@ -395,12 +395,20 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp)
		}
	}

	down_write(&ci->m_lock);
	/* Promote S_DEL_ON_CLS to S_DEL_PENDING when close */
	if (ci->m_flags & S_DEL_ON_CLS) {
		ci->m_flags &= ~S_DEL_ON_CLS;
		ci->m_flags |= S_DEL_PENDING;
	}
	up_write(&ci->m_lock);

	if (atomic_dec_and_test(&ci->m_count)) {
		bool do_unlink = false;

		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);
		if (ci->m_flags & S_DEL_PENDING) {
			ci->m_flags &= ~S_DEL_PENDING;
			do_unlink = true;
		}
		up_write(&ci->m_lock);