Skip to content

Commit 829def1

Browse files
Christoph Hellwigaxboe
authored andcommitted
zloop: forget write cache on force removal
Add a new options that causes zloop to truncate the zone files to the write pointer value recorded at the last cache flush to simulate unclean shutdowns. Signed-off-by: Christoph Hellwig <[email protected]> Reviewed-by: Bart Van Assche <[email protected]> Reviewed-by: Damien Le Moal <[email protected]> Reviewed-by: Martin K. Petersen <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent eff8d16 commit 829def1

2 files changed

Lines changed: 102 additions & 0 deletions

File tree

Documentation/admin-guide/blockdev/zoned_loop.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ ordered_zone_append Enable zloop mitigation of zone append reordering.
104104
(extents), as when enabled, this can significantly reduce
105105
the number of data extents needed to for a file data
106106
mapping.
107+
discard_write_cache Discard all data that was not explicitly persisted using a
108+
flush operation when the device is removed by truncating
109+
each zone file to the size recorded during the last flush
110+
operation. This simulates power fail events where
111+
uncommitted data is lost.
107112
=================== =========================================================
108113

109114
3) Deleting a Zoned Device

drivers/block/zloop.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/mutex.h>
1818
#include <linux/parser.h>
1919
#include <linux/seq_file.h>
20+
#include <linux/xattr.h>
2021

2122
/*
2223
* Options for adding (and removing) a device.
@@ -34,6 +35,7 @@ enum {
3435
ZLOOP_OPT_BUFFERED_IO = (1 << 8),
3536
ZLOOP_OPT_ZONE_APPEND = (1 << 9),
3637
ZLOOP_OPT_ORDERED_ZONE_APPEND = (1 << 10),
38+
ZLOOP_OPT_DISCARD_WRITE_CACHE = (1 << 11),
3739
};
3840

3941
static const match_table_t zloop_opt_tokens = {
@@ -48,6 +50,7 @@ static const match_table_t zloop_opt_tokens = {
4850
{ ZLOOP_OPT_BUFFERED_IO, "buffered_io" },
4951
{ ZLOOP_OPT_ZONE_APPEND, "zone_append=%u" },
5052
{ ZLOOP_OPT_ORDERED_ZONE_APPEND, "ordered_zone_append" },
53+
{ ZLOOP_OPT_DISCARD_WRITE_CACHE, "discard_write_cache" },
5154
{ ZLOOP_OPT_ERR, NULL }
5255
};
5356

@@ -79,6 +82,7 @@ struct zloop_options {
7982
bool buffered_io;
8083
bool zone_append;
8184
bool ordered_zone_append;
85+
bool discard_write_cache;
8286
};
8387

8488
/*
@@ -119,6 +123,7 @@ struct zloop_device {
119123
bool buffered_io;
120124
bool zone_append;
121125
bool ordered_zone_append;
126+
bool discard_write_cache;
122127

123128
const char *base_dir;
124129
struct file *data_dir;
@@ -550,6 +555,41 @@ static void zloop_rw(struct zloop_cmd *cmd)
550555
zloop_put_cmd(cmd);
551556
}
552557

558+
static inline bool zloop_zone_is_active(struct zloop_zone *zone)
559+
{
560+
switch (zone->cond) {
561+
case BLK_ZONE_COND_EXP_OPEN:
562+
case BLK_ZONE_COND_IMP_OPEN:
563+
case BLK_ZONE_COND_CLOSED:
564+
return true;
565+
default:
566+
return false;
567+
}
568+
}
569+
570+
static int zloop_record_safe_wps(struct zloop_device *zlo)
571+
{
572+
unsigned int i;
573+
int ret;
574+
575+
for (i = 0; i < zlo->nr_zones; i++) {
576+
struct zloop_zone *zone = &zlo->zones[i];
577+
struct file *file = zone->file;
578+
579+
if (!zloop_zone_is_active(zone))
580+
continue;
581+
ret = vfs_setxattr(file_mnt_idmap(file), file_dentry(file),
582+
"user.zloop.wp", &zone->wp, sizeof(zone->wp), 0);
583+
if (ret) {
584+
pr_err("%pg: failed to record write pointer (%d)\n",
585+
zlo->disk->part0, ret);
586+
return ret;
587+
}
588+
}
589+
590+
return 0;
591+
}
592+
553593
/*
554594
* Sync the entire FS containing the zone files instead of walking all files.
555595
*/
@@ -558,6 +598,12 @@ static int zloop_flush(struct zloop_device *zlo)
558598
struct super_block *sb = file_inode(zlo->data_dir)->i_sb;
559599
int ret;
560600

601+
if (zlo->discard_write_cache) {
602+
ret = zloop_record_safe_wps(zlo);
603+
if (ret)
604+
return ret;
605+
}
606+
561607
down_read(&sb->s_umount);
562608
ret = sync_filesystem(sb);
563609
up_read(&sb->s_umount);
@@ -1054,6 +1100,7 @@ static int zloop_ctl_add(struct zloop_options *opts)
10541100
zlo->zone_append = opts->zone_append;
10551101
if (zlo->zone_append)
10561102
zlo->ordered_zone_append = opts->ordered_zone_append;
1103+
zlo->discard_write_cache = opts->discard_write_cache;
10571104

10581105
zlo->workqueue = alloc_workqueue("zloop%d", WQ_UNBOUND | WQ_FREEZABLE,
10591106
opts->nr_queues * opts->queue_depth, zlo->id);
@@ -1176,6 +1223,49 @@ static int zloop_ctl_add(struct zloop_options *opts)
11761223
return ret;
11771224
}
11781225

1226+
static void zloop_truncate(struct file *file, loff_t pos)
1227+
{
1228+
struct mnt_idmap *idmap = file_mnt_idmap(file);
1229+
struct dentry *dentry = file_dentry(file);
1230+
struct iattr newattrs;
1231+
1232+
newattrs.ia_size = pos;
1233+
newattrs.ia_valid = ATTR_SIZE;
1234+
1235+
inode_lock(dentry->d_inode);
1236+
notify_change(idmap, dentry, &newattrs, NULL);
1237+
inode_unlock(dentry->d_inode);
1238+
}
1239+
1240+
static void zloop_forget_cache(struct zloop_device *zlo)
1241+
{
1242+
unsigned int i;
1243+
int ret;
1244+
1245+
pr_info("%pg: discarding volatile write cache\n", zlo->disk->part0);
1246+
1247+
for (i = 0; i < zlo->nr_zones; i++) {
1248+
struct zloop_zone *zone = &zlo->zones[i];
1249+
struct file *file = zone->file;
1250+
sector_t old_wp;
1251+
1252+
if (!zloop_zone_is_active(zone))
1253+
continue;
1254+
1255+
ret = vfs_getxattr(file_mnt_idmap(file), file_dentry(file),
1256+
"user.zloop.wp", &old_wp, sizeof(old_wp));
1257+
if (ret == -ENODATA) {
1258+
old_wp = 0;
1259+
} else if (ret != sizeof(old_wp)) {
1260+
pr_err("%pg: failed to retrieve write pointer (%d)\n",
1261+
zlo->disk->part0, ret);
1262+
continue;
1263+
}
1264+
if (old_wp < zone->wp)
1265+
zloop_truncate(file, old_wp);
1266+
}
1267+
}
1268+
11791269
static int zloop_ctl_remove(struct zloop_options *opts)
11801270
{
11811271
struct zloop_device *zlo;
@@ -1210,6 +1300,10 @@ static int zloop_ctl_remove(struct zloop_options *opts)
12101300
return ret;
12111301

12121302
del_gendisk(zlo->disk);
1303+
1304+
if (zlo->discard_write_cache)
1305+
zloop_forget_cache(zlo);
1306+
12131307
put_disk(zlo->disk);
12141308

12151309
pr_info("Removed device %d\n", opts->id);
@@ -1361,6 +1455,9 @@ static int zloop_parse_options(struct zloop_options *opts, const char *buf)
13611455
case ZLOOP_OPT_ORDERED_ZONE_APPEND:
13621456
opts->ordered_zone_append = true;
13631457
break;
1458+
case ZLOOP_OPT_DISCARD_WRITE_CACHE:
1459+
opts->discard_write_cache = true;
1460+
break;
13641461
case ZLOOP_OPT_ERR:
13651462
default:
13661463
pr_warn("unknown parameter or missing value '%s'\n", p);

0 commit comments

Comments
 (0)