From patchwork Tue Mar 29 14:31:20 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anand Jain X-Patchwork-Id: 8687761 Return-Path: X-Original-To: patchwork-linux-btrfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 3CD7FC0554 for ; Tue, 29 Mar 2016 14:31:39 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D7AAD202F8 for ; Tue, 29 Mar 2016 14:31:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 7BDC420160 for ; Tue, 29 Mar 2016 14:31:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756831AbcC2Obb (ORCPT ); Tue, 29 Mar 2016 10:31:31 -0400 Received: from userp1040.oracle.com ([156.151.31.81]:18498 "EHLO userp1040.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756892AbcC2Oba (ORCPT ); Tue, 29 Mar 2016 10:31:30 -0400 Received: from aserv0021.oracle.com (aserv0021.oracle.com [141.146.126.233]) by userp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id u2TEVSnK025377 (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 29 Mar 2016 14:31:29 GMT Received: from userv0122.oracle.com (userv0122.oracle.com [156.151.31.75]) by aserv0021.oracle.com (8.13.8/8.13.8) with ESMTP id u2TEVS4h015420 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 29 Mar 2016 14:31:28 GMT Received: from abhmp0018.oracle.com (abhmp0018.oracle.com [141.146.116.24]) by userv0122.oracle.com (8.14.4/8.14.4) with ESMTP id u2TEVR2D007800 for ; Tue, 29 Mar 2016 14:31:28 GMT Received: from arch2.sg.oracle.com (/10.186.101.65) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Tue, 29 Mar 2016 07:31:27 -0700 From: Anand Jain To: linux-btrfs@vger.kernel.org Subject: [PATCH] btrfs: debug: procfs-devlist: introduce procfs interface for the device list for debugging Date: Tue, 29 Mar 2016 22:31:20 +0800 Message-Id: <1459261880-32336-1-git-send-email-anand.jain@oracle.com> X-Mailer: git-send-email 2.7.0 X-Source-IP: aserv0021.oracle.com [141.146.126.233] Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Spam-Status: No, score=-7.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Anand Jain This patch introduces profs interface /proc/fs/btrfs/devlist, which as of now exports all the members of kernel fs_devices. The current /sys/fs/btrfs interface works when the fs is mounted, and is on the file directory hierarchy and also has the sysfs limitation max output of U64 per file. Here btrfs procfs uses seq_file to export all the members of fs_devices. Also shows the contents when device is not mounted, but have registered with btrfs kernel (useful as an alternative to buggy ready ioctl) An attempt is made to follow the some standard file format output such as ini. So that a simple warper python script will provide end user useful interfaces. Further planning to add few more members to the interface such as group profile info. The long term idea is to make procfs interface a onestop btrfs application interface for the device and fs info from the kernel, where a simple python script can make use of it. Signed-off-by: Anand Jain --- fs/btrfs/Makefile | 2 +- fs/btrfs/ctree.h | 4 + fs/btrfs/procfs.c | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/btrfs/procfs.h | 1 + fs/btrfs/super.c | 4 + 5 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 fs/btrfs/procfs.c create mode 100644 fs/btrfs/procfs.h diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index 128ce17a80b0..019f936788cc 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_BTRFS_FS) := btrfs.o btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ file-item.o inode-item.o inode-map.o disk-io.o \ transaction.o inode.o file.o tree-defrag.o \ - extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \ + extent_map.o sysfs.o procfs.o struct-funcs.o xattr.o ordered-data.o \ extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ export.o tree-log.o free-space-cache.o zlib.o lzo.o \ compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \ diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 36f1c29e00a0..429364a4b487 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -4593,4 +4593,8 @@ static inline int btrfs_test_is_dummy_root(struct btrfs_root *root) return 0; } +/* procfs.c */ +void btrfs_exit_procfs(void); +void btrfs_init_procfs(void); + #endif diff --git a/fs/btrfs/procfs.c b/fs/btrfs/procfs.c new file mode 100644 index 000000000000..99edcad8a825 --- /dev/null +++ b/fs/btrfs/procfs.c @@ -0,0 +1,250 @@ +#include +#include +#include +#include "ctree.h" +#include "volumes.h" +#include "rcu-string.h" + +#define BTRFS_PROC_PATH "fs/btrfs" +#define BTRFS_PROC_DEVLIST "devlist" + +struct proc_dir_entry *btrfs_proc_root; + +void btrfs_print_devlist(struct seq_file *seq) +{ + + /* Btrfs Procfs String Len */ +#define BPSL 256 +#define BTRFS_SEQ_PRINT(plist, arg)\ + snprintf(str, BPSL, plist, arg);\ + if (sprt)\ + seq_printf(seq, "\t");\ + seq_printf(seq, str) + + char str[BPSL]; + struct btrfs_device *device; + struct btrfs_fs_devices *fs_devices; + struct btrfs_fs_devices *cur_fs_devices; + struct btrfs_fs_devices *sprt; //sprout fs devices + struct list_head *fs_uuids = btrfs_get_fs_uuids(); + struct list_head *cur_uuid; + + seq_printf(seq, "\n#Its Experimental, parameters may change without notice.\n\n"); + + mutex_lock(&uuid_mutex); + /* Todo: there must be better way than nested locks */ + list_for_each(cur_uuid, fs_uuids) { + cur_fs_devices = list_entry(cur_uuid, struct btrfs_fs_devices, list); + + mutex_lock(&cur_fs_devices->device_list_mutex); + + fs_devices = cur_fs_devices; + sprt = NULL; + +again_fs_devs: + if (sprt) { + BTRFS_SEQ_PRINT("[[seed_fsid: %pU]]\n", fs_devices->fsid); + BTRFS_SEQ_PRINT("\tsprout_fsid:\t\t%pU\n", sprt->fsid); + } else { + BTRFS_SEQ_PRINT("[fsid: %pU]\n", fs_devices->fsid); + } + if (fs_devices->seed) { + BTRFS_SEQ_PRINT("\tseed_fsid:\t\t%pU\n", fs_devices->seed->fsid); + } + BTRFS_SEQ_PRINT("\tfs_devs_addr:\t\t%p\n", fs_devices); + BTRFS_SEQ_PRINT("\tnum_devices:\t\t%llu\n", fs_devices->num_devices); + BTRFS_SEQ_PRINT("\topen_devices:\t\t%llu\n", fs_devices->open_devices); + BTRFS_SEQ_PRINT("\trw_devices:\t\t%llu\n", fs_devices->rw_devices); + BTRFS_SEQ_PRINT("\tmissing_devices:\t%llu\n", fs_devices->missing_devices); + BTRFS_SEQ_PRINT("\ttotal_rw_devices:\t%llu\n", fs_devices->total_rw_bytes); + BTRFS_SEQ_PRINT("\ttotal_devices:\t\t%llu\n", fs_devices->total_devices); + BTRFS_SEQ_PRINT("\topened:\t\t\t%d\n", fs_devices->opened); + BTRFS_SEQ_PRINT("\tseeding:\t\t%d\n", fs_devices->seeding); + BTRFS_SEQ_PRINT("\trotating:\t\t%d\n", fs_devices->rotating); + BTRFS_SEQ_PRINT("\tspare:\t\t\t%d\n", fs_devices->spare); + + BTRFS_SEQ_PRINT("\tfsid_kobj_state:\t%d\n", fs_devices->fsid_kobj.state_initialized); + BTRFS_SEQ_PRINT("\tfsid_kobj_insysfs:\t%d\n", fs_devices->fsid_kobj.state_in_sysfs); + + if (fs_devices->device_dir_kobj) { + BTRFS_SEQ_PRINT("\tdevice_kobj_state:\t%d\n", fs_devices->device_dir_kobj->state_initialized); + BTRFS_SEQ_PRINT("\tdevice_kobj_insysfs:\t%d\n", fs_devices->device_dir_kobj->state_in_sysfs); + } else { + BTRFS_SEQ_PRINT("\tdevice_kobj_state:\t%s\n", "null"); + BTRFS_SEQ_PRINT("\tdevice_kobj_insysfs:\t%s\n", "null"); + } + + list_for_each_entry(device, &fs_devices->devices, dev_list) { + BTRFS_SEQ_PRINT("\t[[uuid: %pU]]\n", device->uuid); + BTRFS_SEQ_PRINT("\t\tdev_addr:\t%p\n", device); + rcu_read_lock(); + BTRFS_SEQ_PRINT("\t\tdevice:\t\t%s\n", + device->name ? rcu_str_deref(device->name): "(null)"); + rcu_read_unlock(); + BTRFS_SEQ_PRINT("\t\tdevid:\t\t%llu\n", device->devid); + if (device->dev_root) { + BTRFS_SEQ_PRINT("\t\tdev_root_fsid:\t%pU\n", + device->dev_root->fs_info->fsid); + } + BTRFS_SEQ_PRINT("\t\tgeneration:\t%llu\n", device->generation); + BTRFS_SEQ_PRINT("\t\ttotal_bytes:\t%llu\n", device->total_bytes); + BTRFS_SEQ_PRINT("\t\tdev_totalbytes:\t%llu\n", device->disk_total_bytes); + BTRFS_SEQ_PRINT("\t\tbytes_used:\t%llu\n", device->bytes_used); + BTRFS_SEQ_PRINT("\t\ttype:\t\t%llu\n", device->type); + BTRFS_SEQ_PRINT("\t\tio_align:\t%u\n", device->io_align); + BTRFS_SEQ_PRINT("\t\tio_width:\t%u\n", device->io_width); + BTRFS_SEQ_PRINT("\t\tsector_size:\t%u\n", device->sector_size); + BTRFS_SEQ_PRINT("\t\tmode:\t\t0x%llx\n", (u64)device->mode); + BTRFS_SEQ_PRINT("\t\twriteable:\t%d\n", device->writeable); + BTRFS_SEQ_PRINT("\t\tin_fs_metadata:\t%d\n", device->in_fs_metadata); + BTRFS_SEQ_PRINT("\t\tmissing:\t%d\n", device->missing); + BTRFS_SEQ_PRINT("\t\tfailed:\t\t%d\n", device->failed); + BTRFS_SEQ_PRINT("\t\toffline:\t%d\n", device->offline); + BTRFS_SEQ_PRINT("\t\tcan_discard:\t%d\n", device->can_discard); + BTRFS_SEQ_PRINT("\t\treplace_tgtdev:\t%d\n", + device->is_tgtdev_for_dev_replace); + BTRFS_SEQ_PRINT("\t\tactive_pending:\t%d\n", device->running_pending); + BTRFS_SEQ_PRINT("\t\tnobarriers:\t%d\n", device->nobarriers); + BTRFS_SEQ_PRINT("\t\tdevstats_valid:\t%d\n", device->dev_stats_valid); + BTRFS_SEQ_PRINT("\t\tbdev:\t\t%s\n", device->bdev ? "not_null":"null"); + } + + if (fs_devices->seed) { + sprt = fs_devices; + fs_devices = fs_devices->seed; + goto again_fs_devs; + } + seq_printf(seq, "\n"); + + mutex_unlock(&cur_fs_devices->device_list_mutex); + } + mutex_unlock(&uuid_mutex); +} +static int btrfs_devlist_show(struct seq_file *seq, void *offset) +{ + btrfs_print_devlist(seq); + return 0; +} + +static int btrfs_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, btrfs_devlist_show, PDE_DATA(inode)); +} + +static const struct file_operations btrfs_seq_fops = { + .owner = THIS_MODULE, + .open = btrfs_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void btrfs_init_procfs(void) +{ + btrfs_proc_root = proc_mkdir(BTRFS_PROC_PATH, NULL); + if (btrfs_proc_root) + proc_create_data(BTRFS_PROC_DEVLIST, S_IRUGO, btrfs_proc_root, + &btrfs_seq_fops, NULL); + return; +} + +void btrfs_exit_procfs(void) +{ + if (btrfs_proc_root) + remove_proc_entry(BTRFS_PROC_DEVLIST, btrfs_proc_root); + remove_proc_entry(BTRFS_PROC_PATH, NULL); +} + +void btrfs_printk_fsdev(void) +{ + struct btrfs_device *device; + struct btrfs_fs_devices *fs_devices; + struct btrfs_fs_devices *cur_fs_devices; + struct btrfs_fs_devices *sprt; //sprout fs devices + struct list_head *fs_uuids = btrfs_get_fs_uuids(); + struct list_head *cur_uuid; + + list_for_each(cur_uuid, fs_uuids) { + cur_fs_devices = list_entry(cur_uuid, struct btrfs_fs_devices, list); + + fs_devices = cur_fs_devices; + sprt = NULL; + +again_fs_devs: + if (sprt) { + printk(KERN_INFO "[[seed_fsid: %pU]]\n", fs_devices->fsid); + printk(KERN_INFO "\tsprout_fsid:\t\t%pU\n", sprt->fsid); + } else { + printk(KERN_INFO "[fsid: %pU]\n", fs_devices->fsid); + } + if (fs_devices->seed) { + printk(KERN_INFO "\tseed_fsid:\t\t%pU\n", fs_devices->seed->fsid); + } + printk(KERN_INFO "\tfs_devs_addr:\t\t%p\n", fs_devices); + printk(KERN_INFO "\tnum_devices:\t\t%llu\n", fs_devices->num_devices); + printk(KERN_INFO "\topen_devices:\t\t%llu\n", fs_devices->open_devices); + printk(KERN_INFO "\trw_devices:\t\t%llu\n", fs_devices->rw_devices); + printk(KERN_INFO "\tmissing_devices:\t%llu\n", fs_devices->missing_devices); + printk(KERN_INFO "\ttotal_rw_devices:\t%llu\n", fs_devices->total_rw_bytes); + printk(KERN_INFO "\ttotal_devices:\t\t%llu\n", fs_devices->total_devices); + printk(KERN_INFO "\topened:\t\t\t%d\n", fs_devices->opened); + printk(KERN_INFO "\tseeding:\t\t%d\n", fs_devices->seeding); + printk(KERN_INFO "\trotating:\t\t%d\n", fs_devices->rotating); + printk(KERN_INFO "\tspare:\t\t\t%d\n", fs_devices->spare); + + printk(KERN_INFO "\tfsid_kobj_state:\t%d\n", fs_devices->fsid_kobj.state_initialized); + printk(KERN_INFO "\tfsid_kobj_insysfs:\t%d\n", fs_devices->fsid_kobj.state_in_sysfs); + + if (fs_devices->device_dir_kobj) { + printk(KERN_INFO "\tdevice_kobj_state:\t%d\n", fs_devices->device_dir_kobj->state_initialized); + printk(KERN_INFO "\tdevice_kobj_insysfs:\t%d\n", fs_devices->device_dir_kobj->state_in_sysfs); + } else { + printk(KERN_INFO "\tdevice_kobj_state:\t%s\n", "null"); + printk(KERN_INFO "\tdevice_kobj_insysfs:\t%s\n", "null"); + } + + printk(KERN_INFO "\tfs_info:\t\t%pK\n", fs_devices->fs_info); + + list_for_each_entry(device, &fs_devices->devices, dev_list) { + printk(KERN_INFO "\t[[uuid: %pU]]\n", device->uuid); + printk(KERN_INFO "\t\tdev_addr:\t%p\n", device); + rcu_read_lock(); + printk(KERN_INFO "\t\tdevice:\t\t%s\n", + device->name ? rcu_str_deref(device->name): "(null)"); + rcu_read_unlock(); + printk(KERN_INFO "\t\tdevid:\t\t%llu\n", device->devid); + if (device->dev_root) { + printk(KERN_INFO "\t\tdev_root_fsid:\t%pU\n", + device->dev_root->fs_info->fsid); + } + printk(KERN_INFO "\t\tgeneration:\t%llu\n", device->generation); + printk(KERN_INFO "\t\ttotal_bytes:\t%llu\n", device->total_bytes); + printk(KERN_INFO "\t\tdev_totalbytes:\t%llu\n", device->disk_total_bytes); + printk(KERN_INFO "\t\tbytes_used:\t%llu\n", device->bytes_used); + printk(KERN_INFO "\t\ttype:\t\t%llu\n", device->type); + printk(KERN_INFO "\t\tio_align:\t%u\n", device->io_align); + printk(KERN_INFO "\t\tio_width:\t%u\n", device->io_width); + printk(KERN_INFO "\t\tsector_size:\t%u\n", device->sector_size); + printk(KERN_INFO "\t\tmode:\t\t0x%llx\n", (u64)device->mode); + printk(KERN_INFO "\t\twriteable:\t%d\n", device->writeable); + printk(KERN_INFO "\t\tin_fs_metadata:\t%d\n", device->in_fs_metadata); + printk(KERN_INFO "\t\tmissing:\t%d\n", device->missing); + printk(KERN_INFO "\t\tfailed:\t\t%d\n", device->failed); + printk(KERN_INFO "\t\toffline:\t%d\n", device->offline); + printk(KERN_INFO "\t\tcan_discard:\t%d\n", device->can_discard); + printk(KERN_INFO "\t\treplace_tgtdev:\t%d\n", + device->is_tgtdev_for_dev_replace); + printk(KERN_INFO "\t\tactive_pending:\t%d\n", device->running_pending); + printk(KERN_INFO "\t\tnobarriers:\t%d\n", device->nobarriers); + printk(KERN_INFO "\t\tdevstats_valid:\t%d\n", device->dev_stats_valid); + printk(KERN_INFO "\t\tbdev:\t\t%s\n", device->bdev ? "not_null":"null"); + } + + if (fs_devices->seed) { + sprt = fs_devices; + fs_devices = fs_devices->seed; + goto again_fs_devs; + } + printk(KERN_INFO "\n"); + } +} diff --git a/fs/btrfs/procfs.h b/fs/btrfs/procfs.h new file mode 100644 index 000000000000..e36d2145804e --- /dev/null +++ b/fs/btrfs/procfs.h @@ -0,0 +1 @@ +void btrfs_printk_fsdev(void); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 138fca39ffbb..868ad9e4cde0 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2361,6 +2361,8 @@ static int __init init_btrfs_fs(void) if (err) goto free_hash; + btrfs_init_procfs(); + btrfs_init_compress(); err = btrfs_init_cachep(); @@ -2439,6 +2441,7 @@ free_cachep: btrfs_destroy_cachep(); free_compress: btrfs_exit_compress(); + btrfs_exit_procfs(); btrfs_exit_sysfs(); free_hash: btrfs_hash_exit(); @@ -2458,6 +2461,7 @@ static void __exit exit_btrfs_fs(void) btrfs_interface_exit(); btrfs_end_io_wq_exit(); unregister_filesystem(&btrfs_fs_type); + btrfs_exit_procfs(); btrfs_exit_sysfs(); btrfs_cleanup_fs_uuids(); btrfs_exit_compress();