Received: by 2002:a5b:505:0:0:0:0:0 with SMTP id o5csp24722ybp; Thu, 3 Oct 2019 09:39:58 -0700 (PDT) X-Google-Smtp-Source: APXvYqwPCEgWzQziqFAfVWXwYeRPGPO+ZZR6aX2QYhZbGwyxnbOENUn6L/Y0+jhiS+KA9tLmLF/A X-Received: by 2002:a05:6402:184d:: with SMTP id v13mr10800397edy.56.1570120798112; Thu, 03 Oct 2019 09:39:58 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1570120798; cv=none; d=google.com; s=arc-20160816; b=En7bp2dQ9klxAj9ngcevj9NuMo42Ql1oXCHdhSk/lOH0hmvgvM3UzB07LiziuIrJ+L xIoQUJS89NfG2Nfp9o19ayy8EyVijxmI8WD4h1rumnnDPoPXoISTzITmQubjvS/gDkij bN/tQcP294rM1VD7+vJCp1U6mYgeAJdDtLlTvOmMj3G8rFFbJnqLdA3MoQkh79zMYFRn NPtmvlnI7+t6T2QvlKmcBcBxggk7XFqeFN5WAAXRDIKSlPJgSdikCg3H+WG6k1uh9VKq T3NBmjgsPTfMrI1z+jxj8qElpMe5oyaSvfhGcZTkp/aT/N/kO1YnnuiK7QqtKAO9SCa/ y78w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=M7CTinECH7GmdlQviowMQxTKeXAV0lNAwSoOWdAsApQ=; b=Tr4WeFq5MHnpXdeIItafeakeqd23w/bNgqE/oWGEu1UpVs29d6C1P5zY7t+Bbn05GE h6J7MMzkIgApne+xTJyQ2ifnWF9x1w3W3XOfRYjdjltfEkMZ651+6HlKXArsRQ1pECjI TmHIEJxXz1+dzYbjiSge0r//ftlKXmJo2VCvn9x7XBHKuIjOwZyZnp3XAlqRuUCw3sxM qAD5bTCw41I7czqRgCG8rL5Au1U82kyYGfjynlGS3OaQsOz/cPso6jGrGIi3esqcGaMS WfibGZMOJPm4ikmpvcG9FYmfk8hegRqILCcCnQ5oxqhyDrDkor4OjR8pTj9WBXnf735S BnWw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=eqFm0teo; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l21si1831498edc.112.2019.10.03.09.39.32; Thu, 03 Oct 2019 09:39:58 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=eqFm0teo; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2391437AbfJCQf4 (ORCPT + 99 others); Thu, 3 Oct 2019 12:35:56 -0400 Received: from mail.kernel.org ([198.145.29.99]:44914 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389429AbfJCQfx (ORCPT ); Thu, 3 Oct 2019 12:35:53 -0400 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id C8FD72070B; Thu, 3 Oct 2019 16:35:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1570120551; bh=Q2csLGPfbPef3CuRi72M6y/BVZlrVtVLVt5CDkrmq8Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eqFm0teokzezRZnr2XECQVrE+PXWQD7kjpmvOHxxx5nlnJDcON6pQizFeNKR95zDQ BNU908FL137RkErMiI9YH50KcrVl3IR3DUHmnNwIpz/lEBlL52fM0Jihth981wLdph 7ovCq8qlSxZqR5cAqWZeXye03i0BQ0zKNV9xcj1U= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Vitaly Wool , Markus Linnala , Chris Murphy , Agustin DallAlba , "Maciej S. Szmigiero" , Shakeel Butt , Henry Burns , Andrew Morton , Linus Torvalds Subject: [PATCH 5.2 264/313] z3fold: fix retry mechanism in page reclaim Date: Thu, 3 Oct 2019 17:54:02 +0200 Message-Id: <20191003154559.044870572@linuxfoundation.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191003154533.590915454@linuxfoundation.org> References: <20191003154533.590915454@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Vitaly Wool commit 3f9d2b5766aea06042630ac60b7316fd0cebf06f upstream. z3fold_page_reclaim()'s retry mechanism is broken: on a second iteration it will have zhdr from the first one so that zhdr is no longer in line with struct page. That leads to crashes when the system is stressed. Fix that by moving zhdr assignment up. While at it, protect against using already freed handles by using own local slots structure in z3fold_page_reclaim(). Link: http://lkml.kernel.org/r/20190908162919.830388dc7404d1e2c80f4095@gmail.com Signed-off-by: Vitaly Wool Reported-by: Markus Linnala Reported-by: Chris Murphy Reported-by: Agustin Dall'Alba Cc: "Maciej S. Szmigiero" Cc: Shakeel Butt Cc: Henry Burns Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/z3fold.c | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) --- a/mm/z3fold.c +++ b/mm/z3fold.c @@ -368,9 +368,10 @@ static inline int __idx(struct z3fold_he * Encodes the handle of a particular buddy within a z3fold page * Pool lock should be held as this function accesses first_num */ -static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud) +static unsigned long __encode_handle(struct z3fold_header *zhdr, + struct z3fold_buddy_slots *slots, + enum buddy bud) { - struct z3fold_buddy_slots *slots; unsigned long h = (unsigned long)zhdr; int idx = 0; @@ -387,11 +388,15 @@ static unsigned long encode_handle(struc if (bud == LAST) h |= (zhdr->last_chunks << BUDDY_SHIFT); - slots = zhdr->slots; slots->slot[idx] = h; return (unsigned long)&slots->slot[idx]; } +static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud) +{ + return __encode_handle(zhdr, zhdr->slots, bud); +} + /* Returns the z3fold page where a given handle is stored */ static inline struct z3fold_header *handle_to_z3fold_header(unsigned long h) { @@ -626,6 +631,7 @@ static void do_compact_page(struct z3fol } if (unlikely(PageIsolated(page) || + test_bit(PAGE_CLAIMED, &page->private) || test_bit(PAGE_STALE, &page->private))) { z3fold_page_unlock(zhdr); return; @@ -1102,6 +1108,7 @@ static int z3fold_reclaim_page(struct z3 struct z3fold_header *zhdr = NULL; struct page *page = NULL; struct list_head *pos; + struct z3fold_buddy_slots slots; unsigned long first_handle = 0, middle_handle = 0, last_handle = 0; spin_lock(&pool->lock); @@ -1120,16 +1127,22 @@ static int z3fold_reclaim_page(struct z3 /* this bit could have been set by free, in which case * we pass over to the next page in the pool. */ - if (test_and_set_bit(PAGE_CLAIMED, &page->private)) + if (test_and_set_bit(PAGE_CLAIMED, &page->private)) { + page = NULL; continue; + } - if (unlikely(PageIsolated(page))) + if (unlikely(PageIsolated(page))) { + clear_bit(PAGE_CLAIMED, &page->private); + page = NULL; continue; + } + zhdr = page_address(page); if (test_bit(PAGE_HEADLESS, &page->private)) break; - zhdr = page_address(page); if (!z3fold_page_trylock(zhdr)) { + clear_bit(PAGE_CLAIMED, &page->private); zhdr = NULL; continue; /* can't evict at this point */ } @@ -1147,26 +1160,30 @@ static int z3fold_reclaim_page(struct z3 if (!test_bit(PAGE_HEADLESS, &page->private)) { /* - * We need encode the handles before unlocking, since - * we can race with free that will set - * (first|last)_chunks to 0 + * We need encode the handles before unlocking, and + * use our local slots structure because z3fold_free + * can zero out zhdr->slots and we can't do much + * about that */ first_handle = 0; last_handle = 0; middle_handle = 0; if (zhdr->first_chunks) - first_handle = encode_handle(zhdr, FIRST); + first_handle = __encode_handle(zhdr, &slots, + FIRST); if (zhdr->middle_chunks) - middle_handle = encode_handle(zhdr, MIDDLE); + middle_handle = __encode_handle(zhdr, &slots, + MIDDLE); if (zhdr->last_chunks) - last_handle = encode_handle(zhdr, LAST); + last_handle = __encode_handle(zhdr, &slots, + LAST); /* * it's safe to unlock here because we hold a * reference to this page */ z3fold_page_unlock(zhdr); } else { - first_handle = encode_handle(zhdr, HEADLESS); + first_handle = __encode_handle(zhdr, &slots, HEADLESS); last_handle = middle_handle = 0; } @@ -1196,9 +1213,9 @@ next: spin_lock(&pool->lock); list_add(&page->lru, &pool->lru); spin_unlock(&pool->lock); + clear_bit(PAGE_CLAIMED, &page->private); } else { z3fold_page_lock(zhdr); - clear_bit(PAGE_CLAIMED, &page->private); if (kref_put(&zhdr->refcount, release_z3fold_page_locked)) { atomic64_dec(&pool->pages_nr); @@ -1213,6 +1230,7 @@ next: list_add(&page->lru, &pool->lru); spin_unlock(&pool->lock); z3fold_page_unlock(zhdr); + clear_bit(PAGE_CLAIMED, &page->private); } /* We started off locked to we need to lock the pool back */ @@ -1317,7 +1335,8 @@ static bool z3fold_page_isolate(struct p VM_BUG_ON_PAGE(!PageMovable(page), page); VM_BUG_ON_PAGE(PageIsolated(page), page); - if (test_bit(PAGE_HEADLESS, &page->private)) + if (test_bit(PAGE_HEADLESS, &page->private) || + test_bit(PAGE_CLAIMED, &page->private)) return false; zhdr = page_address(page);