summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch
blob: 41969349e2474769318a2f95203e04ae14e75377 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
From 5c82e0b33f2a373d5e19569635f108cfa096f53e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adrian=20Ambro=C5=BCewicz?= <adrian.ambrozewicz@intel.com>
Date: Mon, 29 Jul 2019 10:19:00 +0200
Subject: [PATCH] Add IO stats to USB Mass Storage gadget
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Introduces new attribute to Mass Storage Gadget ConfigFS : stats.
It's read-only attribute which contains statistics of read/write operations
based on LUN transaction counters (IO number and bytes transferred).

Goal is to provide a way to observe whether simulated device is actually
used by host. Statistics on hosted file / nbd level are not always viable
due to page cache having severe impact on actual IO statistics.
This attribute should provide information about host IO on USB Gadget as
close to endpoint as possible.

Attribute is tied completely to configFS implementation and it's lifecycle
is managed by Kernel and user. Driver implements a handler which populates
output buffer on read.

Tests performed:
- mounted USB Mass Storage gadget, new attribute showed up in gadget tree
- attribute was monitored for changes during IO performed on host machine
- removed device, attribute (along with other device attributes) was gone

Signed-off-by: Adrian Ambrożewicz <adrian.ambrozewicz@intel.com>
---
 drivers/usb/gadget/function/f_mass_storage.c | 12 ++++++++++++
 drivers/usb/gadget/function/storage_common.c |  9 +++++++++
 drivers/usb/gadget/function/storage_common.h | 29 ++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+)

diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 7c96c4665178..ecc3c68a7882 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -710,6 +710,8 @@ static int do_read(struct fsg_common *common)
 		amount_left  -= nread;
 		common->residue -= nread;
 
+		fsg_stats_rd_attempt(&curlun->stats, nread);
+
 		/*
 		 * Except at the end of the transfer, nread will be
 		 * equal to the buffer size, which is divisible by the
@@ -907,6 +909,8 @@ static int do_write(struct fsg_common *common)
 		amount_left_to_write -= nwritten;
 		common->residue -= nwritten;
 
+		fsg_stats_wr_attempt(&curlun->stats, nwritten);
+
 		/* If an error occurred, report it and its position */
 		if (nwritten < amount) {
 			curlun->sense_data = SS_WRITE_ERROR;
@@ -3122,6 +3126,13 @@ static ssize_t fsg_lun_opts_inquiry_string_store(struct config_item *item,
 
 CONFIGFS_ATTR(fsg_lun_opts_, inquiry_string);
 
+static ssize_t fsg_lun_opts_stats_show(struct config_item *item, char *page)
+{
+	return fsg_show_stats(to_fsg_lun_opts(item)->lun, page);
+}
+
+CONFIGFS_ATTR_RO(fsg_lun_opts_, stats);
+
 static struct configfs_attribute *fsg_lun_attrs[] = {
 	&fsg_lun_opts_attr_file,
 	&fsg_lun_opts_attr_ro,
@@ -3129,6 +3140,7 @@ static struct configfs_attribute *fsg_lun_attrs[] = {
 	&fsg_lun_opts_attr_cdrom,
 	&fsg_lun_opts_attr_nofua,
 	&fsg_lun_opts_attr_inquiry_string,
+	&fsg_lun_opts_attr_stats,
 	NULL,
 };
 
diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c
index f7e6c42558eb..2325b97961df 100644
--- a/drivers/usb/gadget/function/storage_common.c
+++ b/drivers/usb/gadget/function/storage_common.c
@@ -371,6 +371,15 @@ ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf)
 }
 EXPORT_SYMBOL_GPL(fsg_show_inquiry_string);
 
+ssize_t fsg_show_stats(struct fsg_lun *curlun, char *buf)
+{
+	return sprintf(buf, "read cnt: %u\n" "read sum: %llu\n"
+		       "write cnt: %u\n" "write sum: %llu\n",
+		       curlun->stats.read.count, curlun->stats.read.bytes,
+		       curlun->stats.write.count, curlun->stats.write.bytes);
+}
+EXPORT_SYMBOL_GPL(fsg_show_stats);
+
 /*
  * The caller must hold fsg->filesem for reading when calling this function.
  */
diff --git a/drivers/usb/gadget/function/storage_common.h b/drivers/usb/gadget/function/storage_common.h
index e5e3a2553aaa..447021ba821a 100644
--- a/drivers/usb/gadget/function/storage_common.h
+++ b/drivers/usb/gadget/function/storage_common.h
@@ -95,6 +95,32 @@ do {									\
  */
 #define INQUIRY_STRING_LEN ((size_t) (8 + 16 + 4 + 1))
 
+struct fsg_stats_cnt {
+	u64 bytes;
+	u32 count;
+};
+
+struct fsg_stats {
+	struct fsg_stats_cnt read;
+	struct fsg_stats_cnt write;
+};
+
+static inline void fsg_stats_update(struct fsg_stats_cnt *cnt, u64 diff)
+{
+	cnt->count++;
+	cnt->bytes += diff;
+}
+
+static inline void fsg_stats_wr_attempt(struct fsg_stats *stats, u64 b_written)
+{
+	fsg_stats_update(&stats->write, b_written);
+}
+
+static inline void fsg_stats_rd_attempt(struct fsg_stats *stats, u64 b_read)
+{
+	fsg_stats_update(&stats->read, b_read);
+}
+
 struct fsg_lun {
 	struct file	*filp;
 	loff_t		file_length;
@@ -120,6 +146,8 @@ struct fsg_lun {
 	const char	*name;		/* "lun.name" */
 	const char	**name_pfx;	/* "function.name" */
 	char		inquiry_string[INQUIRY_STRING_LEN];
+
+	struct fsg_stats	stats;
 };
 
 static inline bool fsg_lun_is_open(struct fsg_lun *curlun)
@@ -213,6 +241,7 @@ ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
 ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf);
 ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf);
 ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf);
+ssize_t fsg_show_stats(struct fsg_lun *curlun, char *buf);
 ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem,
 		     const char *buf, size_t count);
 ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count);
-- 
2.7.4