diff options
Diffstat (limited to 'fs/aio.c')
| -rw-r--r-- | fs/aio.c | 20 | 
1 files changed, 18 insertions, 2 deletions
@@ -1610,6 +1610,14 @@ static int aio_fsync(struct fsync_iocb *req, const struct iocb *iocb,  	return 0;  } +static void aio_poll_put_work(struct work_struct *work) +{ +	struct poll_iocb *req = container_of(work, struct poll_iocb, work); +	struct aio_kiocb *iocb = container_of(req, struct aio_kiocb, poll); + +	iocb_put(iocb); +} +  static void aio_poll_complete_work(struct work_struct *work)  {  	struct poll_iocb *req = container_of(work, struct poll_iocb, work); @@ -1674,6 +1682,8 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,  	list_del_init(&req->wait.entry);  	if (mask && spin_trylock_irqsave(&iocb->ki_ctx->ctx_lock, flags)) { +		struct kioctx *ctx = iocb->ki_ctx; +  		/*  		 * Try to complete the iocb inline if we can. Use  		 * irqsave/irqrestore because not all filesystems (e.g. fuse) @@ -1683,8 +1693,14 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,  		list_del(&iocb->ki_list);  		iocb->ki_res.res = mangle_poll(mask);  		req->done = true; -		spin_unlock_irqrestore(&iocb->ki_ctx->ctx_lock, flags); -		iocb_put(iocb); +		if (iocb->ki_eventfd && eventfd_signal_count()) { +			iocb = NULL; +			INIT_WORK(&req->work, aio_poll_put_work); +			schedule_work(&req->work); +		} +		spin_unlock_irqrestore(&ctx->ctx_lock, flags); +		if (iocb) +			iocb_put(iocb);  	} else {  		schedule_work(&req->work);  	}  |