18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * f2fs IO tracer 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2014 Motorola Mobility 68c2ecf20Sopenharmony_ci * Copyright (c) 2014 Jaegeuk Kim <jaegeuk@kernel.org> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/fs.h> 98c2ecf20Sopenharmony_ci#include <linux/f2fs_fs.h> 108c2ecf20Sopenharmony_ci#include <linux/sched.h> 118c2ecf20Sopenharmony_ci#include <linux/radix-tree.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "f2fs.h" 148c2ecf20Sopenharmony_ci#include "trace.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic RADIX_TREE(pids, GFP_ATOMIC); 178c2ecf20Sopenharmony_cistatic spinlock_t pids_lock; 188c2ecf20Sopenharmony_cistatic struct last_io_info last_io; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic inline void __print_last_io(void) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci if (!last_io.len) 238c2ecf20Sopenharmony_ci return; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci trace_printk("%3x:%3x %4x %-16s %2x %5x %5x %12x %4x\n", 268c2ecf20Sopenharmony_ci last_io.major, last_io.minor, 278c2ecf20Sopenharmony_ci last_io.pid, "----------------", 288c2ecf20Sopenharmony_ci last_io.type, 298c2ecf20Sopenharmony_ci last_io.fio.op, last_io.fio.op_flags, 308c2ecf20Sopenharmony_ci last_io.fio.new_blkaddr, 318c2ecf20Sopenharmony_ci last_io.len); 328c2ecf20Sopenharmony_ci memset(&last_io, 0, sizeof(last_io)); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int __file_type(struct inode *inode, pid_t pid) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci if (f2fs_is_atomic_file(inode)) 388c2ecf20Sopenharmony_ci return __ATOMIC_FILE; 398c2ecf20Sopenharmony_ci else if (f2fs_is_volatile_file(inode)) 408c2ecf20Sopenharmony_ci return __VOLATILE_FILE; 418c2ecf20Sopenharmony_ci else if (S_ISDIR(inode->i_mode)) 428c2ecf20Sopenharmony_ci return __DIR_FILE; 438c2ecf20Sopenharmony_ci else if (inode->i_ino == F2FS_NODE_INO(F2FS_I_SB(inode))) 448c2ecf20Sopenharmony_ci return __NODE_FILE; 458c2ecf20Sopenharmony_ci else if (inode->i_ino == F2FS_META_INO(F2FS_I_SB(inode))) 468c2ecf20Sopenharmony_ci return __META_FILE; 478c2ecf20Sopenharmony_ci else if (pid) 488c2ecf20Sopenharmony_ci return __NORMAL_FILE; 498c2ecf20Sopenharmony_ci else 508c2ecf20Sopenharmony_ci return __MISC_FILE; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_civoid f2fs_trace_pid(struct page *page) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 568c2ecf20Sopenharmony_ci pid_t pid = task_pid_nr(current); 578c2ecf20Sopenharmony_ci void *p; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci set_page_private(page, (unsigned long)pid); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ciretry: 628c2ecf20Sopenharmony_ci if (radix_tree_preload(GFP_NOFS)) 638c2ecf20Sopenharmony_ci return; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci spin_lock(&pids_lock); 668c2ecf20Sopenharmony_ci p = radix_tree_lookup(&pids, pid); 678c2ecf20Sopenharmony_ci if (p == current) 688c2ecf20Sopenharmony_ci goto out; 698c2ecf20Sopenharmony_ci if (p) 708c2ecf20Sopenharmony_ci radix_tree_delete(&pids, pid); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (radix_tree_insert(&pids, pid, current)) { 738c2ecf20Sopenharmony_ci spin_unlock(&pids_lock); 748c2ecf20Sopenharmony_ci radix_tree_preload_end(); 758c2ecf20Sopenharmony_ci cond_resched(); 768c2ecf20Sopenharmony_ci goto retry; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci trace_printk("%3x:%3x %4x %-16s\n", 808c2ecf20Sopenharmony_ci MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev), 818c2ecf20Sopenharmony_ci pid, current->comm); 828c2ecf20Sopenharmony_ciout: 838c2ecf20Sopenharmony_ci spin_unlock(&pids_lock); 848c2ecf20Sopenharmony_ci radix_tree_preload_end(); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_civoid f2fs_trace_ios(struct f2fs_io_info *fio, int flush) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct inode *inode; 908c2ecf20Sopenharmony_ci pid_t pid; 918c2ecf20Sopenharmony_ci int major, minor; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (flush) { 948c2ecf20Sopenharmony_ci __print_last_io(); 958c2ecf20Sopenharmony_ci return; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci inode = fio->page->mapping->host; 998c2ecf20Sopenharmony_ci pid = page_private(fio->page); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci major = MAJOR(inode->i_sb->s_dev); 1028c2ecf20Sopenharmony_ci minor = MINOR(inode->i_sb->s_dev); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (last_io.major == major && last_io.minor == minor && 1058c2ecf20Sopenharmony_ci last_io.pid == pid && 1068c2ecf20Sopenharmony_ci last_io.type == __file_type(inode, pid) && 1078c2ecf20Sopenharmony_ci last_io.fio.op == fio->op && 1088c2ecf20Sopenharmony_ci last_io.fio.op_flags == fio->op_flags && 1098c2ecf20Sopenharmony_ci last_io.fio.new_blkaddr + last_io.len == 1108c2ecf20Sopenharmony_ci fio->new_blkaddr) { 1118c2ecf20Sopenharmony_ci last_io.len++; 1128c2ecf20Sopenharmony_ci return; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci __print_last_io(); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci last_io.major = major; 1188c2ecf20Sopenharmony_ci last_io.minor = minor; 1198c2ecf20Sopenharmony_ci last_io.pid = pid; 1208c2ecf20Sopenharmony_ci last_io.type = __file_type(inode, pid); 1218c2ecf20Sopenharmony_ci last_io.fio = *fio; 1228c2ecf20Sopenharmony_ci last_io.len = 1; 1238c2ecf20Sopenharmony_ci return; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_civoid f2fs_build_trace_ios(void) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci spin_lock_init(&pids_lock); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#define PIDVEC_SIZE 128 1328c2ecf20Sopenharmony_cistatic unsigned int gang_lookup_pids(pid_t *results, unsigned long first_index, 1338c2ecf20Sopenharmony_ci unsigned int max_items) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct radix_tree_iter iter; 1368c2ecf20Sopenharmony_ci void **slot; 1378c2ecf20Sopenharmony_ci unsigned int ret = 0; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (unlikely(!max_items)) 1408c2ecf20Sopenharmony_ci return 0; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci radix_tree_for_each_slot(slot, &pids, &iter, first_index) { 1438c2ecf20Sopenharmony_ci results[ret] = iter.index; 1448c2ecf20Sopenharmony_ci if (++ret == max_items) 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci return ret; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_civoid f2fs_destroy_trace_ios(void) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci pid_t pid[PIDVEC_SIZE]; 1538c2ecf20Sopenharmony_ci pid_t next_pid = 0; 1548c2ecf20Sopenharmony_ci unsigned int found; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci spin_lock(&pids_lock); 1578c2ecf20Sopenharmony_ci while ((found = gang_lookup_pids(pid, next_pid, PIDVEC_SIZE))) { 1588c2ecf20Sopenharmony_ci unsigned idx; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci next_pid = pid[found - 1] + 1; 1618c2ecf20Sopenharmony_ci for (idx = 0; idx < found; idx++) 1628c2ecf20Sopenharmony_ci radix_tree_delete(&pids, pid[idx]); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci spin_unlock(&pids_lock); 1658c2ecf20Sopenharmony_ci} 166