Commit | Line | Data |
---|---|---|
f931551b | 1 | /* |
7fac3301 MM |
2 | * Copyright (c) 2012 Intel Corporation. All rights reserved. |
3 | * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved. | |
f931551b RC |
4 | * Copyright (c) 2006 PathScale, Inc. All rights reserved. |
5 | * | |
6 | * This software is available to you under a choice of one of two | |
7 | * licenses. You may choose to be licensed under the terms of the GNU | |
8 | * General Public License (GPL) Version 2, available from the file | |
9 | * COPYING in the main directory of this source tree, or the | |
10 | * OpenIB.org BSD license below: | |
11 | * | |
12 | * Redistribution and use in source and binary forms, with or | |
13 | * without modification, are permitted provided that the following | |
14 | * conditions are met: | |
15 | * | |
16 | * - Redistributions of source code must retain the above | |
17 | * copyright notice, this list of conditions and the following | |
18 | * disclaimer. | |
19 | * | |
20 | * - Redistributions in binary form must reproduce the above | |
21 | * copyright notice, this list of conditions and the following | |
22 | * disclaimer in the documentation and/or other materials | |
23 | * provided with the distribution. | |
24 | * | |
25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
32 | * SOFTWARE. | |
33 | */ | |
34 | ||
35 | #include <linux/module.h> | |
36 | #include <linux/fs.h> | |
37 | #include <linux/mount.h> | |
38 | #include <linux/pagemap.h> | |
39 | #include <linux/init.h> | |
40 | #include <linux/namei.h> | |
41 | ||
42 | #include "qib.h" | |
43 | ||
44 | #define QIBFS_MAGIC 0x726a77 | |
45 | ||
46 | static struct super_block *qib_super; | |
47 | ||
496ad9aa | 48 | #define private2dd(file) (file_inode(file)->i_private) |
f931551b RC |
49 | |
50 | static int qibfs_mknod(struct inode *dir, struct dentry *dentry, | |
f9ec8006 | 51 | umode_t mode, const struct file_operations *fops, |
f931551b RC |
52 | void *data) |
53 | { | |
54 | int error; | |
55 | struct inode *inode = new_inode(dir->i_sb); | |
56 | ||
57 | if (!inode) { | |
58 | error = -EPERM; | |
59 | goto bail; | |
60 | } | |
61 | ||
85fe4025 | 62 | inode->i_ino = get_next_ino(); |
f931551b | 63 | inode->i_mode = mode; |
d03ca582 EB |
64 | inode->i_uid = GLOBAL_ROOT_UID; |
65 | inode->i_gid = GLOBAL_ROOT_GID; | |
f931551b RC |
66 | inode->i_blocks = 0; |
67 | inode->i_atime = CURRENT_TIME; | |
68 | inode->i_mtime = inode->i_atime; | |
69 | inode->i_ctime = inode->i_atime; | |
70 | inode->i_private = data; | |
f9ec8006 | 71 | if (S_ISDIR(mode)) { |
f931551b RC |
72 | inode->i_op = &simple_dir_inode_operations; |
73 | inc_nlink(inode); | |
74 | inc_nlink(dir); | |
75 | } | |
76 | ||
77 | inode->i_fop = fops; | |
78 | ||
79 | d_instantiate(dentry, inode); | |
80 | error = 0; | |
81 | ||
82 | bail: | |
83 | return error; | |
84 | } | |
85 | ||
f9ec8006 | 86 | static int create_file(const char *name, umode_t mode, |
f931551b RC |
87 | struct dentry *parent, struct dentry **dentry, |
88 | const struct file_operations *fops, void *data) | |
89 | { | |
90 | int error; | |
91 | ||
f931551b RC |
92 | mutex_lock(&parent->d_inode->i_mutex); |
93 | *dentry = lookup_one_len(name, parent, strlen(name)); | |
94 | if (!IS_ERR(*dentry)) | |
95 | error = qibfs_mknod(parent->d_inode, *dentry, | |
96 | mode, fops, data); | |
97 | else | |
98 | error = PTR_ERR(*dentry); | |
99 | mutex_unlock(&parent->d_inode->i_mutex); | |
100 | ||
101 | return error; | |
102 | } | |
103 | ||
104 | static ssize_t driver_stats_read(struct file *file, char __user *buf, | |
105 | size_t count, loff_t *ppos) | |
106 | { | |
1ed88dd7 | 107 | qib_stats.sps_ints = qib_sps_ints(); |
f931551b | 108 | return simple_read_from_buffer(buf, count, ppos, &qib_stats, |
041af0bb | 109 | sizeof(qib_stats)); |
f931551b RC |
110 | } |
111 | ||
112 | /* | |
113 | * driver stats field names, one line per stat, single string. Used by | |
114 | * programs like ipathstats to print the stats in a way which works for | |
115 | * different versions of drivers, without changing program source. | |
116 | * if qlogic_ib_stats changes, this needs to change. Names need to be | |
117 | * 12 chars or less (w/o newline), for proper display by ipathstats utility. | |
118 | */ | |
119 | static const char qib_statnames[] = | |
120 | "KernIntr\n" | |
121 | "ErrorIntr\n" | |
122 | "Tx_Errs\n" | |
123 | "Rcv_Errs\n" | |
124 | "H/W_Errs\n" | |
125 | "NoPIOBufs\n" | |
126 | "CtxtsOpen\n" | |
127 | "RcvLen_Errs\n" | |
128 | "EgrBufFull\n" | |
129 | "EgrHdrFull\n" | |
130 | ; | |
131 | ||
132 | static ssize_t driver_names_read(struct file *file, char __user *buf, | |
133 | size_t count, loff_t *ppos) | |
134 | { | |
135 | return simple_read_from_buffer(buf, count, ppos, qib_statnames, | |
041af0bb | 136 | sizeof(qib_statnames) - 1); /* no null */ |
f931551b RC |
137 | } |
138 | ||
139 | static const struct file_operations driver_ops[] = { | |
dd378c21 AB |
140 | { .read = driver_stats_read, .llseek = generic_file_llseek, }, |
141 | { .read = driver_names_read, .llseek = generic_file_llseek, }, | |
f931551b RC |
142 | }; |
143 | ||
144 | /* read the per-device counters */ | |
145 | static ssize_t dev_counters_read(struct file *file, char __user *buf, | |
146 | size_t count, loff_t *ppos) | |
147 | { | |
148 | u64 *counters; | |
f27ec1d6 | 149 | size_t avail; |
f931551b RC |
150 | struct qib_devdata *dd = private2dd(file); |
151 | ||
f27ec1d6 RD |
152 | avail = dd->f_read_cntrs(dd, *ppos, NULL, &counters); |
153 | return simple_read_from_buffer(buf, count, ppos, counters, avail); | |
f931551b RC |
154 | } |
155 | ||
156 | /* read the per-device counters */ | |
157 | static ssize_t dev_names_read(struct file *file, char __user *buf, | |
158 | size_t count, loff_t *ppos) | |
159 | { | |
160 | char *names; | |
f27ec1d6 | 161 | size_t avail; |
f931551b RC |
162 | struct qib_devdata *dd = private2dd(file); |
163 | ||
f27ec1d6 RD |
164 | avail = dd->f_read_cntrs(dd, *ppos, &names, NULL); |
165 | return simple_read_from_buffer(buf, count, ppos, names, avail); | |
f931551b RC |
166 | } |
167 | ||
168 | static const struct file_operations cntr_ops[] = { | |
dd378c21 AB |
169 | { .read = dev_counters_read, .llseek = generic_file_llseek, }, |
170 | { .read = dev_names_read, .llseek = generic_file_llseek, }, | |
f931551b RC |
171 | }; |
172 | ||
173 | /* | |
496ad9aa | 174 | * Could use file_inode(file)->i_ino to figure out which file, |
f931551b RC |
175 | * instead of separate routine for each, but for now, this works... |
176 | */ | |
177 | ||
178 | /* read the per-port names (same for each port) */ | |
179 | static ssize_t portnames_read(struct file *file, char __user *buf, | |
180 | size_t count, loff_t *ppos) | |
181 | { | |
182 | char *names; | |
f27ec1d6 | 183 | size_t avail; |
f931551b RC |
184 | struct qib_devdata *dd = private2dd(file); |
185 | ||
f27ec1d6 RD |
186 | avail = dd->f_read_portcntrs(dd, *ppos, 0, &names, NULL); |
187 | return simple_read_from_buffer(buf, count, ppos, names, avail); | |
f931551b RC |
188 | } |
189 | ||
190 | /* read the per-port counters for port 1 (pidx 0) */ | |
191 | static ssize_t portcntrs_1_read(struct file *file, char __user *buf, | |
192 | size_t count, loff_t *ppos) | |
193 | { | |
194 | u64 *counters; | |
f27ec1d6 | 195 | size_t avail; |
f931551b RC |
196 | struct qib_devdata *dd = private2dd(file); |
197 | ||
f27ec1d6 RD |
198 | avail = dd->f_read_portcntrs(dd, *ppos, 0, NULL, &counters); |
199 | return simple_read_from_buffer(buf, count, ppos, counters, avail); | |
f931551b RC |
200 | } |
201 | ||
202 | /* read the per-port counters for port 2 (pidx 1) */ | |
203 | static ssize_t portcntrs_2_read(struct file *file, char __user *buf, | |
204 | size_t count, loff_t *ppos) | |
205 | { | |
206 | u64 *counters; | |
f27ec1d6 | 207 | size_t avail; |
f931551b RC |
208 | struct qib_devdata *dd = private2dd(file); |
209 | ||
f27ec1d6 RD |
210 | avail = dd->f_read_portcntrs(dd, *ppos, 1, NULL, &counters); |
211 | return simple_read_from_buffer(buf, count, ppos, counters, avail); | |
f931551b RC |
212 | } |
213 | ||
214 | static const struct file_operations portcntr_ops[] = { | |
dd378c21 AB |
215 | { .read = portnames_read, .llseek = generic_file_llseek, }, |
216 | { .read = portcntrs_1_read, .llseek = generic_file_llseek, }, | |
217 | { .read = portcntrs_2_read, .llseek = generic_file_llseek, }, | |
f931551b RC |
218 | }; |
219 | ||
220 | /* | |
221 | * read the per-port QSFP data for port 1 (pidx 0) | |
222 | */ | |
223 | static ssize_t qsfp_1_read(struct file *file, char __user *buf, | |
224 | size_t count, loff_t *ppos) | |
225 | { | |
226 | struct qib_devdata *dd = private2dd(file); | |
227 | char *tmp; | |
228 | int ret; | |
229 | ||
230 | tmp = kmalloc(PAGE_SIZE, GFP_KERNEL); | |
231 | if (!tmp) | |
232 | return -ENOMEM; | |
233 | ||
234 | ret = qib_qsfp_dump(dd->pport, tmp, PAGE_SIZE); | |
235 | if (ret > 0) | |
236 | ret = simple_read_from_buffer(buf, count, ppos, tmp, ret); | |
237 | kfree(tmp); | |
238 | return ret; | |
239 | } | |
240 | ||
241 | /* | |
242 | * read the per-port QSFP data for port 2 (pidx 1) | |
243 | */ | |
244 | static ssize_t qsfp_2_read(struct file *file, char __user *buf, | |
245 | size_t count, loff_t *ppos) | |
246 | { | |
247 | struct qib_devdata *dd = private2dd(file); | |
248 | char *tmp; | |
249 | int ret; | |
250 | ||
251 | if (dd->num_pports < 2) | |
252 | return -ENODEV; | |
253 | ||
254 | tmp = kmalloc(PAGE_SIZE, GFP_KERNEL); | |
255 | if (!tmp) | |
256 | return -ENOMEM; | |
257 | ||
258 | ret = qib_qsfp_dump(dd->pport + 1, tmp, PAGE_SIZE); | |
259 | if (ret > 0) | |
260 | ret = simple_read_from_buffer(buf, count, ppos, tmp, ret); | |
261 | kfree(tmp); | |
262 | return ret; | |
263 | } | |
264 | ||
265 | static const struct file_operations qsfp_ops[] = { | |
dd378c21 AB |
266 | { .read = qsfp_1_read, .llseek = generic_file_llseek, }, |
267 | { .read = qsfp_2_read, .llseek = generic_file_llseek, }, | |
f931551b RC |
268 | }; |
269 | ||
270 | static ssize_t flash_read(struct file *file, char __user *buf, | |
271 | size_t count, loff_t *ppos) | |
272 | { | |
273 | struct qib_devdata *dd; | |
274 | ssize_t ret; | |
275 | loff_t pos; | |
276 | char *tmp; | |
277 | ||
278 | pos = *ppos; | |
279 | ||
280 | if (pos < 0) { | |
281 | ret = -EINVAL; | |
282 | goto bail; | |
283 | } | |
284 | ||
285 | if (pos >= sizeof(struct qib_flash)) { | |
286 | ret = 0; | |
287 | goto bail; | |
288 | } | |
289 | ||
290 | if (count > sizeof(struct qib_flash) - pos) | |
291 | count = sizeof(struct qib_flash) - pos; | |
292 | ||
293 | tmp = kmalloc(count, GFP_KERNEL); | |
294 | if (!tmp) { | |
295 | ret = -ENOMEM; | |
296 | goto bail; | |
297 | } | |
298 | ||
299 | dd = private2dd(file); | |
300 | if (qib_eeprom_read(dd, pos, tmp, count)) { | |
301 | qib_dev_err(dd, "failed to read from flash\n"); | |
302 | ret = -ENXIO; | |
303 | goto bail_tmp; | |
304 | } | |
305 | ||
306 | if (copy_to_user(buf, tmp, count)) { | |
307 | ret = -EFAULT; | |
308 | goto bail_tmp; | |
309 | } | |
310 | ||
311 | *ppos = pos + count; | |
312 | ret = count; | |
313 | ||
314 | bail_tmp: | |
315 | kfree(tmp); | |
316 | ||
317 | bail: | |
318 | return ret; | |
319 | } | |
320 | ||
321 | static ssize_t flash_write(struct file *file, const char __user *buf, | |
322 | size_t count, loff_t *ppos) | |
323 | { | |
324 | struct qib_devdata *dd; | |
325 | ssize_t ret; | |
326 | loff_t pos; | |
327 | char *tmp; | |
328 | ||
329 | pos = *ppos; | |
330 | ||
331 | if (pos != 0) { | |
332 | ret = -EINVAL; | |
333 | goto bail; | |
334 | } | |
335 | ||
336 | if (count != sizeof(struct qib_flash)) { | |
337 | ret = -EINVAL; | |
338 | goto bail; | |
339 | } | |
340 | ||
341 | tmp = kmalloc(count, GFP_KERNEL); | |
342 | if (!tmp) { | |
343 | ret = -ENOMEM; | |
344 | goto bail; | |
345 | } | |
346 | ||
347 | if (copy_from_user(tmp, buf, count)) { | |
348 | ret = -EFAULT; | |
349 | goto bail_tmp; | |
350 | } | |
351 | ||
352 | dd = private2dd(file); | |
353 | if (qib_eeprom_write(dd, pos, tmp, count)) { | |
354 | ret = -ENXIO; | |
355 | qib_dev_err(dd, "failed to write to flash\n"); | |
356 | goto bail_tmp; | |
357 | } | |
358 | ||
359 | *ppos = pos + count; | |
360 | ret = count; | |
361 | ||
362 | bail_tmp: | |
363 | kfree(tmp); | |
364 | ||
365 | bail: | |
366 | return ret; | |
367 | } | |
368 | ||
369 | static const struct file_operations flash_ops = { | |
370 | .read = flash_read, | |
371 | .write = flash_write, | |
6038f373 | 372 | .llseek = default_llseek, |
f931551b RC |
373 | }; |
374 | ||
375 | static int add_cntr_files(struct super_block *sb, struct qib_devdata *dd) | |
376 | { | |
377 | struct dentry *dir, *tmp; | |
378 | char unit[10]; | |
379 | int ret, i; | |
380 | ||
381 | /* create the per-unit directory */ | |
041af0bb | 382 | snprintf(unit, sizeof(unit), "%u", dd->unit); |
f931551b RC |
383 | ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir, |
384 | &simple_dir_operations, dd); | |
385 | if (ret) { | |
7fac3301 | 386 | pr_err("create_file(%s) failed: %d\n", unit, ret); |
f931551b RC |
387 | goto bail; |
388 | } | |
389 | ||
390 | /* create the files in the new directory */ | |
391 | ret = create_file("counters", S_IFREG|S_IRUGO, dir, &tmp, | |
392 | &cntr_ops[0], dd); | |
393 | if (ret) { | |
7fac3301 | 394 | pr_err("create_file(%s/counters) failed: %d\n", |
f931551b RC |
395 | unit, ret); |
396 | goto bail; | |
397 | } | |
398 | ret = create_file("counter_names", S_IFREG|S_IRUGO, dir, &tmp, | |
399 | &cntr_ops[1], dd); | |
400 | if (ret) { | |
7fac3301 | 401 | pr_err("create_file(%s/counter_names) failed: %d\n", |
f931551b RC |
402 | unit, ret); |
403 | goto bail; | |
404 | } | |
405 | ret = create_file("portcounter_names", S_IFREG|S_IRUGO, dir, &tmp, | |
406 | &portcntr_ops[0], dd); | |
407 | if (ret) { | |
7fac3301 | 408 | pr_err("create_file(%s/%s) failed: %d\n", |
f931551b RC |
409 | unit, "portcounter_names", ret); |
410 | goto bail; | |
411 | } | |
412 | for (i = 1; i <= dd->num_pports; i++) { | |
413 | char fname[24]; | |
414 | ||
415 | sprintf(fname, "port%dcounters", i); | |
416 | /* create the files in the new directory */ | |
417 | ret = create_file(fname, S_IFREG|S_IRUGO, dir, &tmp, | |
418 | &portcntr_ops[i], dd); | |
419 | if (ret) { | |
7fac3301 | 420 | pr_err("create_file(%s/%s) failed: %d\n", |
f931551b RC |
421 | unit, fname, ret); |
422 | goto bail; | |
423 | } | |
424 | if (!(dd->flags & QIB_HAS_QSFP)) | |
425 | continue; | |
426 | sprintf(fname, "qsfp%d", i); | |
427 | ret = create_file(fname, S_IFREG|S_IRUGO, dir, &tmp, | |
428 | &qsfp_ops[i - 1], dd); | |
429 | if (ret) { | |
7fac3301 | 430 | pr_err("create_file(%s/%s) failed: %d\n", |
f931551b RC |
431 | unit, fname, ret); |
432 | goto bail; | |
433 | } | |
434 | } | |
435 | ||
436 | ret = create_file("flash", S_IFREG|S_IWUSR|S_IRUGO, dir, &tmp, | |
437 | &flash_ops, dd); | |
438 | if (ret) | |
7fac3301 | 439 | pr_err("create_file(%s/flash) failed: %d\n", |
f931551b RC |
440 | unit, ret); |
441 | bail: | |
442 | return ret; | |
443 | } | |
444 | ||
445 | static int remove_file(struct dentry *parent, char *name) | |
446 | { | |
447 | struct dentry *tmp; | |
448 | int ret; | |
449 | ||
450 | tmp = lookup_one_len(name, parent, strlen(name)); | |
451 | ||
452 | if (IS_ERR(tmp)) { | |
453 | ret = PTR_ERR(tmp); | |
454 | goto bail; | |
455 | } | |
456 | ||
f931551b | 457 | spin_lock(&tmp->d_lock); |
a95104fd | 458 | if (!d_unhashed(tmp) && tmp->d_inode) { |
f931551b RC |
459 | __d_drop(tmp); |
460 | spin_unlock(&tmp->d_lock); | |
f931551b RC |
461 | simple_unlink(parent->d_inode, tmp); |
462 | } else { | |
463 | spin_unlock(&tmp->d_lock); | |
f931551b | 464 | } |
441a9d0e | 465 | dput(tmp); |
f931551b RC |
466 | |
467 | ret = 0; | |
468 | bail: | |
469 | /* | |
470 | * We don't expect clients to care about the return value, but | |
471 | * it's there if they need it. | |
472 | */ | |
473 | return ret; | |
474 | } | |
475 | ||
476 | static int remove_device_files(struct super_block *sb, | |
477 | struct qib_devdata *dd) | |
478 | { | |
479 | struct dentry *dir, *root; | |
480 | char unit[10]; | |
481 | int ret, i; | |
482 | ||
483 | root = dget(sb->s_root); | |
484 | mutex_lock(&root->d_inode->i_mutex); | |
041af0bb | 485 | snprintf(unit, sizeof(unit), "%u", dd->unit); |
f931551b RC |
486 | dir = lookup_one_len(unit, root, strlen(unit)); |
487 | ||
488 | if (IS_ERR(dir)) { | |
489 | ret = PTR_ERR(dir); | |
7fac3301 | 490 | pr_err("Lookup of %s failed\n", unit); |
f931551b RC |
491 | goto bail; |
492 | } | |
493 | ||
441a9d0e | 494 | mutex_lock(&dir->d_inode->i_mutex); |
f931551b RC |
495 | remove_file(dir, "counters"); |
496 | remove_file(dir, "counter_names"); | |
497 | remove_file(dir, "portcounter_names"); | |
498 | for (i = 0; i < dd->num_pports; i++) { | |
499 | char fname[24]; | |
500 | ||
501 | sprintf(fname, "port%dcounters", i + 1); | |
502 | remove_file(dir, fname); | |
503 | if (dd->flags & QIB_HAS_QSFP) { | |
504 | sprintf(fname, "qsfp%d", i + 1); | |
505 | remove_file(dir, fname); | |
506 | } | |
507 | } | |
508 | remove_file(dir, "flash"); | |
441a9d0e | 509 | mutex_unlock(&dir->d_inode->i_mutex); |
f931551b | 510 | ret = simple_rmdir(root->d_inode, dir); |
441a9d0e AV |
511 | d_delete(dir); |
512 | dput(dir); | |
f931551b RC |
513 | |
514 | bail: | |
515 | mutex_unlock(&root->d_inode->i_mutex); | |
516 | dput(root); | |
517 | return ret; | |
518 | } | |
519 | ||
520 | /* | |
521 | * This fills everything in when the fs is mounted, to handle umount/mount | |
522 | * after device init. The direct add_cntr_files() call handles adding | |
523 | * them from the init code, when the fs is already mounted. | |
524 | */ | |
525 | static int qibfs_fill_super(struct super_block *sb, void *data, int silent) | |
526 | { | |
527 | struct qib_devdata *dd, *tmp; | |
528 | unsigned long flags; | |
529 | int ret; | |
530 | ||
531 | static struct tree_descr files[] = { | |
532 | [2] = {"driver_stats", &driver_ops[0], S_IRUGO}, | |
533 | [3] = {"driver_stats_names", &driver_ops[1], S_IRUGO}, | |
534 | {""}, | |
535 | }; | |
536 | ||
537 | ret = simple_fill_super(sb, QIBFS_MAGIC, files); | |
538 | if (ret) { | |
7fac3301 | 539 | pr_err("simple_fill_super failed: %d\n", ret); |
f931551b RC |
540 | goto bail; |
541 | } | |
542 | ||
543 | spin_lock_irqsave(&qib_devs_lock, flags); | |
544 | ||
545 | list_for_each_entry_safe(dd, tmp, &qib_dev_list, list) { | |
546 | spin_unlock_irqrestore(&qib_devs_lock, flags); | |
547 | ret = add_cntr_files(sb, dd); | |
971b2e8a | 548 | if (ret) |
f931551b | 549 | goto bail; |
f931551b RC |
550 | spin_lock_irqsave(&qib_devs_lock, flags); |
551 | } | |
552 | ||
553 | spin_unlock_irqrestore(&qib_devs_lock, flags); | |
554 | ||
555 | bail: | |
556 | return ret; | |
557 | } | |
558 | ||
fc14f2fe AV |
559 | static struct dentry *qibfs_mount(struct file_system_type *fs_type, int flags, |
560 | const char *dev_name, void *data) | |
f931551b | 561 | { |
fc14f2fe | 562 | struct dentry *ret; |
da12c1f6 | 563 | |
fc14f2fe AV |
564 | ret = mount_single(fs_type, flags, data, qibfs_fill_super); |
565 | if (!IS_ERR(ret)) | |
566 | qib_super = ret->d_sb; | |
f931551b RC |
567 | return ret; |
568 | } | |
569 | ||
570 | static void qibfs_kill_super(struct super_block *s) | |
571 | { | |
572 | kill_litter_super(s); | |
573 | qib_super = NULL; | |
574 | } | |
575 | ||
576 | int qibfs_add(struct qib_devdata *dd) | |
577 | { | |
578 | int ret; | |
579 | ||
580 | /* | |
581 | * On first unit initialized, qib_super will not yet exist | |
582 | * because nobody has yet tried to mount the filesystem, so | |
583 | * we can't consider that to be an error; if an error occurs | |
584 | * during the mount, that will get a complaint, so this is OK. | |
585 | * add_cntr_files() for all units is done at mount from | |
586 | * qibfs_fill_super(), so one way or another, everything works. | |
587 | */ | |
588 | if (qib_super == NULL) | |
589 | ret = 0; | |
590 | else | |
591 | ret = add_cntr_files(qib_super, dd); | |
592 | return ret; | |
593 | } | |
594 | ||
595 | int qibfs_remove(struct qib_devdata *dd) | |
596 | { | |
597 | int ret = 0; | |
598 | ||
599 | if (qib_super) | |
600 | ret = remove_device_files(qib_super, dd); | |
601 | ||
602 | return ret; | |
603 | } | |
604 | ||
605 | static struct file_system_type qibfs_fs_type = { | |
606 | .owner = THIS_MODULE, | |
607 | .name = "ipathfs", | |
fc14f2fe | 608 | .mount = qibfs_mount, |
f931551b RC |
609 | .kill_sb = qibfs_kill_super, |
610 | }; | |
7f78e035 | 611 | MODULE_ALIAS_FS("ipathfs"); |
f931551b RC |
612 | |
613 | int __init qib_init_qibfs(void) | |
614 | { | |
615 | return register_filesystem(&qibfs_fs_type); | |
616 | } | |
617 | ||
618 | int __exit qib_exit_qibfs(void) | |
619 | { | |
620 | return unregister_filesystem(&qibfs_fs_type); | |
621 | } |