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.
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
3941static 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+
11791269static 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