diff options
author | Kent Overstreet <koverstreet@google.com> | 2013-05-07 19:18:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-07 21:38:29 -0400 |
commit | 0460fef2a9215680f7f85415b57731b7e0fdf673 (patch) | |
tree | a97456b0a9c6c6f66c4f22eac11d037be4c4d290 /include/linux/aio.h | |
parent | 21b40200cfe961b1428a529c63c33b1f1e1b4738 (diff) |
aio: use cancellation list lazily
Cancelling kiocbs requires adding them to a per kioctx linked list,
which is one of the few things we need to take the kioctx lock for in
the fast path. But most kiocbs can't be cancelled - so if we just do
this lazily, we can avoid quite a bit of locking overhead.
While we're at it, instead of using a flag bit switch to using ki_cancel
itself to indicate that a kiocb has been cancelled/completed. This lets
us get rid of ki_flags entirely.
[akpm@linux-foundation.org: remove buggy BUG()]
Signed-off-by: Kent Overstreet <koverstreet@google.com>
Cc: Zach Brown <zab@redhat.com>
Cc: Felipe Balbi <balbi@ti.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Asai Thambi S P <asamymuthupa@micron.com>
Cc: Selvan Mani <smani@micron.com>
Cc: Sam Bradshaw <sbradshaw@micron.com>
Cc: Jeff Moyer <jmoyer@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Benjamin LaHaise <bcrl@kvack.org>
Reviewed-by: "Theodore Ts'o" <tytso@mit.edu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux/aio.h')
-rw-r--r-- | include/linux/aio.h | 27 |
1 files changed, 18 insertions, 9 deletions
diff --git a/include/linux/aio.h b/include/linux/aio.h index 1e728f0086f8..d2a00038ec77 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h | |||
@@ -10,17 +10,24 @@ | |||
10 | #include <linux/atomic.h> | 10 | #include <linux/atomic.h> |
11 | 11 | ||
12 | struct kioctx; | 12 | struct kioctx; |
13 | struct kiocb; | ||
13 | 14 | ||
14 | #define KIOCB_SYNC_KEY (~0U) | 15 | #define KIOCB_SYNC_KEY (~0U) |
15 | 16 | ||
16 | /* ki_flags bits */ | 17 | /* |
17 | #define KIF_CANCELLED 2 | 18 | * We use ki_cancel == KIOCB_CANCELLED to indicate that a kiocb has been either |
18 | 19 | * cancelled or completed (this makes a certain amount of sense because | |
19 | #define kiocbSetCancelled(iocb) set_bit(KIF_CANCELLED, &(iocb)->ki_flags) | 20 | * successful cancellation - io_cancel() - does deliver the completion to |
20 | 21 | * userspace). | |
21 | #define kiocbClearCancelled(iocb) clear_bit(KIF_CANCELLED, &(iocb)->ki_flags) | 22 | * |
23 | * And since most things don't implement kiocb cancellation and we'd really like | ||
24 | * kiocb completion to be lockless when possible, we use ki_cancel to | ||
25 | * synchronize cancellation and completion - we only set it to KIOCB_CANCELLED | ||
26 | * with xchg() or cmpxchg(), see batch_complete_aio() and kiocb_cancel(). | ||
27 | */ | ||
28 | #define KIOCB_CANCELLED ((void *) (~0ULL)) | ||
22 | 29 | ||
23 | #define kiocbIsCancelled(iocb) test_bit(KIF_CANCELLED, &(iocb)->ki_flags) | 30 | typedef int (kiocb_cancel_fn)(struct kiocb *, struct io_event *); |
24 | 31 | ||
25 | /* is there a better place to document function pointer methods? */ | 32 | /* is there a better place to document function pointer methods? */ |
26 | /** | 33 | /** |
@@ -48,13 +55,12 @@ struct kioctx; | |||
48 | * calls may result in undefined behaviour. | 55 | * calls may result in undefined behaviour. |
49 | */ | 56 | */ |
50 | struct kiocb { | 57 | struct kiocb { |
51 | unsigned long ki_flags; | ||
52 | atomic_t ki_users; | 58 | atomic_t ki_users; |
53 | unsigned ki_key; /* id of this request */ | 59 | unsigned ki_key; /* id of this request */ |
54 | 60 | ||
55 | struct file *ki_filp; | 61 | struct file *ki_filp; |
56 | struct kioctx *ki_ctx; /* may be NULL for sync ops */ | 62 | struct kioctx *ki_ctx; /* may be NULL for sync ops */ |
57 | int (*ki_cancel)(struct kiocb *, struct io_event *); | 63 | kiocb_cancel_fn *ki_cancel; |
58 | ssize_t (*ki_retry)(struct kiocb *); | 64 | ssize_t (*ki_retry)(struct kiocb *); |
59 | void (*ki_dtor)(struct kiocb *); | 65 | void (*ki_dtor)(struct kiocb *); |
60 | 66 | ||
@@ -112,6 +118,7 @@ struct mm_struct; | |||
112 | extern void exit_aio(struct mm_struct *mm); | 118 | extern void exit_aio(struct mm_struct *mm); |
113 | extern long do_io_submit(aio_context_t ctx_id, long nr, | 119 | extern long do_io_submit(aio_context_t ctx_id, long nr, |
114 | struct iocb __user *__user *iocbpp, bool compat); | 120 | struct iocb __user *__user *iocbpp, bool compat); |
121 | void kiocb_set_cancel_fn(struct kiocb *req, kiocb_cancel_fn *cancel); | ||
115 | #else | 122 | #else |
116 | static inline ssize_t wait_on_sync_kiocb(struct kiocb *iocb) { return 0; } | 123 | static inline ssize_t wait_on_sync_kiocb(struct kiocb *iocb) { return 0; } |
117 | static inline void aio_put_req(struct kiocb *iocb) { } | 124 | static inline void aio_put_req(struct kiocb *iocb) { } |
@@ -121,6 +128,8 @@ static inline void exit_aio(struct mm_struct *mm) { } | |||
121 | static inline long do_io_submit(aio_context_t ctx_id, long nr, | 128 | static inline long do_io_submit(aio_context_t ctx_id, long nr, |
122 | struct iocb __user * __user *iocbpp, | 129 | struct iocb __user * __user *iocbpp, |
123 | bool compat) { return 0; } | 130 | bool compat) { return 0; } |
131 | static inline void kiocb_set_cancel_fn(struct kiocb *req, | ||
132 | kiocb_cancel_fn *cancel) { } | ||
124 | #endif /* CONFIG_AIO */ | 133 | #endif /* CONFIG_AIO */ |
125 | 134 | ||
126 | static inline struct kiocb *list_kiocb(struct list_head *h) | 135 | static inline struct kiocb *list_kiocb(struct list_head *h) |