18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Feature set bits and string conversion.
48c2ecf20Sopenharmony_ci * Inspired by ext4's features compat/incompat/ro_compat related code.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright 2020 Coly Li <colyli@suse.de>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/bcache.h>
108c2ecf20Sopenharmony_ci#include "bcache.h"
118c2ecf20Sopenharmony_ci#include "features.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistruct feature {
148c2ecf20Sopenharmony_ci	int		compat;
158c2ecf20Sopenharmony_ci	unsigned int	mask;
168c2ecf20Sopenharmony_ci	const char	*string;
178c2ecf20Sopenharmony_ci};
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic struct feature feature_list[] = {
208c2ecf20Sopenharmony_ci	{BCH_FEATURE_INCOMPAT, BCH_FEATURE_INCOMPAT_LOG_LARGE_BUCKET_SIZE,
218c2ecf20Sopenharmony_ci		"large_bucket"},
228c2ecf20Sopenharmony_ci	{0, 0, 0 },
238c2ecf20Sopenharmony_ci};
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define compose_feature_string(type)				\
268c2ecf20Sopenharmony_ci({									\
278c2ecf20Sopenharmony_ci	struct feature *f;						\
288c2ecf20Sopenharmony_ci	bool first = true;						\
298c2ecf20Sopenharmony_ci									\
308c2ecf20Sopenharmony_ci	for (f = &feature_list[0]; f->compat != 0; f++) {		\
318c2ecf20Sopenharmony_ci		if (f->compat != BCH_FEATURE_ ## type)			\
328c2ecf20Sopenharmony_ci			continue;					\
338c2ecf20Sopenharmony_ci		if (BCH_HAS_ ## type ## _FEATURE(&c->cache->sb, f->mask)) {	\
348c2ecf20Sopenharmony_ci			if (first) {					\
358c2ecf20Sopenharmony_ci				out += snprintf(out, buf + size - out,	\
368c2ecf20Sopenharmony_ci						"[");	\
378c2ecf20Sopenharmony_ci			} else {					\
388c2ecf20Sopenharmony_ci				out += snprintf(out, buf + size - out,	\
398c2ecf20Sopenharmony_ci						" [");			\
408c2ecf20Sopenharmony_ci			}						\
418c2ecf20Sopenharmony_ci		} else if (!first) {					\
428c2ecf20Sopenharmony_ci			out += snprintf(out, buf + size - out, " ");	\
438c2ecf20Sopenharmony_ci		}							\
448c2ecf20Sopenharmony_ci									\
458c2ecf20Sopenharmony_ci		out += snprintf(out, buf + size - out, "%s", f->string);\
468c2ecf20Sopenharmony_ci									\
478c2ecf20Sopenharmony_ci		if (BCH_HAS_ ## type ## _FEATURE(&c->cache->sb, f->mask))	\
488c2ecf20Sopenharmony_ci			out += snprintf(out, buf + size - out, "]");	\
498c2ecf20Sopenharmony_ci									\
508c2ecf20Sopenharmony_ci		first = false;						\
518c2ecf20Sopenharmony_ci	}								\
528c2ecf20Sopenharmony_ci	if (!first)							\
538c2ecf20Sopenharmony_ci		out += snprintf(out, buf + size - out, "\n");		\
548c2ecf20Sopenharmony_ci})
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ciint bch_print_cache_set_feature_compat(struct cache_set *c, char *buf, int size)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	char *out = buf;
598c2ecf20Sopenharmony_ci	compose_feature_string(COMPAT);
608c2ecf20Sopenharmony_ci	return out - buf;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ciint bch_print_cache_set_feature_ro_compat(struct cache_set *c, char *buf, int size)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	char *out = buf;
668c2ecf20Sopenharmony_ci	compose_feature_string(RO_COMPAT);
678c2ecf20Sopenharmony_ci	return out - buf;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ciint bch_print_cache_set_feature_incompat(struct cache_set *c, char *buf, int size)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	char *out = buf;
738c2ecf20Sopenharmony_ci	compose_feature_string(INCOMPAT);
748c2ecf20Sopenharmony_ci	return out - buf;
758c2ecf20Sopenharmony_ci}
76