[bug report] z3fold: use per-page spinlock

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

 



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.

   700          if (!test_bit(PAGE_HEADLESS, &page->private))
   701                  z3fold_page_unlock(zhdr);
   702          return -EAGAIN;
   703  }


regards,
dan carpenter

--
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]