+++ /dev/null
-From 303681d5d538d81b5e23754515202b5b9febd2e9 Mon Sep 17 00:00:00 2001
-From: Keno Fischer <keno@juliacomputing.com>
-Date: Tue, 24 Jan 2017 15:17:48 -0800
-Subject: mm/huge_memory.c: respect FOLL_FORCE/FOLL_COW for thp
-
-From: Keno Fischer <keno@juliacomputing.com>
-
-commit 8310d48b125d19fcd9521d83b8293e63eb1646aa upstream.
-
-In commit 19be0eaffa3a ("mm: remove gup_flags FOLL_WRITE games from
-__get_user_pages()"), the mm code was changed from unsetting FOLL_WRITE
-after a COW was resolved to setting the (newly introduced) FOLL_COW
-instead. Simultaneously, the check in gup.c was updated to still allow
-writes with FOLL_FORCE set if FOLL_COW had also been set.
-
-However, a similar check in huge_memory.c was forgotten. As a result,
-remote memory writes to ro regions of memory backed by transparent huge
-pages cause an infinite loop in the kernel (handle_mm_fault sets
-FOLL_COW and returns 0 causing a retry, but follow_trans_huge_pmd bails
-out immidiately because `(flags & FOLL_WRITE) && !pmd_write(*pmd)` is
-true.
-
-While in this state the process is stil SIGKILLable, but little else
-works (e.g. no ptrace attach, no other signals). This is easily
-reproduced with the following code (assuming thp are set to always):
-
- #include <assert.h>
- #include <fcntl.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <string.h>
- #include <sys/mman.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <unistd.h>
-
- #define TEST_SIZE 5 * 1024 * 1024
-
- int main(void) {
- int status;
- pid_t child;
- int fd = open("/proc/self/mem", O_RDWR);
- void *addr = mmap(NULL, TEST_SIZE, PROT_READ,
- MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
- assert(addr != MAP_FAILED);
- pid_t parent_pid = getpid();
- if ((child = fork()) == 0) {
- void *addr2 = mmap(NULL, TEST_SIZE, PROT_READ | PROT_WRITE,
- MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
- assert(addr2 != MAP_FAILED);
- memset(addr2, 'a', TEST_SIZE);
- pwrite(fd, addr2, TEST_SIZE, (uintptr_t)addr);
- return 0;
- }
- assert(child == waitpid(child, &status, 0));
- assert(WIFEXITED(status) && WEXITSTATUS(status) == 0);
- return 0;
- }
-
-Fix this by updating follow_trans_huge_pmd in huge_memory.c analogously
-to the update in gup.c in the original commit. The same pattern exists
-in follow_devmap_pmd. However, we should not be able to reach that
-check with FOLL_COW set, so add WARN_ONCE to make sure we notice if we
-ever do.
-
-[akpm@linux-foundation.org: coding-style fixes]
-Link: http://lkml.kernel.org/r/20170106015025.GA38411@juliacomputing.com
-Signed-off-by: Keno Fischer <keno@juliacomputing.com>
-Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
-Cc: Greg Thelen <gthelen@google.com>
-Cc: Nicholas Piggin <npiggin@gmail.com>
-Cc: Willy Tarreau <w@1wt.eu>
-Cc: Oleg Nesterov <oleg@redhat.com>
-Cc: Kees Cook <keescook@chromium.org>
-Cc: Andy Lutomirski <luto@kernel.org>
-Cc: Michal Hocko <mhocko@suse.com>
-Cc: Hugh Dickins <hughd@google.com>
-Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
-Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-[bwh: Backported to 3.16:
- - Drop change to follow_devmap_pmd()
- - pmd_dirty() is not available; check the page flags as in older
- backports of can_follow_write_pte()
- - Adjust context]
-Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- mm/huge_memory.c | 19 ++++++++++++++++---
- 1 file changed, 16 insertions(+), 3 deletions(-)
-
---- a/mm/huge_memory.c
-+++ b/mm/huge_memory.c
-@@ -1269,6 +1269,18 @@ out_unlock:
- return ret;
- }
-
-+/*
-+ * FOLL_FORCE can write to even unwritable pmd's, but only
-+ * after we've gone through a COW cycle and they are dirty.
-+ */
-+static inline bool can_follow_write_pmd(pmd_t pmd, struct page *page,
-+ unsigned int flags)
-+{
-+ return pmd_write(pmd) ||
-+ ((flags & FOLL_FORCE) && (flags & FOLL_COW) &&
-+ page && PageAnon(page));
-+}
-+
- struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
- unsigned long addr,
- pmd_t *pmd,
-@@ -1279,9 +1291,6 @@ struct page *follow_trans_huge_pmd(struc
-
- assert_spin_locked(pmd_lockptr(mm, pmd));
-
-- if (flags & FOLL_WRITE && !pmd_write(*pmd))
-- goto out;
--
- /* Avoid dumping huge zero page */
- if ((flags & FOLL_DUMP) && is_huge_zero_pmd(*pmd))
- return ERR_PTR(-EFAULT);
-@@ -1292,6 +1301,10 @@ struct page *follow_trans_huge_pmd(struc
-
- page = pmd_page(*pmd);
- VM_BUG_ON_PAGE(!PageHead(page), page);
-+
-+ if (flags & FOLL_WRITE && !can_follow_write_pmd(*pmd, page, flags))
-+ goto out;
-+
- if (flags & FOLL_TOUCH) {
- pmd_t _pmd;
- /*
+++ /dev/null
-From foo@baz Mon Apr 10 17:43:56 CEST 2017
-From: alexander.levin@verizon.com
-Date: Tue, 4 Apr 2017 19:32:21 +0000
-Subject: scsi: ufs: refactor device descriptor reading
-To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
-Cc: "stable@vger.kernel.org" <stable@vger.kernel.org>
-Message-ID: <20170404193158.19041-52-alexander.levin@verizon.com>
-
-From: Tomas Winkler <tomas.winkler@intel.com>
-
-[ Upstream commit 93fdd5ac64bbe80dac6416f048405362d7ef0945 ]
-
-Pull device descriptor reading out of ufs quirk so it can be used also
-for other purposes.
-
-Revamp the fixup setup:
-
-1. Rename ufs_device_info to ufs_dev_desc as very similar name
- ufs_dev_info is already in use.
-
-2. Make the handlers static as they are not used out of the ufshdc.c
- file.
-
-[mkp: applied by hand]
-
-Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
-Reviewed-by: Subhash Jadavani <subhashj@codeaurora.org>
-Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- drivers/scsi/ufs/ufs.h | 12 ++++++++++++
- drivers/scsi/ufs/ufs_quirks.h | 28 ++++++----------------------
- drivers/scsi/ufs/ufshcd.c | 40 +++++++++++++++++++---------------------
- 3 files changed, 37 insertions(+), 43 deletions(-)
-
---- a/drivers/scsi/ufs/ufs.h
-+++ b/drivers/scsi/ufs/ufs.h
-@@ -522,4 +522,16 @@ struct ufs_dev_info {
- bool is_lu_power_on_wp;
- };
-
-+#define MAX_MODEL_LEN 16
-+/**
-+ * ufs_dev_desc - ufs device details from the device descriptor
-+ *
-+ * @wmanufacturerid: card details
-+ * @model: card model
-+ */
-+struct ufs_dev_desc {
-+ u16 wmanufacturerid;
-+ char model[MAX_MODEL_LEN + 1];
-+};
-+
- #endif /* End of Header */
---- a/drivers/scsi/ufs/ufs_quirks.h
-+++ b/drivers/scsi/ufs/ufs_quirks.h
-@@ -21,41 +21,28 @@
- #define UFS_ANY_VENDOR 0xFFFF
- #define UFS_ANY_MODEL "ANY_MODEL"
-
--#define MAX_MODEL_LEN 16
--
- #define UFS_VENDOR_TOSHIBA 0x198
- #define UFS_VENDOR_SAMSUNG 0x1CE
- #define UFS_VENDOR_SKHYNIX 0x1AD
-
- /**
-- * ufs_device_info - ufs device details
-- * @wmanufacturerid: card details
-- * @model: card model
-- */
--struct ufs_device_info {
-- u16 wmanufacturerid;
-- char model[MAX_MODEL_LEN + 1];
--};
--
--/**
- * ufs_dev_fix - ufs device quirk info
- * @card: ufs card details
- * @quirk: device quirk
- */
- struct ufs_dev_fix {
-- struct ufs_device_info card;
-+ struct ufs_dev_desc card;
- unsigned int quirk;
- };
-
- #define END_FIX { { 0 }, 0 }
-
- /* add specific device quirk */
--#define UFS_FIX(_vendor, _model, _quirk) \
-- { \
-- .card.wmanufacturerid = (_vendor),\
-- .card.model = (_model), \
-- .quirk = (_quirk), \
-- }
-+#define UFS_FIX(_vendor, _model, _quirk) { \
-+ .card.wmanufacturerid = (_vendor),\
-+ .card.model = (_model), \
-+ .quirk = (_quirk), \
-+}
-
- /*
- * If UFS device is having issue in processing LCC (Line Control
-@@ -144,7 +131,4 @@ struct ufs_dev_fix {
- */
- #define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 8)
-
--struct ufs_hba;
--void ufs_advertise_fixup_device(struct ufs_hba *hba);
--
- #endif /* UFS_QUIRKS_H_ */
---- a/drivers/scsi/ufs/ufshcd.c
-+++ b/drivers/scsi/ufs/ufshcd.c
-@@ -4874,8 +4874,8 @@ out:
- return ret;
- }
-
--static int ufs_get_device_info(struct ufs_hba *hba,
-- struct ufs_device_info *card_data)
-+static int ufs_get_device_desc(struct ufs_hba *hba,
-+ struct ufs_dev_desc *dev_desc)
- {
- int err;
- u8 model_index;
-@@ -4894,7 +4894,7 @@ static int ufs_get_device_info(struct uf
- * getting vendor (manufacturerID) and Bank Index in big endian
- * format
- */
-- card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 |
-+ dev_desc->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 |
- desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1];
-
- model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
-@@ -4908,36 +4908,26 @@ static int ufs_get_device_info(struct uf
- }
-
- str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0';
-- strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE),
-+ strlcpy(dev_desc->model, (str_desc_buf + QUERY_DESC_HDR_SIZE),
- min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET],
- MAX_MODEL_LEN));
-
- /* Null terminate the model string */
-- card_data->model[MAX_MODEL_LEN] = '\0';
-+ dev_desc->model[MAX_MODEL_LEN] = '\0';
-
- out:
- return err;
- }
-
--void ufs_advertise_fixup_device(struct ufs_hba *hba)
-+static void ufs_fixup_device_setup(struct ufs_hba *hba,
-+ struct ufs_dev_desc *dev_desc)
- {
-- int err;
- struct ufs_dev_fix *f;
-- struct ufs_device_info card_data;
--
-- card_data.wmanufacturerid = 0;
--
-- err = ufs_get_device_info(hba, &card_data);
-- if (err) {
-- dev_err(hba->dev, "%s: Failed getting device info. err = %d\n",
-- __func__, err);
-- return;
-- }
-
- for (f = ufs_fixups; f->quirk; f++) {
-- if (((f->card.wmanufacturerid == card_data.wmanufacturerid) ||
-- (f->card.wmanufacturerid == UFS_ANY_VENDOR)) &&
-- (STR_PRFX_EQUAL(f->card.model, card_data.model) ||
-+ if ((f->card.wmanufacturerid == dev_desc->wmanufacturerid ||
-+ f->card.wmanufacturerid == UFS_ANY_VENDOR) &&
-+ (STR_PRFX_EQUAL(f->card.model, dev_desc->model) ||
- !strcmp(f->card.model, UFS_ANY_MODEL)))
- hba->dev_quirks |= f->quirk;
- }
-@@ -5115,6 +5105,7 @@ static void ufshcd_tune_unipro_params(st
- */
- static int ufshcd_probe_hba(struct ufs_hba *hba)
- {
-+ struct ufs_dev_desc card = {0};
- int ret;
-
- ret = ufshcd_link_startup(hba);
-@@ -5138,7 +5129,14 @@ static int ufshcd_probe_hba(struct ufs_h
- if (ret)
- goto out;
-
-- ufs_advertise_fixup_device(hba);
-+ ret = ufs_get_device_desc(hba, &card);
-+ if (ret) {
-+ dev_err(hba->dev, "%s: Failed getting device info. err = %d\n",
-+ __func__, ret);
-+ goto out;
-+ }
-+
-+ ufs_fixup_device_setup(hba, &card);
- ufshcd_tune_unipro_params(hba);
-
- ret = ufshcd_set_vccq_rail_unused(hba,