diff options
| -rw-r--r-- | xlators/cluster/ec/src/ec-common.c | 16 | 
1 files changed, 14 insertions, 2 deletions
diff --git a/xlators/cluster/ec/src/ec-common.c b/xlators/cluster/ec/src/ec-common.c index 894d2f552f3..fbdad86950a 100644 --- a/xlators/cluster/ec/src/ec-common.c +++ b/xlators/cluster/ec/src/ec-common.c @@ -321,7 +321,7 @@ void ec_resume_parent(ec_fop_data_t * fop, int32_t error)  void ec_complete(ec_fop_data_t * fop)  {      ec_cbk_data_t * cbk = NULL; -    int32_t resume = 0; +    int32_t resume = 0, update = 0;      LOCK(&fop->lock); @@ -335,7 +335,7 @@ void ec_complete(ec_fop_data_t * fop)                      ((cbk->op_ret >= 0) || (cbk->op_errno != ENOTCONN))) {                      fop->answer = cbk; -                    ec_update_bad(fop, cbk->mask); +                    update = 1;                  }              } @@ -349,6 +349,14 @@ void ec_complete(ec_fop_data_t * fop)      UNLOCK(&fop->lock); +    /* ec_update_bad() locks inode->lock. This may cause deadlocks with +       fop->lock when used in another order. Since ec_update_bad() will not +       be called more than once for each fop, it can be called from outside +       the fop->lock locked region. */ +    if (update) { +        ec_update_bad(fop, cbk->mask); +    } +      if (resume)      {          ec_resume(fop, 0); @@ -861,9 +869,13 @@ void ec_lock(ec_fop_data_t * fop)              list_add_tail(&fop->locks[fop->locked].wait_list, &lock->waiting); +            LOCK(&fop->lock); +              fop->jobs++;              fop->refs++; +            UNLOCK(&fop->lock); +              UNLOCK(&lock->loc.inode->lock);              break;  | 
