18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (C) 2008 Red Hat, Inc. All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is released under the GPL.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/sysfs.h>
88c2ecf20Sopenharmony_ci#include <linux/dm-ioctl.h>
98c2ecf20Sopenharmony_ci#include "dm-core.h"
108c2ecf20Sopenharmony_ci#include "dm-rq.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistruct dm_sysfs_attr {
138c2ecf20Sopenharmony_ci	struct attribute attr;
148c2ecf20Sopenharmony_ci	ssize_t (*show)(struct mapped_device *, char *);
158c2ecf20Sopenharmony_ci	ssize_t (*store)(struct mapped_device *, const char *, size_t count);
168c2ecf20Sopenharmony_ci};
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define DM_ATTR_RO(_name) \
198c2ecf20Sopenharmony_cistruct dm_sysfs_attr dm_attr_##_name = \
208c2ecf20Sopenharmony_ci	__ATTR(_name, S_IRUGO, dm_attr_##_name##_show, NULL)
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic ssize_t dm_attr_show(struct kobject *kobj, struct attribute *attr,
238c2ecf20Sopenharmony_ci			    char *page)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	struct dm_sysfs_attr *dm_attr;
268c2ecf20Sopenharmony_ci	struct mapped_device *md;
278c2ecf20Sopenharmony_ci	ssize_t ret;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	dm_attr = container_of(attr, struct dm_sysfs_attr, attr);
308c2ecf20Sopenharmony_ci	if (!dm_attr->show)
318c2ecf20Sopenharmony_ci		return -EIO;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	md = dm_get_from_kobject(kobj);
348c2ecf20Sopenharmony_ci	if (!md)
358c2ecf20Sopenharmony_ci		return -EINVAL;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	ret = dm_attr->show(md, page);
388c2ecf20Sopenharmony_ci	dm_put(md);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	return ret;
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define DM_ATTR_RW(_name) \
448c2ecf20Sopenharmony_cistruct dm_sysfs_attr dm_attr_##_name = \
458c2ecf20Sopenharmony_ci	__ATTR(_name, S_IRUGO | S_IWUSR, dm_attr_##_name##_show, dm_attr_##_name##_store)
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic ssize_t dm_attr_store(struct kobject *kobj, struct attribute *attr,
488c2ecf20Sopenharmony_ci			     const char *page, size_t count)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	struct dm_sysfs_attr *dm_attr;
518c2ecf20Sopenharmony_ci	struct mapped_device *md;
528c2ecf20Sopenharmony_ci	ssize_t ret;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	dm_attr = container_of(attr, struct dm_sysfs_attr, attr);
558c2ecf20Sopenharmony_ci	if (!dm_attr->store)
568c2ecf20Sopenharmony_ci		return -EIO;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	md = dm_get_from_kobject(kobj);
598c2ecf20Sopenharmony_ci	if (!md)
608c2ecf20Sopenharmony_ci		return -EINVAL;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	ret = dm_attr->store(md, page, count);
638c2ecf20Sopenharmony_ci	dm_put(md);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	return ret;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic ssize_t dm_attr_name_show(struct mapped_device *md, char *buf)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	if (dm_copy_name_and_uuid(md, buf, NULL))
718c2ecf20Sopenharmony_ci		return -EIO;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	strcat(buf, "\n");
748c2ecf20Sopenharmony_ci	return strlen(buf);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic ssize_t dm_attr_uuid_show(struct mapped_device *md, char *buf)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	if (dm_copy_name_and_uuid(md, NULL, buf))
808c2ecf20Sopenharmony_ci		return -EIO;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	strcat(buf, "\n");
838c2ecf20Sopenharmony_ci	return strlen(buf);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic ssize_t dm_attr_suspended_show(struct mapped_device *md, char *buf)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	sprintf(buf, "%d\n", dm_suspended_md(md));
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	return strlen(buf);
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic ssize_t dm_attr_use_blk_mq_show(struct mapped_device *md, char *buf)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	/* Purely for userspace compatibility */
968c2ecf20Sopenharmony_ci	sprintf(buf, "%d\n", true);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return strlen(buf);
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic DM_ATTR_RO(name);
1028c2ecf20Sopenharmony_cistatic DM_ATTR_RO(uuid);
1038c2ecf20Sopenharmony_cistatic DM_ATTR_RO(suspended);
1048c2ecf20Sopenharmony_cistatic DM_ATTR_RO(use_blk_mq);
1058c2ecf20Sopenharmony_cistatic DM_ATTR_RW(rq_based_seq_io_merge_deadline);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic struct attribute *dm_attrs[] = {
1088c2ecf20Sopenharmony_ci	&dm_attr_name.attr,
1098c2ecf20Sopenharmony_ci	&dm_attr_uuid.attr,
1108c2ecf20Sopenharmony_ci	&dm_attr_suspended.attr,
1118c2ecf20Sopenharmony_ci	&dm_attr_use_blk_mq.attr,
1128c2ecf20Sopenharmony_ci	&dm_attr_rq_based_seq_io_merge_deadline.attr,
1138c2ecf20Sopenharmony_ci	NULL,
1148c2ecf20Sopenharmony_ci};
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic const struct sysfs_ops dm_sysfs_ops = {
1178c2ecf20Sopenharmony_ci	.show	= dm_attr_show,
1188c2ecf20Sopenharmony_ci	.store	= dm_attr_store,
1198c2ecf20Sopenharmony_ci};
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic struct kobj_type dm_ktype = {
1228c2ecf20Sopenharmony_ci	.sysfs_ops	= &dm_sysfs_ops,
1238c2ecf20Sopenharmony_ci	.default_attrs	= dm_attrs,
1248c2ecf20Sopenharmony_ci	.release	= dm_kobject_release,
1258c2ecf20Sopenharmony_ci};
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/*
1288c2ecf20Sopenharmony_ci * Initialize kobj
1298c2ecf20Sopenharmony_ci * because nobody using md yet, no need to call explicit dm_get/put
1308c2ecf20Sopenharmony_ci */
1318c2ecf20Sopenharmony_ciint dm_sysfs_init(struct mapped_device *md)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	return kobject_init_and_add(dm_kobject(md), &dm_ktype,
1348c2ecf20Sopenharmony_ci				    &disk_to_dev(dm_disk(md))->kobj,
1358c2ecf20Sopenharmony_ci				    "%s", "dm");
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/*
1398c2ecf20Sopenharmony_ci * Remove kobj, called after all references removed
1408c2ecf20Sopenharmony_ci */
1418c2ecf20Sopenharmony_civoid dm_sysfs_exit(struct mapped_device *md)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	struct kobject *kobj = dm_kobject(md);
1448c2ecf20Sopenharmony_ci	kobject_put(kobj);
1458c2ecf20Sopenharmony_ci	wait_for_completion(dm_get_completion_from_kobject(kobj));
1468c2ecf20Sopenharmony_ci}
147