Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 1 | /* |
Mike Marciniszyn | 7fac330 | 2012-07-19 13:04:25 +0000 | [diff] [blame] | 2 | * Copyright (c) 2012 Intel Corporation. All rights reserved. |
| 3 | * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved. |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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 | |
Al Viro | 496ad9a | 2013-01-23 17:07:38 -0500 | [diff] [blame] | 48 | #define private2dd(file) (file_inode(file)->i_private) |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 49 | |
| 50 | static int qibfs_mknod(struct inode *dir, struct dentry *dentry, |
Al Viro | f9ec800 | 2011-07-24 23:27:00 -0400 | [diff] [blame] | 51 | umode_t mode, const struct file_operations *fops, |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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 | |
Christoph Hellwig | 85fe402 | 2010-10-23 11:19:54 -0400 | [diff] [blame] | 62 | inode->i_ino = get_next_ino(); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 63 | inode->i_mode = mode; |
Eric W. Biederman | d03ca58 | 2012-04-25 22:40:44 -0700 | [diff] [blame] | 64 | inode->i_uid = GLOBAL_ROOT_UID; |
| 65 | inode->i_gid = GLOBAL_ROOT_GID; |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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; |
Al Viro | f9ec800 | 2011-07-24 23:27:00 -0400 | [diff] [blame] | 71 | if (S_ISDIR(mode)) { |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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 | |
Al Viro | f9ec800 | 2011-07-24 23:27:00 -0400 | [diff] [blame] | 86 | static int create_file(const char *name, umode_t mode, |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 87 | struct dentry *parent, struct dentry **dentry, |
| 88 | const struct file_operations *fops, void *data) |
| 89 | { |
| 90 | int error; |
| 91 | |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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 | { |
Mike Marciniszyn | 1ed88dd | 2014-03-07 08:40:49 -0500 | [diff] [blame] | 107 | qib_stats.sps_ints = qib_sps_ints(); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 108 | return simple_read_from_buffer(buf, count, ppos, &qib_stats, |
Mike Marciniszyn | 041af0b | 2015-01-16 10:50:32 -0500 | [diff] [blame] | 109 | sizeof(qib_stats)); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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, |
Mike Marciniszyn | 041af0b | 2015-01-16 10:50:32 -0500 | [diff] [blame] | 136 | sizeof(qib_statnames) - 1); /* no null */ |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 137 | } |
| 138 | |
| 139 | static const struct file_operations driver_ops[] = { |
Arnd Bergmann | dd378c2 | 2010-07-07 21:40:06 +0000 | [diff] [blame] | 140 | { .read = driver_stats_read, .llseek = generic_file_llseek, }, |
| 141 | { .read = driver_names_read, .llseek = generic_file_llseek, }, |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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; |
Roland Dreier | f27ec1d | 2010-05-26 13:15:06 -0700 | [diff] [blame] | 149 | size_t avail; |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 150 | struct qib_devdata *dd = private2dd(file); |
| 151 | |
Roland Dreier | f27ec1d | 2010-05-26 13:15:06 -0700 | [diff] [blame] | 152 | avail = dd->f_read_cntrs(dd, *ppos, NULL, &counters); |
| 153 | return simple_read_from_buffer(buf, count, ppos, counters, avail); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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; |
Roland Dreier | f27ec1d | 2010-05-26 13:15:06 -0700 | [diff] [blame] | 161 | size_t avail; |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 162 | struct qib_devdata *dd = private2dd(file); |
| 163 | |
Roland Dreier | f27ec1d | 2010-05-26 13:15:06 -0700 | [diff] [blame] | 164 | avail = dd->f_read_cntrs(dd, *ppos, &names, NULL); |
| 165 | return simple_read_from_buffer(buf, count, ppos, names, avail); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 166 | } |
| 167 | |
| 168 | static const struct file_operations cntr_ops[] = { |
Arnd Bergmann | dd378c2 | 2010-07-07 21:40:06 +0000 | [diff] [blame] | 169 | { .read = dev_counters_read, .llseek = generic_file_llseek, }, |
| 170 | { .read = dev_names_read, .llseek = generic_file_llseek, }, |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 171 | }; |
| 172 | |
| 173 | /* |
Al Viro | 496ad9a | 2013-01-23 17:07:38 -0500 | [diff] [blame] | 174 | * Could use file_inode(file)->i_ino to figure out which file, |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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; |
Roland Dreier | f27ec1d | 2010-05-26 13:15:06 -0700 | [diff] [blame] | 183 | size_t avail; |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 184 | struct qib_devdata *dd = private2dd(file); |
| 185 | |
Roland Dreier | f27ec1d | 2010-05-26 13:15:06 -0700 | [diff] [blame] | 186 | avail = dd->f_read_portcntrs(dd, *ppos, 0, &names, NULL); |
| 187 | return simple_read_from_buffer(buf, count, ppos, names, avail); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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; |
Roland Dreier | f27ec1d | 2010-05-26 13:15:06 -0700 | [diff] [blame] | 195 | size_t avail; |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 196 | struct qib_devdata *dd = private2dd(file); |
| 197 | |
Roland Dreier | f27ec1d | 2010-05-26 13:15:06 -0700 | [diff] [blame] | 198 | avail = dd->f_read_portcntrs(dd, *ppos, 0, NULL, &counters); |
| 199 | return simple_read_from_buffer(buf, count, ppos, counters, avail); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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; |
Roland Dreier | f27ec1d | 2010-05-26 13:15:06 -0700 | [diff] [blame] | 207 | size_t avail; |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 208 | struct qib_devdata *dd = private2dd(file); |
| 209 | |
Roland Dreier | f27ec1d | 2010-05-26 13:15:06 -0700 | [diff] [blame] | 210 | avail = dd->f_read_portcntrs(dd, *ppos, 1, NULL, &counters); |
| 211 | return simple_read_from_buffer(buf, count, ppos, counters, avail); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 212 | } |
| 213 | |
| 214 | static const struct file_operations portcntr_ops[] = { |
Arnd Bergmann | dd378c2 | 2010-07-07 21:40:06 +0000 | [diff] [blame] | 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, }, |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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[] = { |
Arnd Bergmann | dd378c2 | 2010-07-07 21:40:06 +0000 | [diff] [blame] | 266 | { .read = qsfp_1_read, .llseek = generic_file_llseek, }, |
| 267 | { .read = qsfp_2_read, .llseek = generic_file_llseek, }, |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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, |
Arnd Bergmann | 6038f37 | 2010-08-15 18:52:59 +0200 | [diff] [blame] | 372 | .llseek = default_llseek, |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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 */ |
Mike Marciniszyn | 041af0b | 2015-01-16 10:50:32 -0500 | [diff] [blame] | 382 | snprintf(unit, sizeof(unit), "%u", dd->unit); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 383 | ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir, |
| 384 | &simple_dir_operations, dd); |
| 385 | if (ret) { |
Mike Marciniszyn | 7fac330 | 2012-07-19 13:04:25 +0000 | [diff] [blame] | 386 | pr_err("create_file(%s) failed: %d\n", unit, ret); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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) { |
Mike Marciniszyn | 7fac330 | 2012-07-19 13:04:25 +0000 | [diff] [blame] | 394 | pr_err("create_file(%s/counters) failed: %d\n", |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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) { |
Mike Marciniszyn | 7fac330 | 2012-07-19 13:04:25 +0000 | [diff] [blame] | 401 | pr_err("create_file(%s/counter_names) failed: %d\n", |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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) { |
Mike Marciniszyn | 7fac330 | 2012-07-19 13:04:25 +0000 | [diff] [blame] | 408 | pr_err("create_file(%s/%s) failed: %d\n", |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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) { |
Mike Marciniszyn | 7fac330 | 2012-07-19 13:04:25 +0000 | [diff] [blame] | 420 | pr_err("create_file(%s/%s) failed: %d\n", |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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) { |
Mike Marciniszyn | 7fac330 | 2012-07-19 13:04:25 +0000 | [diff] [blame] | 430 | pr_err("create_file(%s/%s) failed: %d\n", |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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) |
Mike Marciniszyn | 7fac330 | 2012-07-19 13:04:25 +0000 | [diff] [blame] | 439 | pr_err("create_file(%s/flash) failed: %d\n", |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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 | |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 457 | spin_lock(&tmp->d_lock); |
David Howells | a95104f | 2015-01-27 15:01:18 +0000 | [diff] [blame] | 458 | if (!d_unhashed(tmp) && tmp->d_inode) { |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 459 | __d_drop(tmp); |
| 460 | spin_unlock(&tmp->d_lock); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 461 | simple_unlink(parent->d_inode, tmp); |
| 462 | } else { |
| 463 | spin_unlock(&tmp->d_lock); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 464 | } |
Al Viro | 441a9d0 | 2013-11-13 07:52:33 -0500 | [diff] [blame] | 465 | dput(tmp); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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); |
Mike Marciniszyn | 041af0b | 2015-01-16 10:50:32 -0500 | [diff] [blame] | 485 | snprintf(unit, sizeof(unit), "%u", dd->unit); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 486 | dir = lookup_one_len(unit, root, strlen(unit)); |
| 487 | |
| 488 | if (IS_ERR(dir)) { |
| 489 | ret = PTR_ERR(dir); |
Mike Marciniszyn | 7fac330 | 2012-07-19 13:04:25 +0000 | [diff] [blame] | 490 | pr_err("Lookup of %s failed\n", unit); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 491 | goto bail; |
| 492 | } |
| 493 | |
Al Viro | 441a9d0 | 2013-11-13 07:52:33 -0500 | [diff] [blame] | 494 | mutex_lock(&dir->d_inode->i_mutex); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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"); |
Al Viro | 441a9d0 | 2013-11-13 07:52:33 -0500 | [diff] [blame] | 509 | mutex_unlock(&dir->d_inode->i_mutex); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 510 | ret = simple_rmdir(root->d_inode, dir); |
Al Viro | 441a9d0 | 2013-11-13 07:52:33 -0500 | [diff] [blame] | 511 | d_delete(dir); |
| 512 | dput(dir); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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) { |
Mike Marciniszyn | 7fac330 | 2012-07-19 13:04:25 +0000 | [diff] [blame] | 539 | pr_err("simple_fill_super failed: %d\n", ret); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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); |
Al Viro | 971b2e8 | 2010-05-28 21:32:44 -0400 | [diff] [blame] | 548 | if (ret) |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 549 | goto bail; |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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 | |
Al Viro | fc14f2f | 2010-07-25 01:48:30 +0400 | [diff] [blame] | 559 | static struct dentry *qibfs_mount(struct file_system_type *fs_type, int flags, |
| 560 | const char *dev_name, void *data) |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 561 | { |
Al Viro | fc14f2f | 2010-07-25 01:48:30 +0400 | [diff] [blame] | 562 | struct dentry *ret; |
Mike Marciniszyn | da12c1f | 2015-01-16 11:23:31 -0500 | [diff] [blame] | 563 | |
Al Viro | fc14f2f | 2010-07-25 01:48:30 +0400 | [diff] [blame] | 564 | ret = mount_single(fs_type, flags, data, qibfs_fill_super); |
| 565 | if (!IS_ERR(ret)) |
| 566 | qib_super = ret->d_sb; |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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", |
Al Viro | fc14f2f | 2010-07-25 01:48:30 +0400 | [diff] [blame] | 608 | .mount = qibfs_mount, |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 609 | .kill_sb = qibfs_kill_super, |
| 610 | }; |
Eric W. Biederman | 7f78e03 | 2013-03-02 19:39:14 -0800 | [diff] [blame] | 611 | MODULE_ALIAS_FS("ipathfs"); |
Ralph Campbell | f931551 | 2010-05-23 21:44:54 -0700 | [diff] [blame] | 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 | } |