Re: [bug report] z3fold: use per-page spinlock

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Dan,

On Thu, Nov 24, 2016 at 11:36 PM, Dan Carpenter
<dan.carpenter@xxxxxxxxxx> wrote:
> Hello Vitaly Wool,
>
> The patch 570931c8c567: "z3fold: use per-page spinlock" from Nov 24,
> 2016, leads to the following Smatch warning:
>
>         mm/z3fold.c:699 z3fold_reclaim_page()
>         error: double unlock 'spin_lock:&pool->lock'
>
> mm/z3fold.c
>    597  static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
>    598  {
>    599          int i, ret = 0, freechunks;
>    600          struct z3fold_header *zhdr;
>    601          struct page *page;
>    602          unsigned long first_handle = 0, middle_handle = 0, last_handle = 0;
>    603
>    604          spin_lock(&pool->lock);
>    605          if (!pool->ops || !pool->ops->evict || list_empty(&pool->lru) ||
>    606                          retries == 0) {
>    607                  spin_unlock(&pool->lock);
>    608                  return -EINVAL;
>    609          }
>    610          for (i = 0; i < retries; i++) {
>    611                  page = list_last_entry(&pool->lru, struct page, lru);
>    612                  list_del(&page->lru);
>    613
>    614                  /* Protect z3fold page against free */
>    615                  set_bit(UNDER_RECLAIM, &page->private);
>    616                  zhdr = page_address(page);
>    617                  if (!test_bit(PAGE_HEADLESS, &page->private)) {
>    618                          list_del(&zhdr->buddy);
>    619                          spin_unlock(&pool->lock);
>    620                          z3fold_page_lock(zhdr);
>    621                          /*
>    622                           * We need encode the handles before unlocking, since
>    623                           * we can race with free that will set
>    624                           * (first|last)_chunks to 0
>    625                           */
>    626                          first_handle = 0;
>    627                          last_handle = 0;
>    628                          middle_handle = 0;
>    629                          if (zhdr->first_chunks)
>    630                                  first_handle = encode_handle(zhdr, FIRST);
>    631                          if (zhdr->middle_chunks)
>    632                                  middle_handle = encode_handle(zhdr, MIDDLE);
>    633                          if (zhdr->last_chunks)
>    634                                  last_handle = encode_handle(zhdr, LAST);
>    635                          z3fold_page_unlock(zhdr);
>    636                  } else {
>    637                          first_handle = encode_handle(zhdr, HEADLESS);
>    638                          last_handle = middle_handle = 0;
>    639                          spin_unlock(&pool->lock);
>    640                  }
>    641
>    642                  /* Issue the eviction callback(s) */
>    643                  if (middle_handle) {
>    644                          ret = pool->ops->evict(pool, middle_handle);
>    645                          if (ret)
>    646                                  goto next;
>    647                  }
>    648                  if (first_handle) {
>    649                          ret = pool->ops->evict(pool, first_handle);
>    650                          if (ret)
>    651                                  goto next;
>    652                  }
>    653                  if (last_handle) {
>    654                          ret = pool->ops->evict(pool, last_handle);
>    655                          if (ret)
>    656                                  goto next;
>
> "ret" is non-zero so we do a little bunny hop to the next line.  Small
> jump deserves a small pun.
>
>    657                  }
>    658  next:
>
> Originally we took the lock here, but now we've moved it into the if
> statement branches.
>
>    659                  if (!test_bit(PAGE_HEADLESS, &page->private))
>    660                          z3fold_page_lock(zhdr);
>    661                  clear_bit(UNDER_RECLAIM, &page->private);
>    662                  if ((test_bit(PAGE_HEADLESS, &page->private) && ret == 0) ||
>    663                      (zhdr->first_chunks == 0 && zhdr->last_chunks == 0 &&
>    664                       zhdr->middle_chunks == 0)) {
>    665                          /*
>    666                           * All buddies are now free, free the z3fold page and
>    667                           * return success.
>    668                           */
>    669                          clear_bit(PAGE_HEADLESS, &page->private);
>    670                          if (!test_bit(PAGE_HEADLESS, &page->private))
>    671                                  z3fold_page_unlock(zhdr);
>    672                          free_z3fold_page(zhdr);
>    673                          atomic64_dec(&pool->pages_nr);
>    674                          return 0;
>    675                  }  else if (!test_bit(PAGE_HEADLESS, &page->private)) {
>    676                          if (zhdr->first_chunks != 0 &&
>    677                              zhdr->last_chunks != 0 &&
>    678                              zhdr->middle_chunks != 0) {
>    679                                  /* Full, add to buddied list */
>    680                                  spin_lock(&pool->lock);
>    681                                  list_add(&zhdr->buddy, &pool->buddied);
>    682                          } else {
>    683                                  int compacted = z3fold_compact_page(zhdr);
>    684                                  /* add to unbuddied list */
>    685                                  spin_lock(&pool->lock);
>    686                                  freechunks = num_free_chunks(zhdr);
>    687                                  if (compacted)
>    688                                          list_add(&zhdr->buddy,
>    689                                                  &pool->unbuddied[freechunks]);
>    690                                  else
>    691                                          list_add_tail(&zhdr->buddy,
>    692                                                  &pool->unbuddied[freechunks]);
>    693                          }
>    694                  }
>
> We don't take the lock if PAGE_HEADLESS is set but ret is non-zero.
>
>    695
>    696                  /* add to beginning of LRU */
>    697                  list_add(&page->lru, &pool->lru);
>    698          }
>    699          spin_unlock(&pool->lock);
>
> Leading to a double unlock.

thanks for the report, will upload the fix shortly.

~vitaly

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@xxxxxxxxx.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@xxxxxxxxx";> email@xxxxxxxxx </a>



[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]