)]}'
{
  "commit": "8603e1b30027f943cc9c1eef2b291d42c3347af1",
  "tree": "80fc225f10d0d6cf46a3cfa3fe3ddd6d77e8aa1e",
  "parents": [
    "c517d838eb7d07bbe9507871fab3931deccff539"
  ],
  "author": {
    "name": "Tejun Heo",
    "email": "tj@kernel.org",
    "time": "Thu Mar 05 08:04:13 2015 -0500"
  },
  "committer": {
    "name": "Tejun Heo",
    "email": "tj@kernel.org",
    "time": "Thu Mar 05 08:04:13 2015 -0500"
  },
  "message": "workqueue: fix hang involving racing cancel[_delayed]_work_sync()\u0027s for PREEMPT_NONE\n\ncancel[_delayed]_work_sync() are implemented using\n__cancel_work_timer() which grabs the PENDING bit using\ntry_to_grab_pending() and then flushes the work item with PENDING set\nto prevent the on-going execution of the work item from requeueing\nitself.\n\ntry_to_grab_pending() can always grab PENDING bit without blocking\nexcept when someone else is doing the above flushing during\ncancelation.  In that case, try_to_grab_pending() returns -ENOENT.  In\nthis case, __cancel_work_timer() currently invokes flush_work().  The\nassumption is that the completion of the work item is what the other\ncanceling task would be waiting for too and thus waiting for the same\ncondition and retrying should allow forward progress without excessive\nbusy looping\n\nUnfortunately, this doesn\u0027t work if preemption is disabled or the\nlatter task has real time priority.  Let\u0027s say task A just got woken\nup from flush_work() by the completion of the target work item.  If,\nbefore task A starts executing, task B gets scheduled and invokes\n__cancel_work_timer() on the same work item, its try_to_grab_pending()\nwill return -ENOENT as the work item is still being canceled by task A\nand flush_work() will also immediately return false as the work item\nis no longer executing.  This puts task B in a busy loop possibly\npreventing task A from executing and clearing the canceling state on\nthe work item leading to a hang.\n\ntask A\t\t\ttask B\t\t\tworker\n\n\t\t\t\t\t\texecuting work\n__cancel_work_timer()\n  try_to_grab_pending()\n  set work CANCELING\n  flush_work()\n    block for work completion\n\t\t\t\t\t\tcompletion, wakes up A\n\t\t\t__cancel_work_timer()\n\t\t\twhile (forever) {\n\t\t\t  try_to_grab_pending()\n\t\t\t    -ENOENT as work is being canceled\n\t\t\t  flush_work()\n\t\t\t    false as work is no longer executing\n\t\t\t}\n\nThis patch removes the possible hang by updating __cancel_work_timer()\nto explicitly wait for clearing of CANCELING rather than invoking\nflush_work() after try_to_grab_pending() fails with -ENOENT.\n\nLink: http://lkml.kernel.org/g/20150206171156.GA8942@axis.com\n\nv3: bit_waitqueue() can\u0027t be used for work items defined in vmalloc\n    area.  Switched to custom wake function which matches the target\n    work item and exclusive wait and wakeup.\n\nv2: v1 used wake_up() on bit_waitqueue() which leads to NULL deref if\n    the target bit waitqueue has wait_bit_queue\u0027s on it.  Use\n    DEFINE_WAIT_BIT() and __wake_up_bit() instead.  Reported by Tomeu\n    Vizoso.\n\nSigned-off-by: Tejun Heo \u003ctj@kernel.org\u003e\nReported-by: Rabin Vincent \u003crabin.vincent@axis.com\u003e\nCc: Tomeu Vizoso \u003ctomeu.vizoso@gmail.com\u003e\nCc: stable@vger.kernel.org\nTested-by: Jesper Nilsson \u003cjesper.nilsson@axis.com\u003e\nTested-by: Rabin Vincent \u003crabin.vincent@axis.com\u003e\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "74db135f99571e37f61e0aecc34d7b5ddba66756",
      "old_mode": 33188,
      "old_path": "include/linux/workqueue.h",
      "new_id": "f597846ff605cccaaf36d3cc4e6d603b630af156",
      "new_mode": 33188,
      "new_path": "include/linux/workqueue.h"
    },
    {
      "type": "modify",
      "old_id": "f2884939479109f349b6291a82ee4cc990aa1c32",
      "old_mode": 33188,
      "old_path": "kernel/workqueue.c",
      "new_id": "41ff75b478c60b443cd80626351b1e3f3030f94b",
      "new_mode": 33188,
      "new_path": "kernel/workqueue.c"
    }
  ]
}
