Commit d8cc62a9 authored by Amir Goldstein's avatar Amir Goldstein Committed by sanglipeng
Browse files

ovl: fix incorrect fdput() on aio completion

stable inclusion
from stable-v5.10.197
commit c6422e6f173d760239cd250eb21fb35a43c54936
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I96Q8P

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=c6422e6f173d760239cd250eb21fb35a43c54936



--------------------------------

commit 724768a3 upstream.

ovl_{read,write}_iter() always call fdput(real) to put one or zero
refcounts of the real file, but for aio, whether it was submitted or not,
ovl_aio_put() also calls fdput(), which is not balanced.  This is only a
problem in the less common case when FDPUT_FPUT flag is set.

To fix the problem use get_file() to take file refcount and use fput()
instead of fdput() in ovl_aio_put().

Fixes: 2406a307 ("ovl: implement async IO routines")
Cc: <stable@vger.kernel.org> # v5.6
Reviewed-by: default avatarMiklos Szeredi <miklos@szeredi.hu>
Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarsanglipeng <sanglipeng1@jd.com>
parent fedd1640
Loading
Loading
Loading
Loading
+3 −6
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ struct ovl_aio_req {
	struct kiocb iocb;
	refcount_t ref;
	struct kiocb *orig_iocb;
	struct fd fd;
};

static struct kmem_cache *ovl_aio_request_cachep;
@@ -256,7 +255,7 @@ static rwf_t ovl_iocb_to_rwf(int ifl)
static inline void ovl_aio_put(struct ovl_aio_req *aio_req)
{
	if (refcount_dec_and_test(&aio_req->ref)) {
		fdput(aio_req->fd);
		fput(aio_req->iocb.ki_filp);
		kmem_cache_free(ovl_aio_request_cachep, aio_req);
	}
}
@@ -322,10 +321,9 @@ static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
		if (!aio_req)
			goto out;

		aio_req->fd = real;
		real.flags = 0;
		aio_req->orig_iocb = iocb;
		kiocb_clone(&aio_req->iocb, iocb, real.file);
		kiocb_clone(&aio_req->iocb, iocb, get_file(real.file));
		aio_req->iocb.ki_complete = ovl_aio_rw_complete;
		refcount_set(&aio_req->ref, 2);
		ret = vfs_iocb_iter_read(real.file, &aio_req->iocb, iter);
@@ -394,10 +392,9 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
		/* Pacify lockdep, same trick as done in aio_write() */
		__sb_writers_release(file_inode(real.file)->i_sb,
				     SB_FREEZE_WRITE);
		aio_req->fd = real;
		real.flags = 0;
		aio_req->orig_iocb = iocb;
		kiocb_clone(&aio_req->iocb, iocb, real.file);
		kiocb_clone(&aio_req->iocb, iocb, get_file(real.file));
		aio_req->iocb.ki_flags = ifl;
		aio_req->iocb.ki_complete = ovl_aio_rw_complete;
		refcount_set(&aio_req->ref, 2);