Commit 2a171aa2 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'akpm' (patches from Andrew)

Merge misc fixes from Andrew Morton:
 "16 patches

  This includes a new rtc driver for the Abracon AB x80x and isn't very
  appropriate for -rc2.  It was still being fiddled with a bit during
  the merge window and I fell asleep during -rc1"

[ So I took the new driver, it seems small and won't regress anything.
  I'm a softy.   - Linus ]

* emailed patches from Andrew Morton <akpm@linux-foundation.org>:
  rtc: armada38x: fix concurrency access in armada38x_rtc_set_time
  ocfs2: dlm: fix race between purge and get lock resource
  nilfs2: fix sanity check of btree level in nilfs_btree_root_broken()
  util_macros.h: have array pointer point to array of constants
  configfs: init configfs module earlier at boot time
  mm/hwpoison-inject: check PageLRU of hpage
  mm/hwpoison-inject: fix refcounting in no-injection case
  mm: soft-offline: fix num_poisoned_pages counting on concurrent events
  rtc: add rtc-abx80x, a driver for the Abracon AB x80x i2c rtc
  Documentation: bindings: add abracon,abx80x
  kasan: show gcc version requirements in Kconfig and Documentation
  mm/memory-failure: call shake_page() when error hits thp tail page
  lib: delete lib/find_last_bit.c
  MAINTAINERS: add co-maintainer for LED subsystem
  zram: add Designated Reviewer for zram in MAINTAINERS
  revert "zram: move compact_store() to sysfs functions area"
parents 3ce05a4e 489405fe
Abracon ABX80X I2C ultra low power RTC/Alarm chip
The Abracon ABX80X family consist of the ab0801, ab0803, ab0804, ab0805, ab1801,
ab1803, ab1804 and ab1805. The ab0805 is the superset of ab080x and the ab1805
is the superset of ab180x.
Required properties:
- "compatible": should one of:
"abracon,abx80x"
"abracon,ab0801"
"abracon,ab0803"
"abracon,ab0804"
"abracon,ab0805"
"abracon,ab1801"
"abracon,ab1803"
"abracon,ab1804"
"abracon,ab1805"
Using "abracon,abx80x" will enable chip autodetection.
- "reg": I2C bus address of the device
Optional properties:
The abx804 and abx805 have a trickle charger that is able to charge the
connected battery or supercap. Both the following properties have to be defined
and valid to enable charging:
- "abracon,tc-diode": should be "standard" (0.6V) or "schottky" (0.3V)
- "abracon,tc-resistor": should be <0>, <3>, <6> or <11>. 0 disables the output
resistor, the other values are in ohm.
......@@ -9,7 +9,9 @@ a fast and comprehensive solution for finding use-after-free and out-of-bounds
bugs.
KASan uses compile-time instrumentation for checking every memory access,
therefore you will need a certain version of GCC > 4.9.2
therefore you will need a gcc version of 4.9.2 or later. KASan could detect out
of bounds accesses to stack or global variables, but only if gcc 5.0 or later was
used to built the kernel.
Currently KASan is supported only for x86_64 architecture and requires that the
kernel be built with the SLUB allocator.
......@@ -23,8 +25,8 @@ To enable KASAN configure kernel with:
and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline/inline
is compiler instrumentation types. The former produces smaller binary the
latter is 1.1 - 2 times faster. Inline instrumentation requires GCC 5.0 or
latter.
latter is 1.1 - 2 times faster. Inline instrumentation requires a gcc version
of 5.0 or later.
Currently KASAN works only with the SLUB memory allocator.
For better bug detection and nicer report, enable CONFIG_STACKTRACE and put
......
......@@ -5805,6 +5805,7 @@ F: drivers/scsi/53c700*
LED SUBSYSTEM
M: Bryan Wu <cooloney@gmail.com>
M: Richard Purdie <rpurdie@rpsys.net>
M: Jacek Anaszewski <j.anaszewski@samsung.com>
L: linux-leds@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds.git
S: Maintained
......@@ -11037,6 +11038,7 @@ F: drivers/media/pci/zoran/
ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER
M: Minchan Kim <minchan@kernel.org>
M: Nitin Gupta <ngupta@vflare.org>
R: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
L: linux-kernel@vger.kernel.org
S: Maintained
F: drivers/block/zram/
......
......@@ -74,6 +74,27 @@ static inline struct zram *dev_to_zram(struct device *dev)
return (struct zram *)dev_to_disk(dev)->private_data;
}
static ssize_t compact_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
unsigned long nr_migrated;
struct zram *zram = dev_to_zram(dev);
struct zram_meta *meta;
down_read(&zram->init_lock);
if (!init_done(zram)) {
up_read(&zram->init_lock);
return -EINVAL;
}
meta = zram->meta;
nr_migrated = zs_compact(meta->mem_pool);
atomic64_add(nr_migrated, &zram->stats.num_migrated);
up_read(&zram->init_lock);
return len;
}
static ssize_t disksize_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
......@@ -1038,6 +1059,7 @@ static const struct block_device_operations zram_devops = {
.owner = THIS_MODULE
};
static DEVICE_ATTR_WO(compact);
static DEVICE_ATTR_RW(disksize);
static DEVICE_ATTR_RO(initstate);
static DEVICE_ATTR_WO(reset);
......@@ -1114,6 +1136,7 @@ static struct attribute *zram_disk_attrs[] = {
&dev_attr_num_writes.attr,
&dev_attr_failed_reads.attr,
&dev_attr_failed_writes.attr,
&dev_attr_compact.attr,
&dev_attr_invalid_io.attr,
&dev_attr_notify_free.attr,
&dev_attr_zero_pages.attr,
......
......@@ -164,6 +164,16 @@ config RTC_DRV_ABB5ZES3
This driver can also be built as a module. If so, the module
will be called rtc-ab-b5ze-s3.
config RTC_DRV_ABX80X
tristate "Abracon ABx80x"
help
If you say yes here you get support for Abracon AB080X and AB180X
families of ultra-low-power battery- and capacitor-backed real-time
clock chips.
This driver can also be built as a module. If so, the module
will be called rtc-abx80x.
config RTC_DRV_AS3722
tristate "ams AS3722 RTC driver"
depends on MFD_AS3722
......
......@@ -25,6 +25,7 @@ obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o
obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o
obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.o
obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o
obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o
obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
......
/*
* A driver for the I2C members of the Abracon AB x8xx RTC family,
* and compatible: AB 1805 and AB 0805
*
* Copyright 2014-2015 Macq S.A.
*
* Author: Philippe De Muyter <phdm@macqel.be>
* Author: Alexandre Belloni <alexandre.belloni@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/bcd.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/rtc.h>
#define ABX8XX_REG_HTH 0x00
#define ABX8XX_REG_SC 0x01
#define ABX8XX_REG_MN 0x02
#define ABX8XX_REG_HR 0x03
#define ABX8XX_REG_DA 0x04
#define ABX8XX_REG_MO 0x05
#define ABX8XX_REG_YR 0x06
#define ABX8XX_REG_WD 0x07
#define ABX8XX_REG_CTRL1 0x10
#define ABX8XX_CTRL_WRITE BIT(1)
#define ABX8XX_CTRL_12_24 BIT(6)
#define ABX8XX_REG_CFG_KEY 0x1f
#define ABX8XX_CFG_KEY_MISC 0x9d
#define ABX8XX_REG_ID0 0x28
#define ABX8XX_REG_TRICKLE 0x20
#define ABX8XX_TRICKLE_CHARGE_ENABLE 0xa0
#define ABX8XX_TRICKLE_STANDARD_DIODE 0x8
#define ABX8XX_TRICKLE_SCHOTTKY_DIODE 0x4
static u8 trickle_resistors[] = {0, 3, 6, 11};
enum abx80x_chip {AB0801, AB0803, AB0804, AB0805,
AB1801, AB1803, AB1804, AB1805, ABX80X};
struct abx80x_cap {
u16 pn;
bool has_tc;
};
static struct abx80x_cap abx80x_caps[] = {
[AB0801] = {.pn = 0x0801},
[AB0803] = {.pn = 0x0803},
[AB0804] = {.pn = 0x0804, .has_tc = true},
[AB0805] = {.pn = 0x0805, .has_tc = true},
[AB1801] = {.pn = 0x1801},
[AB1803] = {.pn = 0x1803},
[AB1804] = {.pn = 0x1804, .has_tc = true},
[AB1805] = {.pn = 0x1805, .has_tc = true},
[ABX80X] = {.pn = 0}
};
static struct i2c_driver abx80x_driver;
static int abx80x_enable_trickle_charger(struct i2c_client *client,
u8 trickle_cfg)
{
int err;
/*
* Write the configuration key register to enable access to the Trickle
* register
*/
err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CFG_KEY,
ABX8XX_CFG_KEY_MISC);
if (err < 0) {
dev_err(&client->dev, "Unable to write configuration key\n");
return -EIO;
}
err = i2c_smbus_write_byte_data(client, ABX8XX_REG_TRICKLE,
ABX8XX_TRICKLE_CHARGE_ENABLE |
trickle_cfg);
if (err < 0) {
dev_err(&client->dev, "Unable to write trickle register\n");
return -EIO;
}
return 0;
}
static int abx80x_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct i2c_client *client = to_i2c_client(dev);
unsigned char buf[8];
int err;
err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_HTH,
sizeof(buf), buf);
if (err < 0) {
dev_err(&client->dev, "Unable to read date\n");
return -EIO;
}
tm->tm_sec = bcd2bin(buf[ABX8XX_REG_SC] & 0x7F);
tm->tm_min = bcd2bin(buf[ABX8XX_REG_MN] & 0x7F);
tm->tm_hour = bcd2bin(buf[ABX8XX_REG_HR] & 0x3F);
tm->tm_wday = buf[ABX8XX_REG_WD] & 0x7;
tm->tm_mday = bcd2bin(buf[ABX8XX_REG_DA] & 0x3F);
tm->tm_mon = bcd2bin(buf[ABX8XX_REG_MO] & 0x1F) - 1;
tm->tm_year = bcd2bin(buf[ABX8XX_REG_YR]) + 100;
err = rtc_valid_tm(tm);
if (err < 0)
dev_err(&client->dev, "retrieved date/time is not valid.\n");
return err;
}
static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct i2c_client *client = to_i2c_client(dev);
unsigned char buf[8];
int err;
if (tm->tm_year < 100)
return -EINVAL;
buf[ABX8XX_REG_HTH] = 0;
buf[ABX8XX_REG_SC] = bin2bcd(tm->tm_sec);
buf[ABX8XX_REG_MN] = bin2bcd(tm->tm_min);
buf[ABX8XX_REG_HR] = bin2bcd(tm->tm_hour);
buf[ABX8XX_REG_DA] = bin2bcd(tm->tm_mday);
buf[ABX8XX_REG_MO] = bin2bcd(tm->tm_mon + 1);
buf[ABX8XX_REG_YR] = bin2bcd(tm->tm_year - 100);
buf[ABX8XX_REG_WD] = tm->tm_wday;
err = i2c_smbus_write_i2c_block_data(client, ABX8XX_REG_HTH,
sizeof(buf), buf);
if (err < 0) {
dev_err(&client->dev, "Unable to write to date registers\n");
return -EIO;
}
return 0;
}
static const struct rtc_class_ops abx80x_rtc_ops = {
.read_time = abx80x_rtc_read_time,
.set_time = abx80x_rtc_set_time,
};
static int abx80x_dt_trickle_cfg(struct device_node *np)
{
const char *diode;
int trickle_cfg = 0;
int i, ret;
u32 tmp;
ret = of_property_read_string(np, "abracon,tc-diode", &diode);
if (ret)
return ret;
if (!strcmp(diode, "standard"))
trickle_cfg |= ABX8XX_TRICKLE_STANDARD_DIODE;
else if (!strcmp(diode, "schottky"))
trickle_cfg |= ABX8XX_TRICKLE_SCHOTTKY_DIODE;
else
return -EINVAL;
ret = of_property_read_u32(np, "abracon,tc-resistor", &tmp);
if (ret)
return ret;
for (i = 0; i < sizeof(trickle_resistors); i++)
if (trickle_resistors[i] == tmp)
break;
if (i == sizeof(trickle_resistors))
return -EINVAL;
return (trickle_cfg | i);
}
static int abx80x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device_node *np = client->dev.of_node;
struct rtc_device *rtc;
int i, data, err, trickle_cfg = -EINVAL;
char buf[7];
unsigned int part = id->driver_data;
unsigned int partnumber;
unsigned int majrev, minrev;
unsigned int lot;
unsigned int wafer;
unsigned int uid;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_ID0,
sizeof(buf), buf);
if (err < 0) {
dev_err(&client->dev, "Unable to read partnumber\n");
return -EIO;
}
partnumber = (buf[0] << 8) | buf[1];
majrev = buf[2] >> 3;
minrev = buf[2] & 0x7;
lot = ((buf[4] & 0x80) << 2) | ((buf[6] & 0x80) << 1) | buf[3];
uid = ((buf[4] & 0x7f) << 8) | buf[5];
wafer = (buf[6] & 0x7c) >> 2;
dev_info(&client->dev, "model %04x, revision %u.%u, lot %x, wafer %x, uid %x\n",
partnumber, majrev, minrev, lot, wafer, uid);
data = i2c_smbus_read_byte_data(client, ABX8XX_REG_CTRL1);
if (data < 0) {
dev_err(&client->dev, "Unable to read control register\n");
return -EIO;
}
err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CTRL1,
((data & ~ABX8XX_CTRL_12_24) |
ABX8XX_CTRL_WRITE));
if (err < 0) {
dev_err(&client->dev, "Unable to write control register\n");
return -EIO;
}
/* part autodetection */
if (part == ABX80X) {
for (i = 0; abx80x_caps[i].pn; i++)
if (partnumber == abx80x_caps[i].pn)
break;
if (abx80x_caps[i].pn == 0) {
dev_err(&client->dev, "Unknown part: %04x\n",
partnumber);
return -EINVAL;
}
part = i;
}
if (partnumber != abx80x_caps[part].pn) {
dev_err(&client->dev, "partnumber mismatch %04x != %04x\n",
partnumber, abx80x_caps[part].pn);
return -EINVAL;
}
if (np && abx80x_caps[part].has_tc)
trickle_cfg = abx80x_dt_trickle_cfg(np);
if (trickle_cfg > 0) {
dev_info(&client->dev, "Enabling trickle charger: %02x\n",
trickle_cfg);
abx80x_enable_trickle_charger(client, trickle_cfg);
}
rtc = devm_rtc_device_register(&client->dev, abx80x_driver.driver.name,
&abx80x_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
i2c_set_clientdata(client, rtc);
return 0;
}
static int abx80x_remove(struct i2c_client *client)
{
return 0;
}
static const struct i2c_device_id abx80x_id[] = {
{ "abx80x", ABX80X },
{ "ab0801", AB0801 },
{ "ab0803", AB0803 },
{ "ab0804", AB0804 },
{ "ab0805", AB0805 },
{ "ab1801", AB1801 },
{ "ab1803", AB1803 },
{ "ab1804", AB1804 },
{ "ab1805", AB1805 },
{ }
};
MODULE_DEVICE_TABLE(i2c, abx80x_id);
static struct i2c_driver abx80x_driver = {
.driver = {
.name = "rtc-abx80x",
},
.probe = abx80x_probe,
.remove = abx80x_remove,
.id_table = abx80x_id,
};
module_i2c_driver(abx80x_driver);
MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>");
MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
MODULE_DESCRIPTION("Abracon ABX80X RTC driver");
MODULE_LICENSE("GPL v2");
......@@ -40,6 +40,13 @@ struct armada38x_rtc {
void __iomem *regs;
void __iomem *regs_soc;
spinlock_t lock;
/*
* While setting the time, the RTC TIME register should not be
* accessed. Setting the RTC time involves sleeping during
* 100ms, so a mutex instead of a spinlock is used to protect
* it
*/
struct mutex mutex_time;
int irq;
};
......@@ -59,8 +66,7 @@ static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
unsigned long time, time_check, flags;
spin_lock_irqsave(&rtc->lock, flags);
mutex_lock(&rtc->mutex_time);
time = readl(rtc->regs + RTC_TIME);
/*
* WA for failing time set attempts. As stated in HW ERRATA if
......@@ -71,7 +77,7 @@ static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
if ((time_check - time) > 1)
time_check = readl(rtc->regs + RTC_TIME);
spin_unlock_irqrestore(&rtc->lock, flags);
mutex_unlock(&rtc->mutex_time);
rtc_time_to_tm(time_check, tm);
......@@ -94,19 +100,12 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
* then wait for 100ms before writing to the time register to be
* sure that the data will be taken into account.
*/
spin_lock_irqsave(&rtc->lock, flags);
mutex_lock(&rtc->mutex_time);
rtc_delayed_write(0, rtc, RTC_STATUS);
spin_unlock_irqrestore(&rtc->lock, flags);
msleep(100);
spin_lock_irqsave(&rtc->lock, flags);
rtc_delayed_write(time, rtc, RTC_TIME);
mutex_unlock(&rtc->mutex_time);
spin_unlock_irqrestore(&rtc->lock, flags);
out:
return ret;
}
......@@ -230,6 +229,7 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
return -ENOMEM;
spin_lock_init(&rtc->lock);
mutex_init(&rtc->mutex_time);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc");
rtc->regs = devm_ioremap_resource(&pdev->dev, res);
......
......@@ -173,5 +173,5 @@ MODULE_LICENSE("GPL");
MODULE_VERSION("0.0.2");
MODULE_DESCRIPTION("Simple RAM filesystem for user driven kernel subsystem configuration.");
module_init(configfs_init);
core_initcall(configfs_init);
module_exit(configfs_exit);
......@@ -388,7 +388,7 @@ static int nilfs_btree_root_broken(const struct nilfs_btree_node *node,
nchildren = nilfs_btree_node_get_nchildren(node);
if (unlikely(level < NILFS_BTREE_LEVEL_NODE_MIN ||
level > NILFS_BTREE_LEVEL_MAX ||
level >= NILFS_BTREE_LEVEL_MAX ||
nchildren < 0 ||
nchildren > NILFS_BTREE_ROOT_NCHILDREN_MAX)) {
pr_crit("NILFS: bad btree root (inode number=%lu): level = %d, flags = 0x%x, nchildren = %d\n",
......
......@@ -757,6 +757,19 @@ struct dlm_lock_resource * dlm_get_lock_resource(struct dlm_ctxt *dlm,
if (tmpres) {
spin_unlock(&dlm->spinlock);
spin_lock(&tmpres->spinlock);
/*
* Right after dlm spinlock was released, dlm_thread could have
* purged the lockres. Check if lockres got unhashed. If so
* start over.
*/
if (hlist_unhashed(&tmpres->hash_node)) {
spin_unlock(&tmpres->spinlock);
dlm_lockres_put(tmpres);
tmpres = NULL;
goto lookup;
}
/* Wait on the thread that is mastering the resource */
if (tmpres->owner == DLM_LOCK_RES_OWNER_UNKNOWN) {
__dlm_wait_on_lockres(tmpres);
......
......@@ -460,7 +460,7 @@ struct nilfs_btree_node {
/* level */
#define NILFS_BTREE_LEVEL_DATA 0
#define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1)
#define NILFS_BTREE_LEVEL_MAX 14
#define NILFS_BTREE_LEVEL_MAX 14 /* Max level (exclusive) */
/**
* struct nilfs_palloc_group_desc - block group descriptor
......
......@@ -5,7 +5,7 @@
({ \
typeof(as) __fc_i, __fc_as = (as) - 1; \
typeof(x) __fc_x = (x); \
typeof(*a) *__fc_a = (a); \
typeof(*a) const *__fc_a = (a); \
for (__fc_i = 0; __fc_i < __fc_as; __fc_i++) { \
if (__fc_x op DIV_ROUND_CLOSEST(__fc_a[__fc_i] + \
__fc_a[__fc_i + 1], 2)) \
......
......@@ -10,8 +10,11 @@ config KASAN
help
Enables kernel address sanitizer - runtime memory debugger,
designed to find out-of-bounds accesses and use-after-free bugs.
This is strictly debugging feature. It consumes about 1/8
of available memory and brings about ~x3 performance slowdown.
This is strictly a debugging feature and it requires a gcc version
of 4.9.2 or later. Detection of out of bounds accesses to stack or
global variables requires gcc 5.0 or later.
This feature consumes about 1/8 of available memory and brings about
~x3 performance slowdown.
For better error detection enable CONFIG_STACKTRACE,
and add slub_debug=U to boot cmdline.
......@@ -40,6 +43,7 @@ config KASAN_INLINE
memory accesses. This is faster than outline (in some workloads
it gives about x2 boost over outline instrumentation), but
make kernel's .text size much bigger.
This requires a gcc version of 5.0 or later.
endchoice
......
/* find_last_bit.c: fallback find next bit implementation
*
* Copyright (C) 2008 IBM Corporation
* Written by Rusty Russell <rusty@rustcorp.com.au>
* (Inspired by David Howell's find_next_bit implementation)
*
* Rewritten by Yury Norov <yury.norov@gmail.com> to decrease
* size and improve performance, 2015.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/bitops.h>
#include <linux/bitmap.h>
#include <linux/export.h>
#include <linux/kernel.h>
#ifndef find_last_bit
unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
{
if (size) {
unsigned long val = BITMAP_LAST_WORD_MASK(size);
unsigned long idx = (size-1) / BITS_PER_LONG;
do {
val &= addr[idx];
if (val)
return idx * BITS_PER_LONG + __fls(val);
val = ~0ul;
} while (idx--);
}
return size;
}
EXPORT_SYMBOL(find_last_bit);
#endif
......@@ -34,13 +34,13 @@ static int hwpoison_inject(void *data, u64 val)
if (!hwpoison_filter_enable)
goto inject;
if (!PageLRU(p) && !PageHuge(p))
shake_page(p, 0);
if (!PageLRU(hpage) && !PageHuge(p))
shake_page(hpage, 0);
/*
* This implies unable to support non-LRU pages.
*/
if (!PageLRU(p) && !PageHuge(p))
return 0;
if (!PageLRU(hpage) && !PageHuge(p))
goto put_out;
/*
* do a racy check with elevated page count, to make sure PG_hwpoison
......@@ -52,11 +52,14 @@ static int hwpoison_inject(void *data, u64 val)
err = hwpoison_filter(hpage);
unlock_page(hpage);
if (err)
return 0;
goto put_out;
inject:
pr_info("Injecting memory failure at pfn %#lx\n", pfn);
return memory_failure(pfn, 18, MF_COUNT_INCREASED);
put_out:
put_page(hpage);
return 0;
}
static int hwpoison_unpoison(void *data, u64 val)
......
......@@ -1187,10 +1187,10 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
* The check (unnecessarily) ignores LRU pages being isolated and
* walked by the page reclaim code, however that's not a big loss.
*/
if (!PageHuge(p) && !PageTransTail(p)) {
if (!PageLRU(p))
shake_page(p, 0);
if (!PageLRU(p)) {
if (!PageHuge(p)) {
if (!PageLRU(hpage))
shake_page(hpage, 0);
if (!PageLRU(hpage)) {
/*
* shake_page could have turned it free.
*/
......@@ -1777,11 +1777,11 @@ int soft_offline_page(struct page *page, int flags)
} else if (ret == 0) { /* for free pages */
if (PageHuge(page)) {
set_page_hwpoison_huge_page(hpage);
dequeue_hwpoisoned_huge_page(hpage);
if (!dequeue_hwpoisoned_huge_page(hpage))
atomic_long_add(1 << compound_order(hpage),
&num_poisoned_pages);
} else {
SetPageHWPoison(page);
if (!TestSetPageHWPoison(page))
atomic_long_inc(&num_poisoned_pages);
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment