diff options
Diffstat (limited to 'fs/inotify_user.c')
| -rw-r--r-- | fs/inotify_user.c | 27 | 
1 files changed, 20 insertions, 7 deletions
| diff --git a/fs/inotify_user.c b/fs/inotify_user.c index 60249429a253..d85c7d931cdf 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c | |||
| @@ -323,7 +323,7 @@ out: | |||
| 323 | } | 323 | } | 
| 324 | 324 | ||
| 325 | /* | 325 | /* | 
| 326 | * remove_kevent - cleans up and ultimately frees the given kevent | 326 | * remove_kevent - cleans up the given kevent | 
| 327 | * | 327 | * | 
| 328 | * Caller must hold dev->ev_mutex. | 328 | * Caller must hold dev->ev_mutex. | 
| 329 | */ | 329 | */ | 
| @@ -334,7 +334,13 @@ static void remove_kevent(struct inotify_device *dev, | |||
| 334 | 334 | ||
| 335 | dev->event_count--; | 335 | dev->event_count--; | 
| 336 | dev->queue_size -= sizeof(struct inotify_event) + kevent->event.len; | 336 | dev->queue_size -= sizeof(struct inotify_event) + kevent->event.len; | 
| 337 | } | ||
| 337 | 338 | ||
| 339 | /* | ||
| 340 | * free_kevent - frees the given kevent. | ||
| 341 | */ | ||
| 342 | static void free_kevent(struct inotify_kernel_event *kevent) | ||
| 343 | { | ||
| 338 | kfree(kevent->name); | 344 | kfree(kevent->name); | 
| 339 | kmem_cache_free(event_cachep, kevent); | 345 | kmem_cache_free(event_cachep, kevent); | 
| 340 | } | 346 | } | 
| @@ -350,6 +356,7 @@ static void inotify_dev_event_dequeue(struct inotify_device *dev) | |||
| 350 | struct inotify_kernel_event *kevent; | 356 | struct inotify_kernel_event *kevent; | 
| 351 | kevent = inotify_dev_get_event(dev); | 357 | kevent = inotify_dev_get_event(dev); | 
| 352 | remove_kevent(dev, kevent); | 358 | remove_kevent(dev, kevent); | 
| 359 | free_kevent(kevent); | ||
| 353 | } | 360 | } | 
| 354 | } | 361 | } | 
| 355 | 362 | ||
| @@ -433,17 +440,15 @@ static ssize_t inotify_read(struct file *file, char __user *buf, | |||
| 433 | dev = file->private_data; | 440 | dev = file->private_data; | 
| 434 | 441 | ||
| 435 | while (1) { | 442 | while (1) { | 
| 436 | int events; | ||
| 437 | 443 | ||
| 438 | prepare_to_wait(&dev->wq, &wait, TASK_INTERRUPTIBLE); | 444 | prepare_to_wait(&dev->wq, &wait, TASK_INTERRUPTIBLE); | 
| 439 | 445 | ||
| 440 | mutex_lock(&dev->ev_mutex); | 446 | mutex_lock(&dev->ev_mutex); | 
| 441 | events = !list_empty(&dev->events); | 447 | if (!list_empty(&dev->events)) { | 
| 442 | mutex_unlock(&dev->ev_mutex); | ||
| 443 | if (events) { | ||
| 444 | ret = 0; | 448 | ret = 0; | 
| 445 | break; | 449 | break; | 
| 446 | } | 450 | } | 
| 451 | mutex_unlock(&dev->ev_mutex); | ||
| 447 | 452 | ||
| 448 | if (file->f_flags & O_NONBLOCK) { | 453 | if (file->f_flags & O_NONBLOCK) { | 
| 449 | ret = -EAGAIN; | 454 | ret = -EAGAIN; | 
| @@ -462,7 +467,6 @@ static ssize_t inotify_read(struct file *file, char __user *buf, | |||
| 462 | if (ret) | 467 | if (ret) | 
| 463 | return ret; | 468 | return ret; | 
| 464 | 469 | ||
| 465 | mutex_lock(&dev->ev_mutex); | ||
| 466 | while (1) { | 470 | while (1) { | 
| 467 | struct inotify_kernel_event *kevent; | 471 | struct inotify_kernel_event *kevent; | 
| 468 | 472 | ||
| @@ -481,6 +485,13 @@ static ssize_t inotify_read(struct file *file, char __user *buf, | |||
| 481 | } | 485 | } | 
| 482 | break; | 486 | break; | 
| 483 | } | 487 | } | 
| 488 | remove_kevent(dev, kevent); | ||
| 489 | |||
| 490 | /* | ||
| 491 | * Must perform the copy_to_user outside the mutex in order | ||
| 492 | * to avoid a lock order reversal with mmap_sem. | ||
| 493 | */ | ||
| 494 | mutex_unlock(&dev->ev_mutex); | ||
| 484 | 495 | ||
| 485 | if (copy_to_user(buf, &kevent->event, event_size)) { | 496 | if (copy_to_user(buf, &kevent->event, event_size)) { | 
| 486 | ret = -EFAULT; | 497 | ret = -EFAULT; | 
| @@ -498,7 +509,9 @@ static ssize_t inotify_read(struct file *file, char __user *buf, | |||
| 498 | count -= kevent->event.len; | 509 | count -= kevent->event.len; | 
| 499 | } | 510 | } | 
| 500 | 511 | ||
| 501 | remove_kevent(dev, kevent); | 512 | free_kevent(kevent); | 
| 513 | |||
| 514 | mutex_lock(&dev->ev_mutex); | ||
| 502 | } | 515 | } | 
| 503 | mutex_unlock(&dev->ev_mutex); | 516 | mutex_unlock(&dev->ev_mutex); | 
| 504 | 517 | ||
