1 /* 2 * Copyright 2012 Cisco Systems, Inc. All rights reserved. 3 * 4 * This program is free software; you may redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; version 2 of the License. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 9 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 10 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 11 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 12 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 13 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 15 * SOFTWARE. 16 */ 17 18 #include <linux/module.h> 19 #include <linux/errno.h> 20 #include <linux/debugfs.h> 21 #include "fnic.h" 22 23 static struct dentry *fnic_trace_debugfs_root; 24 static struct dentry *fnic_trace_debugfs_file; 25 static struct dentry *fnic_trace_enable; 26 27 /* 28 * fnic_trace_ctrl_open - Open the trace_enable file 29 * @inode: The inode pointer. 30 * @file: The file pointer to attach the trace enable/disable flag. 31 * 32 * Description: 33 * This routine opens a debugsfs file trace_enable. 34 * 35 * Returns: 36 * This function returns zero if successful. 37 */ 38 static int fnic_trace_ctrl_open(struct inode *inode, struct file *filp) 39 { 40 filp->private_data = inode->i_private; 41 return 0; 42 } 43 44 /* 45 * fnic_trace_ctrl_read - Read a trace_enable debugfs file 46 * @filp: The file pointer to read from. 47 * @ubuf: The buffer to copy the data to. 48 * @cnt: The number of bytes to read. 49 * @ppos: The position in the file to start reading from. 50 * 51 * Description: 52 * This routine reads value of variable fnic_tracing_enabled 53 * and stores into local @buf. It will start reading file at @ppos and 54 * copy up to @cnt of data to @ubuf from @buf. 55 * 56 * Returns: 57 * This function returns the amount of data that was read. 58 */ 59 static ssize_t fnic_trace_ctrl_read(struct file *filp, 60 char __user *ubuf, 61 size_t cnt, loff_t *ppos) 62 { 63 char buf[64]; 64 int len; 65 len = sprintf(buf, "%u\n", fnic_tracing_enabled); 66 67 return simple_read_from_buffer(ubuf, cnt, ppos, buf, len); 68 } 69 70 /* 71 * fnic_trace_ctrl_write - Write to trace_enable debugfs file 72 * @filp: The file pointer to write from. 73 * @ubuf: The buffer to copy the data from. 74 * @cnt: The number of bytes to write. 75 * @ppos: The position in the file to start writing to. 76 * 77 * Description: 78 * This routine writes data from user buffer @ubuf to buffer @buf and 79 * sets fnic_tracing_enabled value as per user input. 80 * 81 * Returns: 82 * This function returns the amount of data that was written. 83 */ 84 static ssize_t fnic_trace_ctrl_write(struct file *filp, 85 const char __user *ubuf, 86 size_t cnt, loff_t *ppos) 87 { 88 char buf[64]; 89 unsigned long val; 90 int ret; 91 92 if (cnt >= sizeof(buf)) 93 return -EINVAL; 94 95 if (copy_from_user(&buf, ubuf, cnt)) 96 return -EFAULT; 97 98 buf[cnt] = 0; 99 100 ret = kstrtoul(buf, 10, &val); 101 if (ret < 0) 102 return ret; 103 104 fnic_tracing_enabled = val; 105 (*ppos)++; 106 107 return cnt; 108 } 109 110 /* 111 * fnic_trace_debugfs_open - Open the fnic trace log 112 * @inode: The inode pointer 113 * @file: The file pointer to attach the log output 114 * 115 * Description: 116 * This routine is the entry point for the debugfs open file operation. 117 * It allocates the necessary buffer for the log, fills the buffer from 118 * the in-memory log and then returns a pointer to that log in 119 * the private_data field in @file. 120 * 121 * Returns: 122 * This function returns zero if successful. On error it will return 123 * a negative error value. 124 */ 125 static int fnic_trace_debugfs_open(struct inode *inode, 126 struct file *file) 127 { 128 fnic_dbgfs_t *fnic_dbg_prt; 129 fnic_dbg_prt = kzalloc(sizeof(fnic_dbgfs_t), GFP_KERNEL); 130 if (!fnic_dbg_prt) 131 return -ENOMEM; 132 133 fnic_dbg_prt->buffer = vmalloc((3*(trace_max_pages * PAGE_SIZE))); 134 if (!fnic_dbg_prt->buffer) { 135 kfree(fnic_dbg_prt); 136 return -ENOMEM; 137 } 138 memset((void *)fnic_dbg_prt->buffer, 0, 139 (3*(trace_max_pages * PAGE_SIZE))); 140 fnic_dbg_prt->buffer_len = fnic_get_trace_data(fnic_dbg_prt); 141 file->private_data = fnic_dbg_prt; 142 return 0; 143 } 144 145 /* 146 * fnic_trace_debugfs_lseek - Seek through a debugfs file 147 * @file: The file pointer to seek through. 148 * @offset: The offset to seek to or the amount to seek by. 149 * @howto: Indicates how to seek. 150 * 151 * Description: 152 * This routine is the entry point for the debugfs lseek file operation. 153 * The @howto parameter indicates whether @offset is the offset to directly 154 * seek to, or if it is a value to seek forward or reverse by. This function 155 * figures out what the new offset of the debugfs file will be and assigns 156 * that value to the f_pos field of @file. 157 * 158 * Returns: 159 * This function returns the new offset if successful and returns a negative 160 * error if unable to process the seek. 161 */ 162 static loff_t fnic_trace_debugfs_lseek(struct file *file, 163 loff_t offset, 164 int howto) 165 { 166 fnic_dbgfs_t *fnic_dbg_prt = file->private_data; 167 loff_t pos = -1; 168 169 switch (howto) { 170 case 0: 171 pos = offset; 172 break; 173 case 1: 174 pos = file->f_pos + offset; 175 break; 176 case 2: 177 pos = fnic_dbg_prt->buffer_len - offset; 178 } 179 return (pos < 0 || pos > fnic_dbg_prt->buffer_len) ? 180 -EINVAL : (file->f_pos = pos); 181 } 182 183 /* 184 * fnic_trace_debugfs_read - Read a debugfs file 185 * @file: The file pointer to read from. 186 * @ubuf: The buffer to copy the data to. 187 * @nbytes: The number of bytes to read. 188 * @pos: The position in the file to start reading from. 189 * 190 * Description: 191 * This routine reads data from the buffer indicated in the private_data 192 * field of @file. It will start reading at @pos and copy up to @nbytes of 193 * data to @ubuf. 194 * 195 * Returns: 196 * This function returns the amount of data that was read (this could be 197 * less than @nbytes if the end of the file was reached). 198 */ 199 static ssize_t fnic_trace_debugfs_read(struct file *file, 200 char __user *ubuf, 201 size_t nbytes, 202 loff_t *pos) 203 { 204 fnic_dbgfs_t *fnic_dbg_prt = file->private_data; 205 int rc = 0; 206 rc = simple_read_from_buffer(ubuf, nbytes, pos, 207 fnic_dbg_prt->buffer, 208 fnic_dbg_prt->buffer_len); 209 return rc; 210 } 211 212 /* 213 * fnic_trace_debugfs_release - Release the buffer used to store 214 * debugfs file data 215 * @inode: The inode pointer 216 * @file: The file pointer that contains the buffer to release 217 * 218 * Description: 219 * This routine frees the buffer that was allocated when the debugfs 220 * file was opened. 221 * 222 * Returns: 223 * This function returns zero. 224 */ 225 static int fnic_trace_debugfs_release(struct inode *inode, 226 struct file *file) 227 { 228 fnic_dbgfs_t *fnic_dbg_prt = file->private_data; 229 230 vfree(fnic_dbg_prt->buffer); 231 kfree(fnic_dbg_prt); 232 return 0; 233 } 234 235 static const struct file_operations fnic_trace_ctrl_fops = { 236 .owner = THIS_MODULE, 237 .open = fnic_trace_ctrl_open, 238 .read = fnic_trace_ctrl_read, 239 .write = fnic_trace_ctrl_write, 240 }; 241 242 static const struct file_operations fnic_trace_debugfs_fops = { 243 .owner = THIS_MODULE, 244 .open = fnic_trace_debugfs_open, 245 .llseek = fnic_trace_debugfs_lseek, 246 .read = fnic_trace_debugfs_read, 247 .release = fnic_trace_debugfs_release, 248 }; 249 250 /* 251 * fnic_trace_debugfs_init - Initialize debugfs for fnic trace logging 252 * 253 * Description: 254 * When Debugfs is configured this routine sets up the fnic debugfs 255 * file system. If not already created, this routine will create the 256 * fnic directory. It will create file trace to log fnic trace buffer 257 * output into debugfs and it will also create file trace_enable to 258 * control enable/disable of trace logging into trace buffer. 259 */ 260 int fnic_trace_debugfs_init(void) 261 { 262 int rc = -1; 263 fnic_trace_debugfs_root = debugfs_create_dir("fnic", NULL); 264 if (!fnic_trace_debugfs_root) { 265 printk(KERN_DEBUG "Cannot create debugfs root\n"); 266 return rc; 267 } 268 fnic_trace_enable = debugfs_create_file("tracing_enable", 269 S_IFREG|S_IRUGO|S_IWUSR, 270 fnic_trace_debugfs_root, 271 NULL, &fnic_trace_ctrl_fops); 272 273 if (!fnic_trace_enable) { 274 printk(KERN_DEBUG "Cannot create trace_enable file" 275 " under debugfs"); 276 return rc; 277 } 278 279 fnic_trace_debugfs_file = debugfs_create_file("trace", 280 S_IFREG|S_IRUGO|S_IWUSR, 281 fnic_trace_debugfs_root, 282 NULL, 283 &fnic_trace_debugfs_fops); 284 285 if (!fnic_trace_debugfs_file) { 286 printk(KERN_DEBUG "Cannot create trace file under debugfs"); 287 return rc; 288 } 289 rc = 0; 290 return rc; 291 } 292 293 /* 294 * fnic_trace_debugfs_terminate - Tear down debugfs infrastructure 295 * 296 * Description: 297 * When Debugfs is configured this routine removes debugfs file system 298 * elements that are specific to fnic trace logging. 299 */ 300 void fnic_trace_debugfs_terminate(void) 301 { 302 if (fnic_trace_debugfs_file) { 303 debugfs_remove(fnic_trace_debugfs_file); 304 fnic_trace_debugfs_file = NULL; 305 } 306 if (fnic_trace_enable) { 307 debugfs_remove(fnic_trace_enable); 308 fnic_trace_enable = NULL; 309 } 310 if (fnic_trace_debugfs_root) { 311 debugfs_remove(fnic_trace_debugfs_root); 312 fnic_trace_debugfs_root = NULL; 313 } 314 } 315