Commit 24b62696 authored by Hyunchul Lee's avatar Hyunchul Lee Committed by Steve French
Browse files

cifsd: fix reference count decrement of unclaimed file in __ksmbd_lookup_fd



__ksmbd_lookup_fd could decrement the reference count of
unclaimed ksmbd_file to 0 but not release this ksmbd_file.

ksmbd_file cannot be unclaimed except ksmbd_close_inode_fds(),
because ksmbd_file is only removed from the m_fp_list list
after the reference count of ksmbd_file becomes 0. And if the
count is 0, __ksmbd_lookup_fd does not use ksmbd_file found
from idr due to atomic_inc_not_zero.

Signed-off-by: default avatarHyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: default avatarNamjae Jeon <namjae.jeon@samsung.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 3c203783
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -2779,11 +2779,6 @@ int smb2_open(struct ksmbd_work *work)
		goto err_out;
	}

	if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE &&
	    file_present)
		file_present = ksmbd_close_inode_fds(work,
						     d_inode(path.dentry));

	daccess = smb_map_generic_desired_access(req->DesiredAccess);

	if (file_present && !(req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) {
+0 −53
Original line number Diff line number Diff line
@@ -328,25 +328,13 @@ static struct ksmbd_file *ksmbd_fp_get(struct ksmbd_file *fp)
static struct ksmbd_file *__ksmbd_lookup_fd(struct ksmbd_file_table *ft,
		unsigned int id)
{
	bool unclaimed = true;
	struct ksmbd_file *fp;

	read_lock(&ft->lock);
	fp = idr_find(ft->idr, id);
	if (fp)
		fp = ksmbd_fp_get(fp);

	if (fp && fp->f_ci) {
		read_lock(&fp->f_ci->m_lock);
		unclaimed = list_empty(&fp->node);
		read_unlock(&fp->f_ci->m_lock);
	}
	read_unlock(&ft->lock);

	if (fp && unclaimed) {
		atomic_dec(&fp->refcount);
		return NULL;
	}
	return fp;
}

@@ -754,47 +742,6 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
	return 0;
}

static void close_fd_list(struct ksmbd_work *work, struct list_head *head)
{
	while (!list_empty(head)) {
		struct ksmbd_file *fp;

		fp = list_first_entry(head, struct ksmbd_file, node);
		list_del_init(&fp->node);

		__ksmbd_close_fd(&work->sess->file_table, fp);
	}
}

int ksmbd_close_inode_fds(struct ksmbd_work *work, struct inode *inode)
{
	struct ksmbd_inode *ci;
	bool unlinked = true;
	struct ksmbd_file *fp, *fptmp;
	LIST_HEAD(dispose);

	ci = ksmbd_inode_lookup_by_vfsinode(inode);
	if (!ci)
		return true;

	if (ci->m_flags & (S_DEL_ON_CLS | S_DEL_PENDING))
		unlinked = false;

	write_lock(&ci->m_lock);
	list_for_each_entry_safe(fp, fptmp, &ci->m_fp_list, node) {
		if (fp->conn)
			continue;

		list_del(&fp->node);
		list_add(&fp->node, &dispose);
	}
	atomic_dec(&ci->m_count);
	write_unlock(&ci->m_lock);

	close_fd_list(work, &dispose);
	return unlinked;
}

int ksmbd_file_table_flush(struct ksmbd_work *work)
{
	struct ksmbd_file	*fp = NULL;