lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20201123004116.2453-3-ruansy.fnst@cn.fujitsu.com>
Date:   Mon, 23 Nov 2020 08:41:12 +0800
From:   Shiyang Ruan <ruansy.fnst@...fujitsu.com>
To:     <linux-kernel@...r.kernel.org>, <linux-xfs@...r.kernel.org>,
        <linux-nvdimm@...ts.01.org>, <linux-mm@...ck.org>
CC:     <linux-fsdevel@...r.kernel.org>, <linux-raid@...r.kernel.org>,
        <darrick.wong@...cle.com>, <dan.j.williams@...el.com>,
        <david@...morbit.com>, <hch@....de>, <song@...nel.org>,
        <rgoldwyn@...e.de>, <qi.fuli@...itsu.com>, <y-goto@...itsu.com>
Subject: [RFC PATCH v2 2/6] blk: introduce ->block_lost() to handle memory-failure

In fsdax mode, the memory failure happens on block device.  So, it is
needed to introduce an interface for block devices.  Each kind of block
device can handle the memory failure in ther own ways.

Usually, a block device is used directly to mkfs on it.  The filesystem
on it is easily to obtain by 'get_super()'.  The block device can also
be divided into several partitions, or used as a target by mapped
device.  It is hard to get filesystem's superblock in this two ways.
So, add 'bdget_disk_sector()' to get the block device of a partition
where the broken sector located in.  And add
'bd_disk_holder_block_lost()' iterate the mapped devices on it.

Signed-off-by: Shiyang Ruan <ruansy.fnst@...fujitsu.com>
---
 block/genhd.c          | 12 ++++++++++++
 drivers/nvdimm/pmem.c  | 27 +++++++++++++++++++++++++++
 fs/block_dev.c         | 23 +++++++++++++++++++++++
 include/linux/blkdev.h |  2 ++
 include/linux/genhd.h  |  9 +++++++++
 5 files changed, 73 insertions(+)

diff --git a/block/genhd.c b/block/genhd.c
index 0a273211fec2..2c7304f123fa 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1055,6 +1055,18 @@ struct block_device *bdget_disk(struct gendisk *disk, int partno)
 }
 EXPORT_SYMBOL(bdget_disk);
 
+struct block_device *bdget_disk_sector(struct gendisk *disk, sector_t sector)
+{
+	struct block_device *bdev = NULL;
+	struct hd_struct *part = disk_map_sector_rcu(disk, sector);
+
+	if (part)
+		bdev = bdget_part(part);
+
+	return bdev;
+}
+EXPORT_SYMBOL(bdget_disk_sector);
+
 /*
  * print a full list of all partitions - intended for places where the root
  * filesystem can't be mounted and thus to give the victim some idea of what
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 875076b0ea6c..d75a3f370f3c 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -253,6 +253,32 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector,
 	return blk_status_to_errno(rc);
 }
 
+int pmem_block_lost(struct gendisk *disk, struct block_device *bdev,
+		    loff_t disk_offset, void *data)
+{
+	struct super_block *sb;
+	sector_t bdev_sector, disk_sector = disk_offset >> SECTOR_SHIFT;
+	int rc = 0;
+
+	bdev = bdget_disk_sector(disk, disk_sector);
+	if (!bdev)
+		return -ENODEV;
+
+	bdev_sector = disk_sector - get_start_sect(bdev);
+	sb = get_super(bdev);
+	if (!sb) {
+		rc = bd_disk_holder_block_lost(bdev, bdev_sector, data);
+		goto out;
+	} else if (sb->s_op->storage_lost)
+		rc = sb->s_op->storage_lost(sb, bdev,
+					    bdev_sector << SECTOR_SHIFT, data);
+	drop_super(sb);
+
+out:
+	bdput(bdev);
+	return rc;
+}
+
 /* see "strong" declaration in tools/testing/nvdimm/pmem-dax.c */
 __weak long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff,
 		long nr_pages, void **kaddr, pfn_t *pfn)
@@ -281,6 +307,7 @@ static const struct block_device_operations pmem_fops = {
 	.owner =		THIS_MODULE,
 	.submit_bio =		pmem_submit_bio,
 	.rw_page =		pmem_rw_page,
+	.block_lost =		pmem_block_lost,
 };
 
 static int pmem_dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 9e84b1928b94..e1e30828fb9f 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1171,6 +1171,29 @@ struct bd_holder_disk {
 	int			refcnt;
 };
 
+int bd_disk_holder_block_lost(struct block_device *bdev, sector_t offset,
+			      void *data)
+{
+	struct bd_holder_disk *holder;
+	struct gendisk *disk;
+	int rc = 0;
+
+	if (list_empty(&(bdev->bd_holder_disks)))
+		return -ENODEV;
+
+	list_for_each_entry(holder, &bdev->bd_holder_disks, list) {
+		disk = holder->disk;
+		if (disk->fops->block_lost) {
+			rc = disk->fops->block_lost(disk, bdev,
+					       offset << SECTOR_SHIFT, data);
+			if (rc != -ENODEV)
+				break;
+		}
+	}
+	return rc;
+}
+EXPORT_SYMBOL_GPL(bd_disk_holder_block_lost);
+
 static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev,
 						  struct gendisk *disk)
 {
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 639cae2c158b..ddeb268cc938 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1855,6 +1855,8 @@ struct block_device_operations {
 	int (*report_zones)(struct gendisk *, sector_t sector,
 			unsigned int nr_zones, report_zones_cb cb, void *data);
 	char *(*devnode)(struct gendisk *disk, umode_t *mode);
+	int (*block_lost)(struct gendisk *disk, struct block_device *bdev,
+			  loff_t offset, void *data);
 	struct module *owner;
 	const struct pr_ops *pr_ops;
 };
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 38f23d757013..9d8f5b5dab9f 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -303,6 +303,8 @@ static inline void add_disk_no_queue_reg(struct gendisk *disk)
 extern void del_gendisk(struct gendisk *gp);
 extern struct gendisk *get_gendisk(dev_t dev, int *partno);
 extern struct block_device *bdget_disk(struct gendisk *disk, int partno);
+extern struct block_device *bdget_disk_sector(struct gendisk *disk,
+					      sector_t sector);
 
 extern void set_device_ro(struct block_device *bdev, int flag);
 extern void set_disk_ro(struct gendisk *disk, int flag);
@@ -381,9 +383,16 @@ int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long);
 long compat_blkdev_ioctl(struct file *, unsigned, unsigned long);
 
 #ifdef CONFIG_SYSFS
+int bd_disk_holder_block_lost(struct block_device *bdev, sector_t offset,
+			      void *data);
 int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk);
 void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk);
 #else
+static inline int bd_disk_holder_block_lost(struct block_device *bdev,
+					    sector_t offset, void *data)
+{
+	return 0;
+}
 static inline int bd_link_disk_holder(struct block_device *bdev,
 				      struct gendisk *disk)
 {
-- 
2.29.2



Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ