On 2/18/19 3:04 PM, Mariusz Dabrowski wrote: > When the Partial Parity Log is enabled, circular buffer is used to store > PPL data. Each write to RAID device causes overwrite of data in this buffer > so some write_hint can be set to those request to help drives handle > garbage collection. This patch adds new sysfs attribute which can be used > to specify which write_hint should be assigned to PPL. > > Signed-off-by: Mariusz Dabrowski <mariusz.dabrowski@xxxxxxxxx> > --- > v2: moved ppl_write_hint releated stuff from raid5.c to raid5-ppl.c > > Documentation/admin-guide/md.rst | 3 ++ > drivers/md/raid5-log.h | 1 + > drivers/md/raid5-ppl.c | 63 ++++++++++++++++++++++++++++++++++++++++ > drivers/md/raid5.c | 1 + > 4 files changed, 68 insertions(+) > > diff --git a/Documentation/admin-guide/md.rst b/Documentation/admin-guide/md.rst > index 84de718f24a4..3c51084ffd37 100644 > --- a/Documentation/admin-guide/md.rst > +++ b/Documentation/admin-guide/md.rst > @@ -756,3 +756,6 @@ These currently include: > The cache mode for raid5. raid5 could include an extra disk for > caching. The mode can be "write-throuth" and "write-back". The > default is "write-through". > + > + ppl_write_hint > + NVMe stream ID to be set for each PPL write request. > diff --git a/drivers/md/raid5-log.h b/drivers/md/raid5-log.h > index bfb811407061..43c714a8798c 100644 > --- a/drivers/md/raid5-log.h > +++ b/drivers/md/raid5-log.h > @@ -45,6 +45,7 @@ extern void ppl_stripe_write_finished(struct stripe_head *sh); > extern int ppl_modify_log(struct r5conf *conf, struct md_rdev *rdev, bool add); > extern void ppl_quiesce(struct r5conf *conf, int quiesce); > extern int ppl_handle_flush_request(struct r5l_log *log, struct bio *bio); > +extern struct md_sysfs_entry ppl_write_hint; > > static inline bool raid5_has_log(struct r5conf *conf) > { > diff --git a/drivers/md/raid5-ppl.c b/drivers/md/raid5-ppl.c > index 3a7c36326589..f2b3020c2ac8 100644 > --- a/drivers/md/raid5-ppl.c > +++ b/drivers/md/raid5-ppl.c > @@ -21,6 +21,7 @@ > #include <linux/raid/md_p.h> > #include "md.h" > #include "raid5.h" > +#include "raid5-log.h" > > /* > * PPL consists of a 4KB header (struct ppl_header) and at least 128KB for > @@ -116,6 +117,8 @@ struct ppl_conf { > /* stripes to retry if failed to allocate io_unit */ > struct list_head no_mem_stripes; > spinlock_t no_mem_stripes_lock; > + > + unsigned short write_hint; > }; > > struct ppl_log { > @@ -476,6 +479,7 @@ static void ppl_submit_iounit(struct ppl_io_unit *io) > bio_set_dev(bio, log->rdev->bdev); > bio->bi_iter.bi_sector = log->next_io_sector; > bio_add_page(bio, io->header_page, PAGE_SIZE, 0); > + bio->bi_write_hint = ppl_conf->write_hint; > > pr_debug("%s: log->current_io_sector: %llu\n", __func__, > (unsigned long long)log->next_io_sector); > @@ -505,6 +509,7 @@ static void ppl_submit_iounit(struct ppl_io_unit *io) > bio = bio_alloc_bioset(GFP_NOIO, BIO_MAX_PAGES, > &ppl_conf->bs); > bio->bi_opf = prev->bi_opf; > + bio->bi_write_hint = prev->bi_write_hint; > bio_copy_dev(bio, prev); > bio->bi_iter.bi_sector = bio_end_sector(prev); > bio_add_page(bio, sh->ppl_page, PAGE_SIZE, 0); > @@ -1409,6 +1414,7 @@ int ppl_init_log(struct r5conf *conf) > atomic64_set(&ppl_conf->seq, 0); > INIT_LIST_HEAD(&ppl_conf->no_mem_stripes); > spin_lock_init(&ppl_conf->no_mem_stripes_lock); > + ppl_conf->write_hint = RWF_WRITE_LIFE_NOT_SET; > > if (!mddev->external) { > ppl_conf->signature = ~crc32c_le(~0, mddev->uuid, sizeof(mddev->uuid)); > @@ -1503,3 +1509,60 @@ int ppl_modify_log(struct r5conf *conf, struct md_rdev *rdev, bool add) > > return ret; > } > + > +static ssize_t > +ppl_write_hint_show(struct mddev *mddev, char *buf) > +{ > + size_t ret = 0; > + struct r5conf *conf; > + struct ppl_conf *ppl_conf = NULL; > + > + spin_lock(&mddev->lock); > + conf = mddev->private; > + if (conf && raid5_has_ppl(conf)) > + ppl_conf = conf->log_private; > + ret = sprintf(buf, "%d\n", ppl_conf ? ppl_conf->write_hint : 0); > + spin_unlock(&mddev->lock); > + > + return ret; > +} > + > +static ssize_t > +ppl_write_hint_store(struct mddev *mddev, const char *page, size_t len) > +{ > + struct r5conf *conf; > + struct ppl_conf *ppl_conf; > + int err = 0; > + unsigned short new; > + > + if (len >= PAGE_SIZE) > + return -EINVAL; > + if (kstrtou16(page, 10, &new)) > + return -EINVAL; > + > + err = mddev_lock(mddev); > + if (err) > + return err; > + > + conf = mddev->private; > + if (!conf) { > + err = -ENODEV; > + } else if (raid5_has_ppl(conf)) { > + ppl_conf = conf->log_private; > + if (!ppl_conf) > + err = -EINVAL; > + else > + ppl_conf->write_hint = new; > + } else { > + err = -EINVAL; > + } > + > + mddev_unlock(mddev); > + > + return err ?: len; > +} > + > +struct md_sysfs_entry > +ppl_write_hint = __ATTR(ppl_write_hint, S_IRUGO | S_IWUSR, > + ppl_write_hint_show, > + ppl_write_hint_store); > diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c > index cecea901ab8c..09562d7cc080 100644 > --- a/drivers/md/raid5.c > +++ b/drivers/md/raid5.c > @@ -6660,6 +6660,7 @@ static struct attribute *raid5_attrs[] = { > &raid5_skip_copy.attr, > &raid5_rmw_level.attr, > &r5c_journal_mode.attr, > + &ppl_write_hint.attr, > NULL, > }; > static struct attribute_group raid5_attrs_group = { > Ping