diff options
Diffstat (limited to 'drivers/infiniband/ulp/ipoib/ipoib_fs.c')
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_fs.c | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c new file mode 100644 index 000000000000..044f2c78ef15 --- /dev/null +++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c | |||
@@ -0,0 +1,287 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | * $Id: ipoib_fs.c 1389 2004-12-27 22:56:47Z roland $ | ||
33 | */ | ||
34 | |||
35 | #include <linux/pagemap.h> | ||
36 | #include <linux/seq_file.h> | ||
37 | |||
38 | #include "ipoib.h" | ||
39 | |||
40 | enum { | ||
41 | IPOIB_MAGIC = 0x49504942 /* "IPIB" */ | ||
42 | }; | ||
43 | |||
44 | static DECLARE_MUTEX(ipoib_fs_mutex); | ||
45 | static struct dentry *ipoib_root; | ||
46 | static struct super_block *ipoib_sb; | ||
47 | static LIST_HEAD(ipoib_device_list); | ||
48 | |||
49 | static void *ipoib_mcg_seq_start(struct seq_file *file, loff_t *pos) | ||
50 | { | ||
51 | struct ipoib_mcast_iter *iter; | ||
52 | loff_t n = *pos; | ||
53 | |||
54 | iter = ipoib_mcast_iter_init(file->private); | ||
55 | if (!iter) | ||
56 | return NULL; | ||
57 | |||
58 | while (n--) { | ||
59 | if (ipoib_mcast_iter_next(iter)) { | ||
60 | ipoib_mcast_iter_free(iter); | ||
61 | return NULL; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | return iter; | ||
66 | } | ||
67 | |||
68 | static void *ipoib_mcg_seq_next(struct seq_file *file, void *iter_ptr, | ||
69 | loff_t *pos) | ||
70 | { | ||
71 | struct ipoib_mcast_iter *iter = iter_ptr; | ||
72 | |||
73 | (*pos)++; | ||
74 | |||
75 | if (ipoib_mcast_iter_next(iter)) { | ||
76 | ipoib_mcast_iter_free(iter); | ||
77 | return NULL; | ||
78 | } | ||
79 | |||
80 | return iter; | ||
81 | } | ||
82 | |||
83 | static void ipoib_mcg_seq_stop(struct seq_file *file, void *iter_ptr) | ||
84 | { | ||
85 | /* nothing for now */ | ||
86 | } | ||
87 | |||
88 | static int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr) | ||
89 | { | ||
90 | struct ipoib_mcast_iter *iter = iter_ptr; | ||
91 | char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; | ||
92 | union ib_gid mgid; | ||
93 | int i, n; | ||
94 | unsigned long created; | ||
95 | unsigned int queuelen, complete, send_only; | ||
96 | |||
97 | if (iter) { | ||
98 | ipoib_mcast_iter_read(iter, &mgid, &created, &queuelen, | ||
99 | &complete, &send_only); | ||
100 | |||
101 | for (n = 0, i = 0; i < sizeof mgid / 2; ++i) { | ||
102 | n += sprintf(gid_buf + n, "%x", | ||
103 | be16_to_cpu(((u16 *)mgid.raw)[i])); | ||
104 | if (i < sizeof mgid / 2 - 1) | ||
105 | gid_buf[n++] = ':'; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | seq_printf(file, "GID: %*s", -(1 + (int) sizeof gid_buf), gid_buf); | ||
110 | |||
111 | seq_printf(file, | ||
112 | " created: %10ld queuelen: %4d complete: %d send_only: %d\n", | ||
113 | created, queuelen, complete, send_only); | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static struct seq_operations ipoib_seq_ops = { | ||
119 | .start = ipoib_mcg_seq_start, | ||
120 | .next = ipoib_mcg_seq_next, | ||
121 | .stop = ipoib_mcg_seq_stop, | ||
122 | .show = ipoib_mcg_seq_show, | ||
123 | }; | ||
124 | |||
125 | static int ipoib_mcg_open(struct inode *inode, struct file *file) | ||
126 | { | ||
127 | struct seq_file *seq; | ||
128 | int ret; | ||
129 | |||
130 | ret = seq_open(file, &ipoib_seq_ops); | ||
131 | if (ret) | ||
132 | return ret; | ||
133 | |||
134 | seq = file->private_data; | ||
135 | seq->private = inode->u.generic_ip; | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static struct file_operations ipoib_fops = { | ||
141 | .owner = THIS_MODULE, | ||
142 | .open = ipoib_mcg_open, | ||
143 | .read = seq_read, | ||
144 | .llseek = seq_lseek, | ||
145 | .release = seq_release | ||
146 | }; | ||
147 | |||
148 | static struct inode *ipoib_get_inode(void) | ||
149 | { | ||
150 | struct inode *inode = new_inode(ipoib_sb); | ||
151 | |||
152 | if (inode) { | ||
153 | inode->i_mode = S_IFREG | S_IRUGO; | ||
154 | inode->i_uid = 0; | ||
155 | inode->i_gid = 0; | ||
156 | inode->i_blksize = PAGE_CACHE_SIZE; | ||
157 | inode->i_blocks = 0; | ||
158 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
159 | inode->i_fop = &ipoib_fops; | ||
160 | } | ||
161 | |||
162 | return inode; | ||
163 | } | ||
164 | |||
165 | static int __ipoib_create_debug_file(struct net_device *dev) | ||
166 | { | ||
167 | struct ipoib_dev_priv *priv = netdev_priv(dev); | ||
168 | struct dentry *dentry; | ||
169 | struct inode *inode; | ||
170 | char name[IFNAMSIZ + sizeof "_mcg"]; | ||
171 | |||
172 | snprintf(name, sizeof name, "%s_mcg", dev->name); | ||
173 | |||
174 | dentry = d_alloc_name(ipoib_root, name); | ||
175 | if (!dentry) | ||
176 | return -ENOMEM; | ||
177 | |||
178 | inode = ipoib_get_inode(); | ||
179 | if (!inode) { | ||
180 | dput(dentry); | ||
181 | return -ENOMEM; | ||
182 | } | ||
183 | |||
184 | inode->u.generic_ip = dev; | ||
185 | priv->mcg_dentry = dentry; | ||
186 | |||
187 | d_add(dentry, inode); | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | int ipoib_create_debug_file(struct net_device *dev) | ||
193 | { | ||
194 | struct ipoib_dev_priv *priv = netdev_priv(dev); | ||
195 | |||
196 | down(&ipoib_fs_mutex); | ||
197 | |||
198 | list_add_tail(&priv->fs_list, &ipoib_device_list); | ||
199 | |||
200 | if (!ipoib_sb) { | ||
201 | up(&ipoib_fs_mutex); | ||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | up(&ipoib_fs_mutex); | ||
206 | |||
207 | return __ipoib_create_debug_file(dev); | ||
208 | } | ||
209 | |||
210 | void ipoib_delete_debug_file(struct net_device *dev) | ||
211 | { | ||
212 | struct ipoib_dev_priv *priv = netdev_priv(dev); | ||
213 | |||
214 | down(&ipoib_fs_mutex); | ||
215 | list_del(&priv->fs_list); | ||
216 | if (!ipoib_sb) { | ||
217 | up(&ipoib_fs_mutex); | ||
218 | return; | ||
219 | } | ||
220 | up(&ipoib_fs_mutex); | ||
221 | |||
222 | if (priv->mcg_dentry) { | ||
223 | d_drop(priv->mcg_dentry); | ||
224 | simple_unlink(ipoib_root->d_inode, priv->mcg_dentry); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | static int ipoib_fill_super(struct super_block *sb, void *data, int silent) | ||
229 | { | ||
230 | static struct tree_descr ipoib_files[] = { | ||
231 | { "" } | ||
232 | }; | ||
233 | struct ipoib_dev_priv *priv; | ||
234 | int ret; | ||
235 | |||
236 | ret = simple_fill_super(sb, IPOIB_MAGIC, ipoib_files); | ||
237 | if (ret) | ||
238 | return ret; | ||
239 | |||
240 | ipoib_root = sb->s_root; | ||
241 | |||
242 | down(&ipoib_fs_mutex); | ||
243 | |||
244 | ipoib_sb = sb; | ||
245 | |||
246 | list_for_each_entry(priv, &ipoib_device_list, fs_list) { | ||
247 | ret = __ipoib_create_debug_file(priv->dev); | ||
248 | if (ret) | ||
249 | break; | ||
250 | } | ||
251 | |||
252 | up(&ipoib_fs_mutex); | ||
253 | |||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | static struct super_block *ipoib_get_sb(struct file_system_type *fs_type, | ||
258 | int flags, const char *dev_name, void *data) | ||
259 | { | ||
260 | return get_sb_single(fs_type, flags, data, ipoib_fill_super); | ||
261 | } | ||
262 | |||
263 | static void ipoib_kill_sb(struct super_block *sb) | ||
264 | { | ||
265 | down(&ipoib_fs_mutex); | ||
266 | ipoib_sb = NULL; | ||
267 | up(&ipoib_fs_mutex); | ||
268 | |||
269 | kill_litter_super(sb); | ||
270 | } | ||
271 | |||
272 | static struct file_system_type ipoib_fs_type = { | ||
273 | .owner = THIS_MODULE, | ||
274 | .name = "ipoib_debugfs", | ||
275 | .get_sb = ipoib_get_sb, | ||
276 | .kill_sb = ipoib_kill_sb, | ||
277 | }; | ||
278 | |||
279 | int ipoib_register_debugfs(void) | ||
280 | { | ||
281 | return register_filesystem(&ipoib_fs_type); | ||
282 | } | ||
283 | |||
284 | void ipoib_unregister_debugfs(void) | ||
285 | { | ||
286 | unregister_filesystem(&ipoib_fs_type); | ||
287 | } | ||