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