@@ -11,7 +11,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
uuid-tree.o props.o free-space-tree.o tree-checker.o space-info.o \
- block-rsv.o delalloc-space.o block-group.o discard.o
+ block-rsv.o delalloc-space.o block-group.o discard.o procfs.o
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
new file mode 100644
@@ -0,0 +1,600 @@
+#include <linux/seq_file.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include "ctree.h"
+#include "volumes.h"
+#include "rcu-string.h"
+#include "procfs.h"
+
+#define BPSL 256
+
+#define BTRFS_PROC_PATH "fs/btrfs"
+#define BTRFS_PROC_DEVLIST "devlist"
+#define BTRFS_PROC_FSINFO "fsinfo"
+
+//#define USE_ALLOC_LIST
+//#define VOL_FLAGS
+//#define FS_OPEN_RW
+#define BALANCE_RUNNING
+//#define OLD_PROC
+
+struct proc_dir_entry *btrfs_proc_root;
+
+static void fs_state_to_str(struct btrfs_fs_info *fs_info, char *str)
+{
+ if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
+ strcat(str, "|ERROR");
+ if (test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state))
+ strcat(str, "|REMOUNTING");
+ if (test_bit(BTRFS_FS_STATE_TRANS_ABORTED, &fs_info->fs_state))
+ strcat(str, "|TRANS_ABORTED");
+ if (test_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state))
+ strcat(str, "|REPLACING");
+ if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
+ strcat(str, "|DUMMY");
+}
+
+static void fs_flags_to_str(struct btrfs_fs_info *fs_info, char *str)
+{
+ if (test_bit(BTRFS_FS_BARRIER, &fs_info->flags))
+ strcat(str, "|BARRIER");
+ if (test_bit(BTRFS_FS_CLOSING_START, &fs_info->flags))
+ strcat(str, "|CLOSING_START");
+ if (test_bit(BTRFS_FS_CLOSING_DONE, &fs_info->flags))
+ strcat(str, "|CLOSING_DONE");
+ if (test_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags))
+ strcat(str, "|RECOVERING");
+ if (test_bit(BTRFS_FS_OPEN, &fs_info->flags))
+ strcat(str, "|OPEN");
+ if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
+ strcat(str, "|QUOTA_ENABLED");
+ if (test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags))
+ strcat(str, "|UPDATE_UUID_TREE_GEN");
+ if (test_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags))
+ strcat(str, "|FREE_SPACE_TREE");
+ if (test_bit(BTRFS_FS_BTREE_ERR, &fs_info->flags))
+ strcat(str, "|BTREE_ERR");
+ if (test_bit(BTRFS_FS_LOG1_ERR, &fs_info->flags))
+ strcat(str, "|LOG1_ERR");
+ if (test_bit(BTRFS_FS_LOG2_ERR, &fs_info->flags))
+ strcat(str, "|LOG2_ERR");
+ if (test_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags))
+ strcat(str, "|QUOTA_OVERRIDE");
+ if (test_bit(BTRFS_FS_FROZEN, &fs_info->flags))
+ strcat(str, "|FROZEN");
+ if (test_bit(BTRFS_FS_EXCL_OP, &fs_info->flags))
+ strcat(str, "|EXCL_OP");
+#ifdef BALANCE_RUNNING
+ if (test_bit(BTRFS_FS_BALANCE_RUNNING, &fs_info->flags))
+ strcat(str, "|BALANCE_RUNNING");
+#else
+ if (atomic_read(&fs_info->balance_running))
+ strcat(str, "|BALANCE_RUNNING");
+#endif
+ if (atomic_read(&fs_info->balance_pause_req))
+ strcat(str, "|BALANCE_PAUSEREQ");
+ if (atomic_read(&fs_info->balance_cancel_req))
+ strcat(str, "|BALANCE_CANCELREQ");
+}
+
+static void balance_ctl_flags_to_str(struct btrfs_balance_control *bctl,
+ char *str)
+{
+ if (BTRFS_BALANCE_DATA & bctl->flags)
+ strcat(str, "|DATA");
+ if (BTRFS_BALANCE_SYSTEM & bctl->flags)
+ strcat(str, "|SYSTEM");
+ if (BTRFS_BALANCE_METADATA & bctl->flags)
+ strcat(str, "|METADATA");
+ if (BTRFS_BALANCE_FORCE & bctl->flags)
+ strcat(str, "|FORCE");
+ if (BTRFS_BALANCE_RESUME & bctl->flags)
+ strcat(str, "|RESUME");
+}
+
+static char *bg_flags_to_str(u64 chunk_type, char *str)
+{
+ if (chunk_type & BTRFS_BLOCK_GROUP_RAID0)
+ strcat(str, "|RAID0");
+ if (chunk_type & BTRFS_BLOCK_GROUP_RAID1)
+ strcat(str, "|RAID1");
+ if (chunk_type & BTRFS_BLOCK_GROUP_RAID5)
+ strcat(str, "|RAID5");
+ if (chunk_type & BTRFS_BLOCK_GROUP_RAID6)
+ strcat(str, "|RAID6");
+ if (chunk_type & BTRFS_BLOCK_GROUP_DUP)
+ strcat(str, "|DUP");
+ if (chunk_type & BTRFS_BLOCK_GROUP_RAID10)
+ strcat(str, "|RAID10");
+ if (chunk_type & BTRFS_AVAIL_ALLOC_BIT_SINGLE)
+ strcat(str, "|ALLOC_SINGLE");
+
+ return str;
+}
+
+static void balance_args_to_str(struct btrfs_balance_args *bargs, char *str,
+ char *prefix)
+{
+ int ret = 0;
+
+ ret = sprintf(str, "\tbalance_args.%s\t", prefix);
+ str=str+ret;
+
+ if (bargs->flags & BTRFS_BALANCE_ARGS_SOFT)
+ strcat(str, "|SOFT");
+
+ if (bargs->flags & BTRFS_BALANCE_ARGS_PROFILES) {
+ strcat(str, "|profiles=");
+ str = bg_flags_to_str(bargs->profiles, str);
+ str=str+ret;
+ }
+
+ if (bargs->flags & BTRFS_BALANCE_ARGS_USAGE) {
+ ret = sprintf(str, "|usage=%llu ", bargs->usage);
+ str=str+ret;
+ }
+
+ if (bargs->flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) {
+ ret = sprintf(str, "|usage_min=%u usage_max=%u",
+ bargs->usage_min, bargs->usage_max);
+ str=str+ret;
+ }
+
+ if (bargs->flags & BTRFS_BALANCE_ARGS_DEVID) {
+ ret = sprintf(str, "|devid=%llu ", bargs->devid);
+ str=str+ret;
+ }
+
+ if (bargs->flags & BTRFS_BALANCE_ARGS_DRANGE) {
+ ret = sprintf(str, "|DRANGE pstart=%llu pend=%llu ",
+ bargs->pstart, bargs->pend);
+ str=str+ret;
+ }
+
+ if (bargs->flags & BTRFS_BALANCE_ARGS_VRANGE) {
+ ret = sprintf(str, "|VRANGE vstart=%llu vend %llu",
+ bargs->vstart, bargs->vend);
+ str=str+ret;
+ }
+
+ if (bargs->flags & BTRFS_BALANCE_ARGS_LIMIT) {
+ ret = sprintf(str, "|limit=%llu ", bargs->limit);
+ str=str+ret;
+ }
+
+ if (bargs->flags & BTRFS_BALANCE_ARGS_LIMIT_RANGE) {
+ ret = sprintf(str, "|limit_min=%u limit_max=%u",
+ bargs->limit_min, bargs->limit_max);
+ str=str+ret;
+ }
+
+ if (bargs->flags & BTRFS_BALANCE_ARGS_STRIPES_RANGE) {
+ ret = sprintf(str, "|stripes_min=%u stripes_max=%u ",
+ bargs->stripes_min, bargs->stripes_max);
+ str=str+ret;
+ }
+
+ if (bargs->flags & BTRFS_BALANCE_ARGS_CONVERT) {
+ strcat(str, "|convert=");
+ str = bg_flags_to_str(bargs->target, str);
+ }
+}
+
+static void print_balance_args(struct btrfs_balance_args *bargs, char *prefix,
+ struct seq_file *seq)
+{
+#define BTRFS_SEQ_PRINT3(plist, arg)\
+ snprintf(__str, BPSL, plist, arg);\
+ seq_printf(seq, __str)
+ char __str[BPSL];
+
+ char tmp_str[BPSL];
+
+ memset(tmp_str, '\0', 256);
+ balance_args_to_str(bargs, tmp_str, prefix);
+ BTRFS_SEQ_PRINT3("%s\n", tmp_str);
+}
+
+static void balance_progress_to_str(struct btrfs_balance_progress *bstat, char *str)
+{
+ int ret=0;
+ ret = sprintf(str, "expected=%llu ", bstat->expected);
+ str=str+ret;
+ ret = sprintf(str, "considered=%llu ", bstat->considered);
+ str=str+ret;
+ ret = sprintf(str, "completed=%llu ", bstat->completed);
+}
+
+void btrfs_print_fsinfo(struct seq_file *seq)
+{
+ /* Btrfs Procfs String Len */
+#define BTRFS_SEQ_PRINT2(plist, arg)\
+ snprintf(str, BPSL, plist, arg);\
+ seq_printf(seq, str)
+
+ char str[BPSL];
+ char b[BDEVNAME_SIZE];
+ struct list_head *cur_uuid;
+ struct btrfs_fs_info *fs_info;
+ struct btrfs_fs_devices *fs_devices;
+ struct list_head *fs_uuids = btrfs_get_fs_uuids();
+
+ seq_printf(seq, "\n#Its for debugging and experimental only, parameters may change without notice.\n\n");
+
+ list_for_each(cur_uuid, fs_uuids) {
+ char fs_str[256] = {0};
+ fs_devices = list_entry(cur_uuid, struct btrfs_fs_devices, fs_list);
+ fs_info = fs_devices->fs_info;
+ if (!fs_info)
+ continue;
+
+ BTRFS_SEQ_PRINT2("[fsid: %pU]\n", fs_devices->fsid);
+ BTRFS_SEQ_PRINT2("\tsb->s_bdev:\t\t%s\n",
+ fs_info->sb->s_bdev ?
+ bdevname(fs_info->sb->s_bdev, b):
+ "null");
+ BTRFS_SEQ_PRINT2("\tlatest_bdev:\t\t%s\n",
+ fs_devices->latest_bdev ?
+ bdevname(fs_devices->latest_bdev, b):
+ "null");
+
+ fs_state_to_str(fs_info, fs_str);
+ BTRFS_SEQ_PRINT2("\tfs_state:\t\t%s\n", fs_str);
+
+ memset(fs_str, '\0', 256);
+ fs_flags_to_str(fs_info, fs_str);
+ BTRFS_SEQ_PRINT2("\tfs_flags:\t\t%s\n", fs_str);
+
+ BTRFS_SEQ_PRINT2("\tsuper_copy->flags\t0x%llx\n",
+ fs_info->super_copy->flags);
+ BTRFS_SEQ_PRINT2("\tsuper_for_commit->flags\t0x%llx\n",
+ fs_info->super_for_commit->flags);
+ BTRFS_SEQ_PRINT2("\tnodesize\t\t%u\n", fs_info->nodesize);
+ BTRFS_SEQ_PRINT2("\tsectorsize\t\t%u\n", fs_info->sectorsize);
+
+ if (fs_info->balance_ctl) {
+ memset(fs_str, '\0', 256);
+ balance_ctl_flags_to_str(fs_info->balance_ctl, fs_str);
+ BTRFS_SEQ_PRINT2("\tbalance_control\t\t%s\n", fs_str);
+
+ if (fs_info->balance_ctl->flags & BTRFS_BALANCE_DATA)
+ print_balance_args(&fs_info->balance_ctl->data, "data", seq);
+ if (fs_info->balance_ctl->flags & BTRFS_BALANCE_METADATA)
+ print_balance_args(&fs_info->balance_ctl->meta, "meta", seq);
+ if (fs_info->balance_ctl->flags & BTRFS_BALANCE_SYSTEM)
+ print_balance_args(&fs_info->balance_ctl->sys, "sys", seq);
+
+ memset(fs_str, '\0', 256);
+ balance_progress_to_str(&fs_info->balance_ctl->stat, fs_str);
+ BTRFS_SEQ_PRINT2("\tbalance_progress\t%s\n", fs_str);
+
+ } else {
+ BTRFS_SEQ_PRINT2("\tbalance_control\t\t%s\n", "null");
+ }
+
+ BTRFS_SEQ_PRINT2("\tdev_replace.replace_state\t\t%llu\n",
+ fs_info->dev_replace.replace_state);
+ BTRFS_SEQ_PRINT2("\tdev_replace.time start\t\t%lld\n",
+ fs_info->dev_replace.time_started);
+ BTRFS_SEQ_PRINT2("\tdev_replace.time stopped\t%lld\n",
+ fs_info->dev_replace.time_stopped);
+ BTRFS_SEQ_PRINT2("\tdev_replace.cursor_left\t\t%llu\n",
+ fs_info->dev_replace.cursor_left);
+ BTRFS_SEQ_PRINT2("\tdev_replace.committed_cursor_left\t%llu\n",
+ fs_info->dev_replace.committed_cursor_left);
+ BTRFS_SEQ_PRINT2("\tdev_replace.cursor_left_last_write_of_item\t%llu\n",
+ fs_info->dev_replace.cursor_left_last_write_of_item);
+ BTRFS_SEQ_PRINT2("\tdev_replace.cursor_right\t\t%llu\n",
+ fs_info->dev_replace.cursor_right);
+ BTRFS_SEQ_PRINT2("\tdev_replace.cont_reading_from_srcdev_mode\t%llu\n",
+ fs_info->dev_replace.cont_reading_from_srcdev_mode);
+ BTRFS_SEQ_PRINT2("\tdev_replace.is_valid\t\t\t%d\n",
+ fs_info->dev_replace.is_valid);
+ BTRFS_SEQ_PRINT2("\tdev_replace.item_needs_writeback\t%d\n",
+ fs_info->dev_replace.item_needs_writeback);
+ BTRFS_SEQ_PRINT2("\tdev_replace.srcdev\t\t\t%p\n",
+ fs_info->dev_replace.srcdev);
+ BTRFS_SEQ_PRINT2("\tdev_replace.tgtdev\t\t\t%p\n",
+ fs_info->dev_replace.tgtdev);
+ BTRFS_SEQ_PRINT2("\tdev_replace.bio_counter.count\t\t%llu\n",
+ fs_info->dev_replace.bio_counter.count);
+ }
+}
+
+static void dev_state_to_str(struct btrfs_device *device, char *dev_state_str)
+{
+ if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state))
+ strcat(dev_state_str, "|WRITEABLE");
+ if (test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state))
+ strcat(dev_state_str, "|IN_FS_METADATA");
+ if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state))
+ strcat(dev_state_str, "|MISSING");
+ if (test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state))
+ strcat(dev_state_str, "|REPLACE_TGT");
+ if (test_bit(BTRFS_DEV_STATE_FLUSH_SENT, &device->dev_state))
+ strcat(dev_state_str, "|FLUSH_SENT");
+#ifdef READPOLICY
+ if (test_bit(BTRFS_DEV_STATE_RD_PREFERRED, &device->dev_state))
+ strcat(dev_state_str, "|RD_PREFFRRED");
+#endif
+ if (device->dev_stats_valid)
+ strcat(dev_state_str, "|dev_stats_valid");
+}
+
+#ifdef VOL_FLAGS
+static void vol_flags_to_str(struct btrfs_fs_devices *fs_devices, char *vol_flags)
+{
+ if (test_bit(BTRFS_VOL_FLAG_ROTATING, &fs_devices->vol_flags))
+ strcat(vol_flags, "|ROTATING");
+ if (test_bit(BTRFS_VOL_FLAG_SEEDING, &fs_devices->vol_flags))
+ strcat(vol_flags, "|SEEDING");
+ if (test_bit(BTRFS_VOL_FLAG_EXCL_OPS, &fs_devices->vol_flags))
+ strcat(vol_flags, "|EXCL_OPS");
+}
+#endif
+
+void btrfs_print_devlist(struct seq_file *seq, struct btrfs_fs_devices *the_fs_devices)
+{
+/* Btrfs Procfs String Len */
+#define BTRFS_SEQ_PRINT(plist, arg)\
+ snprintf(str, BPSL, plist, arg);\
+ if (sprt) {\
+ if (seq) {\
+ seq_printf(seq, "\t");\
+ }\
+ }\
+ if (seq) {\
+ seq_printf(seq, str);\
+ } else {\
+ printk("boilerplate: %s", 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;
+
+ if (seq)
+ seq_printf(seq, "\n#Its for debugging and experimental only, parameters may change without notice.\n\n");
+
+ /* Todo: there must be better way than nested locks */
+ list_for_each(cur_uuid, fs_uuids) {
+#ifdef VOL_FLAGS
+ char vol_flags[256] = {0};
+#endif
+ cur_fs_devices = list_entry(cur_uuid, struct btrfs_fs_devices, fs_list);
+
+ mutex_lock(&cur_fs_devices->device_list_mutex);
+
+ fs_devices = cur_fs_devices;
+ sprt = NULL;
+
+again_fs_devs:
+ if (the_fs_devices && the_fs_devices != cur_fs_devices)
+ goto skip;
+
+ 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("\tmetadata_uuid:\t\t%pU\n", fs_devices->metadata_uuid);
+ 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_bytes:\t\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);
+#ifdef VOL_FLAGS
+ vol_flags_to_str(fs_devices, vol_flags);
+ BTRFS_SEQ_PRINT("\vol_flags:\\%s\n", vol_flags);
+#else
+ BTRFS_SEQ_PRINT("\tseeding:\t\t%d\n", fs_devices->seeding);
+ BTRFS_SEQ_PRINT("\trotating:\t\t%d\n", fs_devices->rotating);
+#endif
+ 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->devices_kobj) {
+ BTRFS_SEQ_PRINT("\tkobj_state:\t\t%d\n", fs_devices->devices_kobj->state_initialized);
+ BTRFS_SEQ_PRINT("\tkobj_insysfs:\t\t%d\n", fs_devices->devices_kobj->state_in_sysfs);
+ } else {
+ BTRFS_SEQ_PRINT("\tkobj_state:\t\t%s\n", "null");
+ BTRFS_SEQ_PRINT("\tkobj_insysfs:\t\t%s\n", "null");
+ }
+
+#ifdef READPOLICY
+ switch (fs_devices->read_policy) {
+ case BTRFS_READ_POLICY_PID:
+ BTRFS_SEQ_PRINT2("\tread_policy\t\t%s\n", "BTRFS_READ_POLICY_PID:");
+ break;
+ case BTRFS_READ_POLICY_DEVICE:
+ list_for_each_entry(device, &fs_devices->devices, dev_list) {
+ if (test_bit(BTRFS_DEV_STATE_RD_PREFERRED, &device->dev_state)) {
+ BTRFS_SEQ_PRINT("%llu ", device->devid);
+ }
+ }
+ BTRFS_SEQ_PRINT("%s\n", " ");
+ break;
+ default:
+ BTRFS_SEQ_PRINT2("\tread_policy\t%s\n", "unknown\n");
+ }
+#endif
+ list_for_each_entry(device, &fs_devices->devices, dev_list) {
+ char dev_state_str[256] = {0};
+
+ 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);
+ 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);
+ dev_state_to_str(device, dev_state_str);
+ if (strlen(dev_state_str) == 0) {
+ BTRFS_SEQ_PRINT("\t\tdev_state:\t0x%lx\n", device->dev_state);
+ } else {
+ BTRFS_SEQ_PRINT("\t\tdev_state:\t%s\n", dev_state_str);
+ }
+ BTRFS_SEQ_PRINT("\t\tbdev:\t\t%s\n", device->bdev ? "not_null":"null");
+ if (device->bdev) {
+ struct backing_dev_info *bdi = device->bdev->bd_bdi;
+ BTRFS_SEQ_PRINT("\t\tbdi:\t\t%s\n", bdi ? "not_null": "null");
+ if (bdi) {
+ struct bdi_writeback *wb = &bdi->wb;
+ BTRFS_SEQ_PRINT("\t\twb:\t\t%s\n", wb ? "not_null": "null");
+ if (wb) {
+ BTRFS_SEQ_PRINT("\t\twb congested state:\t%lx\n", wb->congested->state);
+ }
+ }
+ }
+ }
+
+#ifdef USE_ALLOC_LIST
+ /* print device from the alloc_list */
+ list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) {
+ char dev_state_str[256] = {0};
+
+ 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);
+ 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);
+ dev_state_to_str(device, dev_state_str);
+ if (strlen(dev_state_str) == 0) {
+ BTRFS_SEQ_PRINT("\t\tdev_state:\t0x%lx\n", device->dev_state);
+ } else {
+ BTRFS_SEQ_PRINT("\t\tdev_state:\t%s\n", dev_state_str);
+ }
+ BTRFS_SEQ_PRINT("\t\tbdev:\t\t%s\n", device->bdev ? "not_null":"null");
+ if (device->bdev) {
+ struct backing_dev_info *bdi = device->bdev->bd_bdi;
+ BTRFS_SEQ_PRINT("\t\tbdi:\t\t%s\n", bdi ? "not_null": "null");
+ if (bdi) {
+ struct bdi_writeback *wb = &bdi->wb;
+ BTRFS_SEQ_PRINT("\t\twb:\t\t%s\n", wb ? "not_null": "null");
+ if (wb) {
+ BTRFS_SEQ_PRINT("\t\twb congested state:\t%lx\n", wb->congested->state);
+ }
+ }
+ }
+ }
+#endif
+skip:
+ if (fs_devices->seed) {
+ sprt = fs_devices;
+ fs_devices = fs_devices->seed;
+ goto again_fs_devs;
+ }
+ if (seq)
+ seq_printf(seq, "\n");
+
+ mutex_unlock(&cur_fs_devices->device_list_mutex);
+ }
+}
+
+static int btrfs_fsinfo_show(struct seq_file *seq, void *offset)
+{
+ btrfs_print_fsinfo(seq);
+ return 0;
+}
+
+static int btrfs_devlist_show(struct seq_file *seq, void *offset)
+{
+ btrfs_print_devlist(seq, NULL);
+ return 0;
+}
+
+static int btrfs_seq_fsinfo_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, btrfs_fsinfo_show, PDE_DATA(inode));
+}
+
+static int btrfs_seq_devlist_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, btrfs_devlist_show, PDE_DATA(inode));
+}
+
+#ifdef OLD_PROC
+static const struct file_operations btrfs_seq_devlist_fops = {
+ .owner = THIS_MODULE,
+ .open = btrfs_seq_devlist_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#else
+static const struct proc_ops btrfs_seq_devlist_fops = {
+ .proc_open = btrfs_seq_devlist_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+};
+#endif
+
+#ifdef OLD_PROC
+static const struct file_operations btrfs_seq_fsinfo_fops = {
+ .owner = THIS_MODULE,
+ .open = btrfs_seq_fsinfo_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#else
+static const struct proc_ops btrfs_seq_fsinfo_fops = {
+ .proc_open = btrfs_seq_fsinfo_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+};
+#endif
+
+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_devlist_fops, NULL);
+ proc_create_data(BTRFS_PROC_FSINFO, S_IRUGO, btrfs_proc_root,
+ &btrfs_seq_fsinfo_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_FSINFO, btrfs_proc_root);
+ }
+ remove_proc_entry(BTRFS_PROC_PATH, NULL);
+}
new file mode 100644
@@ -0,0 +1,2 @@
+void btrfs_exit_procfs(void);
+void btrfs_init_procfs(void);
@@ -47,7 +47,7 @@
#include "tests/btrfs-tests.h"
#include "block-group.h"
#include "discard.h"
-
+#include "procfs.h"
#include "qgroup.h"
#define CREATE_TRACE_POINTS
#include <trace/events/btrfs.h>
@@ -2393,6 +2393,8 @@ static int __init init_btrfs_fs(void)
if (err)
return err;
+ btrfs_init_procfs();
+
btrfs_init_compress();
err = btrfs_init_cachep();
@@ -2477,6 +2479,7 @@ static int __init init_btrfs_fs(void)
btrfs_destroy_cachep();
free_compress:
btrfs_exit_compress();
+ btrfs_exit_procfs();
btrfs_exit_sysfs();
return err;
@@ -2496,6 +2499,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();