diff options
Diffstat (limited to 'fs/aio.c')
| -rw-r--r-- | fs/aio.c | 41 | 
1 files changed, 31 insertions, 10 deletions
@@ -30,6 +30,7 @@  #include <linux/highmem.h>  #include <linux/workqueue.h>  #include <linux/security.h> +#include <linux/eventfd.h>  #include <asm/kmap_types.h>  #include <asm/uaccess.h> @@ -68,10 +69,8 @@ static void aio_queue_work(struct kioctx *);   */  static int __init aio_setup(void)  { -	kiocb_cachep = kmem_cache_create("kiocb", sizeof(struct kiocb), -				0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); -	kioctx_cachep = kmem_cache_create("kioctx", sizeof(struct kioctx), -				0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); +	kiocb_cachep = KMEM_CACHE(kiocb, SLAB_HWCACHE_ALIGN|SLAB_PANIC); +	kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC);  	aio_wq = create_workqueue("aio"); @@ -348,10 +347,9 @@ void fastcall exit_aio(struct mm_struct *mm)  		wait_for_all_aios(ctx);  		/* -		 * this is an overkill, but ensures we don't leave -		 * the ctx on the aio_wq +		 * Ensure we don't leave the ctx on the aio_wq  		 */ -		flush_workqueue(aio_wq); +		cancel_work_sync(&ctx->wq.work);  		if (1 != atomic_read(&ctx->users))  			printk(KERN_DEBUG @@ -374,7 +372,7 @@ void fastcall __put_ioctx(struct kioctx *ctx)  	BUG_ON(ctx->reqs_active);  	cancel_delayed_work(&ctx->wq); -	flush_workqueue(aio_wq); +	cancel_work_sync(&ctx->wq.work);  	aio_free_ring(ctx);  	mmdrop(ctx->mm);  	ctx->mm = NULL; @@ -420,6 +418,7 @@ static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx)  	req->private = NULL;  	req->ki_iovec = NULL;  	INIT_LIST_HEAD(&req->ki_run_list); +	req->ki_eventfd = ERR_PTR(-EINVAL);  	/* Check if the completion queue has enough free space to  	 * accept an event from this io. @@ -461,6 +460,8 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req)  {  	assert_spin_locked(&ctx->ctx_lock); +	if (!IS_ERR(req->ki_eventfd)) +		fput(req->ki_eventfd);  	if (req->ki_dtor)  		req->ki_dtor(req);  	if (req->ki_iovec != &req->ki_inline_vec) @@ -945,6 +946,14 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2)  		return 1;  	} +	/* +	 * Check if the user asked us to deliver the result through an +	 * eventfd. The eventfd_signal() function is safe to be called +	 * from IRQ context. +	 */ +	if (!IS_ERR(iocb->ki_eventfd)) +		eventfd_signal(iocb->ki_eventfd, 1); +  	info = &ctx->ring_info;  	/* add a completion event to the ring buffer. @@ -1529,8 +1538,7 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,  	ssize_t ret;  	/* enforce forwards compatibility on users */ -	if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2 || -		     iocb->aio_reserved3)) { +	if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2)) {  		pr_debug("EINVAL: io_submit: reserve field set\n");  		return -EINVAL;  	} @@ -1554,6 +1562,19 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,  		fput(file);  		return -EAGAIN;  	} +	if (iocb->aio_flags & IOCB_FLAG_RESFD) { +		/* +		 * If the IOCB_FLAG_RESFD flag of aio_flags is set, get an +		 * instance of the file* now. The file descriptor must be +		 * an eventfd() fd, and will be signaled for each completed +		 * event using the eventfd_signal() function. +		 */ +		req->ki_eventfd = eventfd_fget((int) iocb->aio_resfd); +		if (unlikely(IS_ERR(req->ki_eventfd))) { +			ret = PTR_ERR(req->ki_eventfd); +			goto out_put_req; +		} +	}  	req->ki_filp = file;  	ret = put_user(req->ki_key, &user_iocb->aio_key);  | 
