stnmrshx

Patch Race Between freeze_process() and request_firmware()

Apr 11th, 2012
60
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 4.22 KB | None | 0 0
  1. ---
  2. include/linux/kmod.h   |   21 +++++++++++++++++++--
  3. kernel/kmod.c          |   47 +++++++++++++++++++++++++++++++++++++----------
  4. kernel/power/process.c |    3 ++-
  5. 3 files changed, 58 insertions(+), 13 deletions(-)
  6.  
  7. --- a/include/linux/kmod.h
  8. +++ b/include/linux/kmod.h
  9. @@ -112,10 +112,27 @@ call_usermodehelper(char *path, char **a
  10.  
  11. extern struct ctl_table usermodehelper_table[];
  12.  
  13. +enum umh_disable_depth {
  14. +   UMH_ENABLED = 0,
  15. +   UMH_FREEZING,
  16. +   UMH_DISABLED,
  17. +};
  18. +
  19. extern void usermodehelper_init(void);
  20.  
  21. -extern int usermodehelper_disable(void);
  22. -extern void usermodehelper_enable(void);
  23. +extern int __usermodehelper_disable(enum umh_disable_depth depth);
  24. +extern void __usermodehelper_set_disable_depth(enum umh_disable_depth depth);
  25. +
  26. +static inline int usermodehelper_disable(void)
  27. +{
  28. +   return __usermodehelper_disable(UMH_DISABLED);
  29. +}
  30. +
  31. +static inline void usermodehelper_enable(void)
  32. +{
  33. +   __usermodehelper_set_disable_depth(UMH_ENABLED);
  34. +}
  35. +
  36. extern int usermodehelper_read_trylock(void);
  37. extern long usermodehelper_read_lock_wait(long timeout);
  38. extern void usermodehelper_read_unlock(void);
  39. --- a/kernel/kmod.c
  40. +++ b/kernel/kmod.c
  41. @@ -279,7 +279,7 @@ static void __call_usermodehelper(struct
  42.   * land has been frozen during a system-wide hibernation or suspend operation).
  43.   * Should always be manipulated under umhelper_sem acquired for write.
  44.   */
  45. -static int usermodehelper_disabled = 1;
  46. +static enum umh_disable_depth usermodehelper_disabled = UMH_DISABLED;
  47.  
  48. /* Number of helpers running */
  49. static atomic_t running_helpers = ATOMIC_INIT(0);
  50. @@ -304,13 +304,30 @@ static DECLARE_WAIT_QUEUE_HEAD(usermodeh
  51.  
  52. int usermodehelper_read_trylock(void)
  53. {
  54. +   DEFINE_WAIT(wait);
  55.     int ret = 0;
  56.  
  57.     down_read(&umhelper_sem);
  58. -   if (usermodehelper_disabled) {
  59. +   for (;;) {
  60. +       prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
  61. +               TASK_INTERRUPTIBLE);
  62. +       if (!usermodehelper_disabled)
  63. +           break;
  64. +
  65. +       if (usermodehelper_disabled == UMH_DISABLED)
  66. +           ret = -EAGAIN;
  67. +
  68.         up_read(&umhelper_sem);
  69. -       ret = -EAGAIN;
  70. +
  71. +       if (ret)
  72. +           break;
  73. +
  74. +       schedule();
  75. +       try_to_freeze();
  76. +
  77. +       down_read(&umhelper_sem);
  78.     }
  79. +   finish_wait(&usermodehelper_disabled_waitq, &wait);
  80.     return ret;
  81. }
  82. EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
  83. @@ -349,25 +366,35 @@ void usermodehelper_read_unlock(void)
  84. EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
  85.  
  86. /**
  87. - * usermodehelper_enable - allow new helpers to be started again
  88. + * __usermodehelper_set_disable_depth - Modify usermodehelper_disabled.
  89. + * depth: New value to assign into usermodehelper_disabled.
  90. + *
  91. + * Change the value of usermodehelper_disabled (under umhelper_sem locked for
  92. + * writing) and wakeup tasks waiting for it to change and prevent race.
  93.  */
  94. -void usermodehelper_enable(void)
  95. +void __usermodehelper_set_disable_depth(enum umh_disable_depth depth)
  96. {
  97.     down_write(&umhelper_sem);
  98. -   usermodehelper_disabled = 0;
  99. +   usermodehelper_disabled = depth;
  100.     wake_up(&usermodehelper_disabled_waitq);
  101.     up_write(&umhelper_sem);
  102. }
  103.  
  104. /**
  105. - * usermodehelper_disable - prevent new helpers from being started
  106. + * __usermodehelper_disable - Prevent new helpers from being started.
  107. + * @depth: New value to assign into usermodehelper_disabled.
  108. + *
  109. + * Set usermodehelper_disabled to @depth and wait for running helpers to exit.
  110.  */
  111. -int usermodehelper_disable(void)
  112. +int __usermodehelper_disable(enum umh_disable_depth depth)
  113. {
  114.     long retval;
  115.  
  116. +   if (!depth)
  117. +       return -EINVAL;
  118. +
  119.     down_write(&umhelper_sem);
  120. -   usermodehelper_disabled = 1;
  121. +   usermodehelper_disabled = depth;
  122.     up_write(&umhelper_sem);
  123.  
  124.     /*
  125. @@ -382,7 +409,7 @@ int usermodehelper_disable(void)
  126.     if (retval)
  127.         return 0;
  128.  
  129. -   usermodehelper_enable();
  130. +   __usermodehelper_set_disable_depth(UMH_ENABLED);
  131.     return -EAGAIN;
  132. }
  133.  
  134. --- a/kernel/power/process.c
  135. +++ b/kernel/power/process.c
  136. @@ -123,7 +123,7 @@ int freeze_processes(void)
  137. {
  138.     int error;
  139.  
  140. -   error = usermodehelper_disable();
  141. +   error = __usermodehelper_disable(UMH_FREEZING);
  142.     if (error)
  143.         return error;
  144.  
  145. @@ -135,6 +135,7 @@ int freeze_processes(void)
  146.     error = try_to_freeze_tasks(true);
  147.     if (!error) {
  148.         printk("done.");
  149. +       __usermodehelper_set_disable_depth(UMH_DISABLED);
  150.         oom_killer_disable();
  151.     }
  152.     printk("\n");
  153.  
  154.  
  155. --
Add Comment
Please, Sign In to add comment