diff options
| -rw-r--r-- | fs/aio.c | 31 | ||||
| -rw-r--r-- | include/linux/aio.h | 5 | ||||
| -rw-r--r-- | kernel/sysctl.c | 4 |
3 files changed, 26 insertions, 14 deletions
| @@ -42,8 +42,9 @@ | |||
| 42 | #endif | 42 | #endif |
| 43 | 43 | ||
| 44 | /*------ sysctl variables----*/ | 44 | /*------ sysctl variables----*/ |
| 45 | atomic_t aio_nr = ATOMIC_INIT(0); /* current system wide number of aio requests */ | 45 | static DEFINE_SPINLOCK(aio_nr_lock); |
| 46 | unsigned aio_max_nr = 0x10000; /* system wide maximum number of aio requests */ | 46 | unsigned long aio_nr; /* current system wide number of aio requests */ |
| 47 | unsigned long aio_max_nr = 0x10000; /* system wide maximum number of aio requests */ | ||
| 47 | /*----end sysctl variables---*/ | 48 | /*----end sysctl variables---*/ |
| 48 | 49 | ||
| 49 | static kmem_cache_t *kiocb_cachep; | 50 | static kmem_cache_t *kiocb_cachep; |
| @@ -208,7 +209,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) | |||
| 208 | return ERR_PTR(-EINVAL); | 209 | return ERR_PTR(-EINVAL); |
| 209 | } | 210 | } |
| 210 | 211 | ||
| 211 | if (nr_events > aio_max_nr) | 212 | if ((unsigned long)nr_events > aio_max_nr) |
| 212 | return ERR_PTR(-EAGAIN); | 213 | return ERR_PTR(-EAGAIN); |
| 213 | 214 | ||
| 214 | ctx = kmem_cache_alloc(kioctx_cachep, GFP_KERNEL); | 215 | ctx = kmem_cache_alloc(kioctx_cachep, GFP_KERNEL); |
| @@ -233,8 +234,14 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) | |||
| 233 | goto out_freectx; | 234 | goto out_freectx; |
| 234 | 235 | ||
| 235 | /* limit the number of system wide aios */ | 236 | /* limit the number of system wide aios */ |
| 236 | atomic_add(ctx->max_reqs, &aio_nr); /* undone by __put_ioctx */ | 237 | spin_lock(&aio_nr_lock); |
| 237 | if (unlikely(atomic_read(&aio_nr) > aio_max_nr)) | 238 | if (aio_nr + ctx->max_reqs > aio_max_nr || |
| 239 | aio_nr + ctx->max_reqs < aio_nr) | ||
| 240 | ctx->max_reqs = 0; | ||
| 241 | else | ||
| 242 | aio_nr += ctx->max_reqs; | ||
| 243 | spin_unlock(&aio_nr_lock); | ||
| 244 | if (ctx->max_reqs == 0) | ||
| 238 | goto out_cleanup; | 245 | goto out_cleanup; |
| 239 | 246 | ||
| 240 | /* now link into global list. kludge. FIXME */ | 247 | /* now link into global list. kludge. FIXME */ |
| @@ -248,8 +255,6 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) | |||
| 248 | return ctx; | 255 | return ctx; |
| 249 | 256 | ||
| 250 | out_cleanup: | 257 | out_cleanup: |
| 251 | atomic_sub(ctx->max_reqs, &aio_nr); | ||
| 252 | ctx->max_reqs = 0; /* prevent __put_ioctx from sub'ing aio_nr */ | ||
| 253 | __put_ioctx(ctx); | 258 | __put_ioctx(ctx); |
| 254 | return ERR_PTR(-EAGAIN); | 259 | return ERR_PTR(-EAGAIN); |
| 255 | 260 | ||
| @@ -374,7 +379,12 @@ void fastcall __put_ioctx(struct kioctx *ctx) | |||
| 374 | pr_debug("__put_ioctx: freeing %p\n", ctx); | 379 | pr_debug("__put_ioctx: freeing %p\n", ctx); |
| 375 | kmem_cache_free(kioctx_cachep, ctx); | 380 | kmem_cache_free(kioctx_cachep, ctx); |
| 376 | 381 | ||
| 377 | atomic_sub(nr_events, &aio_nr); | 382 | if (nr_events) { |
| 383 | spin_lock(&aio_nr_lock); | ||
| 384 | BUG_ON(aio_nr - nr_events > aio_nr); | ||
| 385 | aio_nr -= nr_events; | ||
| 386 | spin_unlock(&aio_nr_lock); | ||
| 387 | } | ||
| 378 | } | 388 | } |
| 379 | 389 | ||
| 380 | /* aio_get_req | 390 | /* aio_get_req |
| @@ -1258,8 +1268,9 @@ asmlinkage long sys_io_setup(unsigned nr_events, aio_context_t __user *ctxp) | |||
| 1258 | goto out; | 1268 | goto out; |
| 1259 | 1269 | ||
| 1260 | ret = -EINVAL; | 1270 | ret = -EINVAL; |
| 1261 | if (unlikely(ctx || (int)nr_events <= 0)) { | 1271 | if (unlikely(ctx || nr_events == 0)) { |
| 1262 | pr_debug("EINVAL: io_setup: ctx or nr_events > max\n"); | 1272 | pr_debug("EINVAL: io_setup: ctx %lu nr_events %u\n", |
| 1273 | ctx, nr_events); | ||
| 1263 | goto out; | 1274 | goto out; |
| 1264 | } | 1275 | } |
| 1265 | 1276 | ||
diff --git a/include/linux/aio.h b/include/linux/aio.h index 0decf66117c1..403d71dcb7c8 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h | |||
| @@ -183,6 +183,7 @@ struct kioctx { | |||
| 183 | struct list_head active_reqs; /* used for cancellation */ | 183 | struct list_head active_reqs; /* used for cancellation */ |
| 184 | struct list_head run_list; /* used for kicked reqs */ | 184 | struct list_head run_list; /* used for kicked reqs */ |
| 185 | 185 | ||
| 186 | /* sys_io_setup currently limits this to an unsigned int */ | ||
| 186 | unsigned max_reqs; | 187 | unsigned max_reqs; |
| 187 | 188 | ||
| 188 | struct aio_ring_info ring_info; | 189 | struct aio_ring_info ring_info; |
| @@ -234,7 +235,7 @@ static inline struct kiocb *list_kiocb(struct list_head *h) | |||
| 234 | } | 235 | } |
| 235 | 236 | ||
| 236 | /* for sysctl: */ | 237 | /* for sysctl: */ |
| 237 | extern atomic_t aio_nr; | 238 | extern unsigned long aio_nr; |
| 238 | extern unsigned aio_max_nr; | 239 | extern unsigned long aio_max_nr; |
| 239 | 240 | ||
| 240 | #endif /* __LINUX__AIO_H */ | 241 | #endif /* __LINUX__AIO_H */ |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 8e56e2495542..e1351200ce85 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -952,7 +952,7 @@ static ctl_table fs_table[] = { | |||
| 952 | .data = &aio_nr, | 952 | .data = &aio_nr, |
| 953 | .maxlen = sizeof(aio_nr), | 953 | .maxlen = sizeof(aio_nr), |
| 954 | .mode = 0444, | 954 | .mode = 0444, |
| 955 | .proc_handler = &proc_dointvec, | 955 | .proc_handler = &proc_doulongvec_minmax, |
| 956 | }, | 956 | }, |
| 957 | { | 957 | { |
| 958 | .ctl_name = FS_AIO_MAX_NR, | 958 | .ctl_name = FS_AIO_MAX_NR, |
| @@ -960,7 +960,7 @@ static ctl_table fs_table[] = { | |||
| 960 | .data = &aio_max_nr, | 960 | .data = &aio_max_nr, |
| 961 | .maxlen = sizeof(aio_max_nr), | 961 | .maxlen = sizeof(aio_max_nr), |
| 962 | .mode = 0644, | 962 | .mode = 0644, |
| 963 | .proc_handler = &proc_dointvec, | 963 | .proc_handler = &proc_doulongvec_minmax, |
| 964 | }, | 964 | }, |
| 965 | #ifdef CONFIG_INOTIFY | 965 | #ifdef CONFIG_INOTIFY |
| 966 | { | 966 | { |
