aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/s390/block/dasd.c576
-rw-r--r--drivers/s390/block/dasd_int.h57
-rw-r--r--drivers/s390/block/dasd_ioctl.c38
-rw-r--r--drivers/s390/block/dasd_proc.c106
4 files changed, 686 insertions, 91 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 86b6f1cc1b1..432444af7ee 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -22,6 +22,8 @@
22#include <linux/hdreg.h> 22#include <linux/hdreg.h>
23#include <linux/async.h> 23#include <linux/async.h>
24#include <linux/mutex.h> 24#include <linux/mutex.h>
25#include <linux/debugfs.h>
26#include <linux/seq_file.h>
25 27
26#include <asm/ccwdev.h> 28#include <asm/ccwdev.h>
27#include <asm/ebcdic.h> 29#include <asm/ebcdic.h>
@@ -45,6 +47,7 @@
45 * SECTION: exported variables of dasd.c 47 * SECTION: exported variables of dasd.c
46 */ 48 */
47debug_info_t *dasd_debug_area; 49debug_info_t *dasd_debug_area;
50static struct dentry *dasd_debugfs_root_entry;
48struct dasd_discipline *dasd_diag_discipline_pointer; 51struct dasd_discipline *dasd_diag_discipline_pointer;
49void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); 52void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
50 53
@@ -71,6 +74,8 @@ static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
71static void dasd_device_timeout(unsigned long); 74static void dasd_device_timeout(unsigned long);
72static void dasd_block_timeout(unsigned long); 75static void dasd_block_timeout(unsigned long);
73static void __dasd_process_erp(struct dasd_device *, struct dasd_ccw_req *); 76static void __dasd_process_erp(struct dasd_device *, struct dasd_ccw_req *);
77static void dasd_profile_init(struct dasd_profile *, struct dentry *);
78static void dasd_profile_exit(struct dasd_profile *);
74 79
75/* 80/*
76 * SECTION: Operations on the device structure. 81 * SECTION: Operations on the device structure.
@@ -121,7 +126,7 @@ struct dasd_device *dasd_alloc_device(void)
121 device->state = DASD_STATE_NEW; 126 device->state = DASD_STATE_NEW;
122 device->target = DASD_STATE_NEW; 127 device->target = DASD_STATE_NEW;
123 mutex_init(&device->state_mutex); 128 mutex_init(&device->state_mutex);
124 129 spin_lock_init(&device->profile.lock);
125 return device; 130 return device;
126} 131}
127 132
@@ -159,6 +164,7 @@ struct dasd_block *dasd_alloc_block(void)
159 init_timer(&block->timer); 164 init_timer(&block->timer);
160 block->timer.function = dasd_block_timeout; 165 block->timer.function = dasd_block_timeout;
161 block->timer.data = (unsigned long) block; 166 block->timer.data = (unsigned long) block;
167 spin_lock_init(&block->profile.lock);
162 168
163 return block; 169 return block;
164} 170}
@@ -222,19 +228,44 @@ static int dasd_state_known_to_new(struct dasd_device *device)
222 return 0; 228 return 0;
223} 229}
224 230
231static struct dentry *dasd_debugfs_setup(const char *name,
232 struct dentry *base_dentry)
233{
234 struct dentry *pde;
235
236 if (!base_dentry)
237 return NULL;
238 pde = debugfs_create_dir(name, base_dentry);
239 if (!pde || IS_ERR(pde))
240 return NULL;
241 return pde;
242}
243
225/* 244/*
226 * Request the irq line for the device. 245 * Request the irq line for the device.
227 */ 246 */
228static int dasd_state_known_to_basic(struct dasd_device *device) 247static int dasd_state_known_to_basic(struct dasd_device *device)
229{ 248{
249 struct dasd_block *block = device->block;
230 int rc; 250 int rc;
231 251
232 /* Allocate and register gendisk structure. */ 252 /* Allocate and register gendisk structure. */
233 if (device->block) { 253 if (block) {
234 rc = dasd_gendisk_alloc(device->block); 254 rc = dasd_gendisk_alloc(block);
235 if (rc) 255 if (rc)
236 return rc; 256 return rc;
237 } 257 block->debugfs_dentry =
258 dasd_debugfs_setup(block->gdp->disk_name,
259 dasd_debugfs_root_entry);
260 dasd_profile_init(&block->profile, block->debugfs_dentry);
261 if (dasd_global_profile_level == DASD_PROFILE_ON)
262 dasd_profile_on(&device->block->profile);
263 }
264 device->debugfs_dentry =
265 dasd_debugfs_setup(dev_name(&device->cdev->dev),
266 dasd_debugfs_root_entry);
267 dasd_profile_init(&device->profile, device->debugfs_dentry);
268
238 /* register 'device' debug area, used for all DBF_DEV_XXX calls */ 269 /* register 'device' debug area, used for all DBF_DEV_XXX calls */
239 device->debug_area = debug_register(dev_name(&device->cdev->dev), 4, 1, 270 device->debug_area = debug_register(dev_name(&device->cdev->dev), 4, 1,
240 8 * sizeof(long)); 271 8 * sizeof(long));
@@ -253,6 +284,9 @@ static int dasd_state_basic_to_known(struct dasd_device *device)
253{ 284{
254 int rc; 285 int rc;
255 if (device->block) { 286 if (device->block) {
287 dasd_profile_exit(&device->block->profile);
288 if (device->block->debugfs_dentry)
289 debugfs_remove(device->block->debugfs_dentry);
256 dasd_gendisk_free(device->block); 290 dasd_gendisk_free(device->block);
257 dasd_block_clear_timer(device->block); 291 dasd_block_clear_timer(device->block);
258 } 292 }
@@ -260,6 +294,9 @@ static int dasd_state_basic_to_known(struct dasd_device *device)
260 if (rc) 294 if (rc)
261 return rc; 295 return rc;
262 dasd_device_clear_timer(device); 296 dasd_device_clear_timer(device);
297 dasd_profile_exit(&device->profile);
298 if (device->debugfs_dentry)
299 debugfs_remove(device->debugfs_dentry);
263 300
264 DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device); 301 DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device);
265 if (device->debug_area != NULL) { 302 if (device->debug_area != NULL) {
@@ -609,21 +646,13 @@ void dasd_enable_device(struct dasd_device *device)
609/* 646/*
610 * SECTION: device operation (interrupt handler, start i/o, term i/o ...) 647 * SECTION: device operation (interrupt handler, start i/o, term i/o ...)
611 */ 648 */
612#ifdef CONFIG_DASD_PROFILE
613 649
614struct dasd_profile_info_t dasd_global_profile; 650unsigned int dasd_global_profile_level = DASD_PROFILE_OFF;
615unsigned int dasd_profile_level = DASD_PROFILE_OFF;
616 651
617/* 652#ifdef CONFIG_DASD_PROFILE
618 * Increments counter in global and local profiling structures. 653struct dasd_profile_info dasd_global_profile_data;
619 */ 654static struct dentry *dasd_global_profile_dentry;
620#define dasd_profile_counter(value, counter, block) \ 655static struct dentry *dasd_debugfs_global_entry;
621{ \
622 int index; \
623 for (index = 0; index < 31 && value >> (2+index); index++); \
624 dasd_global_profile.counter[index]++; \
625 block->profile.counter[index]++; \
626}
627 656
628/* 657/*
629 * Add profiling information for cqr before execution. 658 * Add profiling information for cqr before execution.
@@ -634,30 +663,121 @@ static void dasd_profile_start(struct dasd_block *block,
634{ 663{
635 struct list_head *l; 664 struct list_head *l;
636 unsigned int counter; 665 unsigned int counter;
637 666 struct dasd_device *device;
638 if (dasd_profile_level != DASD_PROFILE_ON)
639 return;
640 667
641 /* count the length of the chanq for statistics */ 668 /* count the length of the chanq for statistics */
642 counter = 0; 669 counter = 0;
643 list_for_each(l, &block->ccw_queue) 670 if (dasd_global_profile_level || block->profile.data)
644 if (++counter >= 31) 671 list_for_each(l, &block->ccw_queue)
645 break; 672 if (++counter >= 31)
646 dasd_global_profile.dasd_io_nr_req[counter]++; 673 break;
647 block->profile.dasd_io_nr_req[counter]++; 674
675 if (dasd_global_profile_level) {
676 dasd_global_profile_data.dasd_io_nr_req[counter]++;
677 if (rq_data_dir(req) == READ)
678 dasd_global_profile_data.dasd_read_nr_req[counter]++;
679 }
680
681 spin_lock(&block->profile.lock);
682 if (block->profile.data)
683 block->profile.data->dasd_io_nr_req[counter]++;
684 if (rq_data_dir(req) == READ)
685 block->profile.data->dasd_read_nr_req[counter]++;
686 spin_unlock(&block->profile.lock);
687
688 /*
689 * We count the request for the start device, even though it may run on
690 * some other device due to error recovery. This way we make sure that
691 * we count each request only once.
692 */
693 device = cqr->startdev;
694 if (device->profile.data) {
695 counter = 1; /* request is not yet queued on the start device */
696 list_for_each(l, &device->ccw_queue)
697 if (++counter >= 31)
698 break;
699 }
700 spin_lock(&device->profile.lock);
701 if (device->profile.data) {
702 device->profile.data->dasd_io_nr_req[counter]++;
703 if (rq_data_dir(req) == READ)
704 device->profile.data->dasd_read_nr_req[counter]++;
705 }
706 spin_unlock(&device->profile.lock);
648} 707}
649 708
650/* 709/*
651 * Add profiling information for cqr after execution. 710 * Add profiling information for cqr after execution.
652 */ 711 */
712
713#define dasd_profile_counter(value, index) \
714{ \
715 for (index = 0; index < 31 && value >> (2+index); index++) \
716 ; \
717}
718
719static void dasd_profile_end_add_data(struct dasd_profile_info *data,
720 int is_alias,
721 int is_tpm,
722 int is_read,
723 long sectors,
724 int sectors_ind,
725 int tottime_ind,
726 int tottimeps_ind,
727 int strtime_ind,
728 int irqtime_ind,
729 int irqtimeps_ind,
730 int endtime_ind)
731{
732 /* in case of an overflow, reset the whole profile */
733 if (data->dasd_io_reqs == UINT_MAX) {
734 memset(data, 0, sizeof(*data));
735 getnstimeofday(&data->starttod);
736 }
737 data->dasd_io_reqs++;
738 data->dasd_io_sects += sectors;
739 if (is_alias)
740 data->dasd_io_alias++;
741 if (is_tpm)
742 data->dasd_io_tpm++;
743
744 data->dasd_io_secs[sectors_ind]++;
745 data->dasd_io_times[tottime_ind]++;
746 data->dasd_io_timps[tottimeps_ind]++;
747 data->dasd_io_time1[strtime_ind]++;
748 data->dasd_io_time2[irqtime_ind]++;
749 data->dasd_io_time2ps[irqtimeps_ind]++;
750 data->dasd_io_time3[endtime_ind]++;
751
752 if (is_read) {
753 data->dasd_read_reqs++;
754 data->dasd_read_sects += sectors;
755 if (is_alias)
756 data->dasd_read_alias++;
757 if (is_tpm)
758 data->dasd_read_tpm++;
759 data->dasd_read_secs[sectors_ind]++;
760 data->dasd_read_times[tottime_ind]++;
761 data->dasd_read_time1[strtime_ind]++;
762 data->dasd_read_time2[irqtime_ind]++;
763 data->dasd_read_time3[endtime_ind]++;
764 }
765}
766
653static void dasd_profile_end(struct dasd_block *block, 767static void dasd_profile_end(struct dasd_block *block,
654 struct dasd_ccw_req *cqr, 768 struct dasd_ccw_req *cqr,
655 struct request *req) 769 struct request *req)
656{ 770{
657 long strtime, irqtime, endtime, tottime; /* in microseconds */ 771 long strtime, irqtime, endtime, tottime; /* in microseconds */
658 long tottimeps, sectors; 772 long tottimeps, sectors;
773 struct dasd_device *device;
774 int sectors_ind, tottime_ind, tottimeps_ind, strtime_ind;
775 int irqtime_ind, irqtimeps_ind, endtime_ind;
659 776
660 if (dasd_profile_level != DASD_PROFILE_ON) 777 device = cqr->startdev;
778 if (!(dasd_global_profile_level ||
779 block->profile.data ||
780 device->profile.data))
661 return; 781 return;
662 782
663 sectors = blk_rq_sectors(req); 783 sectors = blk_rq_sectors(req);
@@ -672,29 +792,392 @@ static void dasd_profile_end(struct dasd_block *block,
672 tottime = ((cqr->endclk - cqr->buildclk) >> 12); 792 tottime = ((cqr->endclk - cqr->buildclk) >> 12);
673 tottimeps = tottime / sectors; 793 tottimeps = tottime / sectors;
674 794
675 if (!dasd_global_profile.dasd_io_reqs) 795 dasd_profile_counter(sectors, sectors_ind);
676 memset(&dasd_global_profile, 0, 796 dasd_profile_counter(tottime, tottime_ind);
677 sizeof(struct dasd_profile_info_t)); 797 dasd_profile_counter(tottimeps, tottimeps_ind);
678 dasd_global_profile.dasd_io_reqs++; 798 dasd_profile_counter(strtime, strtime_ind);
679 dasd_global_profile.dasd_io_sects += sectors; 799 dasd_profile_counter(irqtime, irqtime_ind);
680 800 dasd_profile_counter(irqtime / sectors, irqtimeps_ind);
681 if (!block->profile.dasd_io_reqs) 801 dasd_profile_counter(endtime, endtime_ind);
682 memset(&block->profile, 0, 802
683 sizeof(struct dasd_profile_info_t)); 803 if (dasd_global_profile_level) {
684 block->profile.dasd_io_reqs++; 804 dasd_profile_end_add_data(&dasd_global_profile_data,
685 block->profile.dasd_io_sects += sectors; 805 cqr->startdev != block->base,
686 806 cqr->cpmode == 1,
687 dasd_profile_counter(sectors, dasd_io_secs, block); 807 rq_data_dir(req) == READ,
688 dasd_profile_counter(tottime, dasd_io_times, block); 808 sectors, sectors_ind, tottime_ind,
689 dasd_profile_counter(tottimeps, dasd_io_timps, block); 809 tottimeps_ind, strtime_ind,
690 dasd_profile_counter(strtime, dasd_io_time1, block); 810 irqtime_ind, irqtimeps_ind,
691 dasd_profile_counter(irqtime, dasd_io_time2, block); 811 endtime_ind);
692 dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, block); 812 }
693 dasd_profile_counter(endtime, dasd_io_time3, block); 813
814 spin_lock(&block->profile.lock);
815 if (block->profile.data)
816 dasd_profile_end_add_data(block->profile.data,
817 cqr->startdev != block->base,
818 cqr->cpmode == 1,
819 rq_data_dir(req) == READ,
820 sectors, sectors_ind, tottime_ind,
821 tottimeps_ind, strtime_ind,
822 irqtime_ind, irqtimeps_ind,
823 endtime_ind);
824 spin_unlock(&block->profile.lock);
825
826 spin_lock(&device->profile.lock);
827 if (device->profile.data)
828 dasd_profile_end_add_data(device->profile.data,
829 cqr->startdev != block->base,
830 cqr->cpmode == 1,
831 rq_data_dir(req) == READ,
832 sectors, sectors_ind, tottime_ind,
833 tottimeps_ind, strtime_ind,
834 irqtime_ind, irqtimeps_ind,
835 endtime_ind);
836 spin_unlock(&device->profile.lock);
837}
838
839void dasd_profile_reset(struct dasd_profile *profile)
840{
841 struct dasd_profile_info *data;
842
843 spin_lock_bh(&profile->lock);
844 data = profile->data;
845 if (!data) {
846 spin_unlock_bh(&profile->lock);
847 return;
848 }
849 memset(data, 0, sizeof(*data));
850 getnstimeofday(&data->starttod);
851 spin_unlock_bh(&profile->lock);
852}
853
854void dasd_global_profile_reset(void)
855{
856 memset(&dasd_global_profile_data, 0, sizeof(dasd_global_profile_data));
857 getnstimeofday(&dasd_global_profile_data.starttod);
858}
859
860int dasd_profile_on(struct dasd_profile *profile)
861{
862 struct dasd_profile_info *data;
863
864 data = kzalloc(sizeof(*data), GFP_KERNEL);
865 if (!data)
866 return -ENOMEM;
867 spin_lock_bh(&profile->lock);
868 if (profile->data) {
869 spin_unlock_bh(&profile->lock);
870 kfree(data);
871 return 0;
872 }
873 getnstimeofday(&data->starttod);
874 profile->data = data;
875 spin_unlock_bh(&profile->lock);
876 return 0;
877}
878
879void dasd_profile_off(struct dasd_profile *profile)
880{
881 spin_lock_bh(&profile->lock);
882 kfree(profile->data);
883 profile->data = NULL;
884 spin_unlock_bh(&profile->lock);
885}
886
887char *dasd_get_user_string(const char __user *user_buf, size_t user_len)
888{
889 char *buffer;
890
891 buffer = kmalloc(user_len + 1, GFP_KERNEL);
892 if (buffer == NULL)
893 return ERR_PTR(-ENOMEM);
894 if (copy_from_user(buffer, user_buf, user_len) != 0) {
895 kfree(buffer);
896 return ERR_PTR(-EFAULT);
897 }
898 /* got the string, now strip linefeed. */
899 if (buffer[user_len - 1] == '\n')
900 buffer[user_len - 1] = 0;
901 else
902 buffer[user_len] = 0;
903 return buffer;
694} 904}
905
906static ssize_t dasd_stats_write(struct file *file,
907 const char __user *user_buf,
908 size_t user_len, loff_t *pos)
909{
910 char *buffer, *str;
911 int rc;
912 struct seq_file *m = (struct seq_file *)file->private_data;
913 struct dasd_profile *prof = m->private;
914
915 if (user_len > 65536)
916 user_len = 65536;
917 buffer = dasd_get_user_string(user_buf, user_len);
918 if (IS_ERR(buffer))
919 return PTR_ERR(buffer);
920
921 str = skip_spaces(buffer);
922 rc = user_len;
923 if (strncmp(str, "reset", 5) == 0) {
924 dasd_profile_reset(prof);
925 } else if (strncmp(str, "on", 2) == 0) {
926 rc = dasd_profile_on(prof);
927 if (!rc)
928 rc = user_len;
929 } else if (strncmp(str, "off", 3) == 0) {
930 dasd_profile_off(prof);
931 } else
932 rc = -EINVAL;
933 kfree(buffer);
934 return rc;
935}
936
937static void dasd_stats_array(struct seq_file *m, unsigned int *array)
938{
939 int i;
940
941 for (i = 0; i < 32; i++)
942 seq_printf(m, "%u ", array[i]);
943 seq_putc(m, '\n');
944}
945
946static void dasd_stats_seq_print(struct seq_file *m,
947 struct dasd_profile_info *data)
948{
949 seq_printf(m, "start_time %ld.%09ld\n",
950 data->starttod.tv_sec, data->starttod.tv_nsec);
951 seq_printf(m, "total_requests %u\n", data->dasd_io_reqs);
952 seq_printf(m, "total_sectors %u\n", data->dasd_io_sects);
953 seq_printf(m, "total_pav %u\n", data->dasd_io_alias);
954 seq_printf(m, "total_hpf %u\n", data->dasd_io_tpm);
955 seq_printf(m, "histogram_sectors ");
956 dasd_stats_array(m, data->dasd_io_secs);
957 seq_printf(m, "histogram_io_times ");
958 dasd_stats_array(m, data->dasd_io_times);
959 seq_printf(m, "histogram_io_times_weighted ");
960 dasd_stats_array(m, data->dasd_io_timps);
961 seq_printf(m, "histogram_time_build_to_ssch ");
962 dasd_stats_array(m, data->dasd_io_time1);
963 seq_printf(m, "histogram_time_ssch_to_irq ");
964 dasd_stats_array(m, data->dasd_io_time2);
965 seq_printf(m, "histogram_time_ssch_to_irq_weighted ");
966 dasd_stats_array(m, data->dasd_io_time2ps);
967 seq_printf(m, "histogram_time_irq_to_end ");
968 dasd_stats_array(m, data->dasd_io_time3);
969 seq_printf(m, "histogram_ccw_queue_length ");
970 dasd_stats_array(m, data->dasd_io_nr_req);
971 seq_printf(m, "total_read_requests %u\n", data->dasd_read_reqs);
972 seq_printf(m, "total_read_sectors %u\n", data->dasd_read_sects);
973 seq_printf(m, "total_read_pav %u\n", data->dasd_read_alias);
974 seq_printf(m, "total_read_hpf %u\n", data->dasd_read_tpm);
975 seq_printf(m, "histogram_read_sectors ");
976 dasd_stats_array(m, data->dasd_read_secs);
977 seq_printf(m, "histogram_read_times ");
978 dasd_stats_array(m, data->dasd_read_times);
979 seq_printf(m, "histogram_read_time_build_to_ssch ");
980 dasd_stats_array(m, data->dasd_read_time1);
981 seq_printf(m, "histogram_read_time_ssch_to_irq ");
982 dasd_stats_array(m, data->dasd_read_time2);
983 seq_printf(m, "histogram_read_time_irq_to_end ");
984 dasd_stats_array(m, data->dasd_read_time3);
985 seq_printf(m, "histogram_read_ccw_queue_length ");
986 dasd_stats_array(m, data->dasd_read_nr_req);
987}
988
989static int dasd_stats_show(struct seq_file *m, void *v)
990{
991 struct dasd_profile *profile;
992 struct dasd_profile_info *data;
993
994 profile = m->private;
995 spin_lock_bh(&profile->lock);
996 data = profile->data;
997 if (!data) {
998 spin_unlock_bh(&profile->lock);
999 seq_printf(m, "disabled\n");
1000 return 0;
1001 }
1002 dasd_stats_seq_print(m, data);
1003 spin_unlock_bh(&profile->lock);
1004 return 0;
1005}
1006
1007static int dasd_stats_open(struct inode *inode, struct file *file)
1008{
1009 struct dasd_profile *profile = inode->i_private;
1010 return single_open(file, dasd_stats_show, profile);
1011}
1012
1013static const struct file_operations dasd_stats_raw_fops = {
1014 .owner = THIS_MODULE,
1015 .open = dasd_stats_open,
1016 .read = seq_read,
1017 .llseek = seq_lseek,
1018 .release = single_release,
1019 .write = dasd_stats_write,
1020};
1021
1022static ssize_t dasd_stats_global_write(struct file *file,
1023 const char __user *user_buf,
1024 size_t user_len, loff_t *pos)
1025{
1026 char *buffer, *str;
1027 ssize_t rc;
1028
1029 if (user_len > 65536)
1030 user_len = 65536;
1031 buffer = dasd_get_user_string(user_buf, user_len);
1032 if (IS_ERR(buffer))
1033 return PTR_ERR(buffer);
1034 str = skip_spaces(buffer);
1035 rc = user_len;
1036 if (strncmp(str, "reset", 5) == 0) {
1037 dasd_global_profile_reset();
1038 } else if (strncmp(str, "on", 2) == 0) {
1039 dasd_global_profile_reset();
1040 dasd_global_profile_level = DASD_PROFILE_GLOBAL_ONLY;
1041 } else if (strncmp(str, "off", 3) == 0) {
1042 dasd_global_profile_level = DASD_PROFILE_OFF;
1043 } else
1044 rc = -EINVAL;
1045 kfree(buffer);
1046 return rc;
1047}
1048
1049static int dasd_stats_global_show(struct seq_file *m, void *v)
1050{
1051 if (!dasd_global_profile_level) {
1052 seq_printf(m, "disabled\n");
1053 return 0;
1054 }
1055 dasd_stats_seq_print(m, &dasd_global_profile_data);
1056 return 0;
1057}
1058
1059static int dasd_stats_global_open(struct inode *inode, struct file *file)
1060{
1061 return single_open(file, dasd_stats_global_show, NULL);
1062}
1063
1064static const struct file_operations dasd_stats_global_fops = {
1065 .owner = THIS_MODULE,
1066 .open = dasd_stats_global_open,
1067 .read = seq_read,
1068 .llseek = seq_lseek,
1069 .release = single_release,
1070 .write = dasd_stats_global_write,
1071};
1072
1073static void dasd_profile_init(struct dasd_profile *profile,
1074 struct dentry *base_dentry)
1075{
1076 mode_t mode;
1077 struct dentry *pde;
1078
1079 if (!base_dentry)
1080 return;
1081 profile->dentry = NULL;
1082 profile->data = NULL;
1083 mode = (S_IRUSR | S_IWUSR | S_IFREG);
1084 pde = debugfs_create_file("statistics", mode, base_dentry,
1085 profile, &dasd_stats_raw_fops);
1086 if (pde && !IS_ERR(pde))
1087 profile->dentry = pde;
1088 return;
1089}
1090
1091static void dasd_profile_exit(struct dasd_profile *profile)
1092{
1093 dasd_profile_off(profile);
1094 if (profile->dentry) {
1095 debugfs_remove(profile->dentry);
1096 profile->dentry = NULL;
1097 }
1098}
1099
1100static void dasd_statistics_removeroot(void)
1101{
1102 dasd_global_profile_level = DASD_PROFILE_OFF;
1103 if (dasd_global_profile_dentry) {
1104 debugfs_remove(dasd_global_profile_dentry);
1105 dasd_global_profile_dentry = NULL;
1106 }
1107 if (dasd_debugfs_global_entry)
1108 debugfs_remove(dasd_debugfs_global_entry);
1109 if (dasd_debugfs_root_entry)
1110 debugfs_remove(dasd_debugfs_root_entry);
1111}
1112
1113static void dasd_statistics_createroot(void)
1114{
1115 mode_t mode;
1116 struct dentry *pde;
1117
1118 dasd_debugfs_root_entry = NULL;
1119 dasd_debugfs_global_entry = NULL;
1120 dasd_global_profile_dentry = NULL;
1121 pde = debugfs_create_dir("dasd", NULL);
1122 if (!pde || IS_ERR(pde))
1123 goto error;
1124 dasd_debugfs_root_entry = pde;
1125 pde = debugfs_create_dir("global", dasd_debugfs_root_entry);
1126 if (!pde || IS_ERR(pde))
1127 goto error;
1128 dasd_debugfs_global_entry = pde;
1129
1130 mode = (S_IRUSR | S_IWUSR | S_IFREG);
1131 pde = debugfs_create_file("statistics", mode, dasd_debugfs_global_entry,
1132 NULL, &dasd_stats_global_fops);
1133 if (!pde || IS_ERR(pde))
1134 goto error;
1135 dasd_global_profile_dentry = pde;
1136 return;
1137
1138error:
1139 DBF_EVENT(DBF_ERR, "%s",
1140 "Creation of the dasd debugfs interface failed");
1141 dasd_statistics_removeroot();
1142 return;
1143}
1144
695#else 1145#else
696#define dasd_profile_start(block, cqr, req) do {} while (0) 1146#define dasd_profile_start(block, cqr, req) do {} while (0)
697#define dasd_profile_end(block, cqr, req) do {} while (0) 1147#define dasd_profile_end(block, cqr, req) do {} while (0)
1148
1149static void dasd_statistics_createroot(void)
1150{
1151 return;
1152}
1153
1154static void dasd_statistics_removeroot(void)
1155{
1156 return;
1157}
1158
1159int dasd_stats_generic_show(struct seq_file *m, void *v)
1160{
1161 seq_printf(m, "Statistics are not activated in this kernel\n");
1162 return 0;
1163}
1164
1165static void dasd_profile_init(struct dasd_profile *profile,
1166 struct dentry *base_dentry)
1167{
1168 return;
1169}
1170
1171static void dasd_profile_exit(struct dasd_profile *profile)
1172{
1173 return;
1174}
1175
1176int dasd_profile_on(struct dasd_profile *profile)
1177{
1178 return 0;
1179}
1180
698#endif /* CONFIG_DASD_PROFILE */ 1181#endif /* CONFIG_DASD_PROFILE */
699 1182
700/* 1183/*
@@ -2441,6 +2924,7 @@ dasd_exit(void)
2441 debug_unregister(dasd_debug_area); 2924 debug_unregister(dasd_debug_area);
2442 dasd_debug_area = NULL; 2925 dasd_debug_area = NULL;
2443 } 2926 }
2927 dasd_statistics_removeroot();
2444} 2928}
2445 2929
2446/* 2930/*
@@ -2992,6 +3476,8 @@ static int __init dasd_init(void)
2992 3476
2993 dasd_diag_discipline_pointer = NULL; 3477 dasd_diag_discipline_pointer = NULL;
2994 3478
3479 dasd_statistics_createroot();
3480
2995 rc = dasd_devmap_init(); 3481 rc = dasd_devmap_init();
2996 if (rc) 3482 if (rc)
2997 goto failed; 3483 goto failed;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index d1e4f2c1264..1dd12bd85a6 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -382,6 +382,41 @@ struct dasd_path {
382 __u8 npm; 382 __u8 npm;
383}; 383};
384 384
385struct dasd_profile_info {
386 /* legacy part of profile data, as in dasd_profile_info_t */
387 unsigned int dasd_io_reqs; /* number of requests processed */
388 unsigned int dasd_io_sects; /* number of sectors processed */
389 unsigned int dasd_io_secs[32]; /* histogram of request's sizes */
390 unsigned int dasd_io_times[32]; /* histogram of requests's times */
391 unsigned int dasd_io_timps[32]; /* h. of requests's times per sector */
392 unsigned int dasd_io_time1[32]; /* hist. of time from build to start */
393 unsigned int dasd_io_time2[32]; /* hist. of time from start to irq */
394 unsigned int dasd_io_time2ps[32]; /* hist. of time from start to irq */
395 unsigned int dasd_io_time3[32]; /* hist. of time from irq to end */
396 unsigned int dasd_io_nr_req[32]; /* hist. of # of requests in chanq */
397
398 /* new data */
399 struct timespec starttod; /* time of start or last reset */
400 unsigned int dasd_io_alias; /* requests using an alias */
401 unsigned int dasd_io_tpm; /* requests using transport mode */
402 unsigned int dasd_read_reqs; /* total number of read requests */
403 unsigned int dasd_read_sects; /* total number read sectors */
404 unsigned int dasd_read_alias; /* read request using an alias */
405 unsigned int dasd_read_tpm; /* read requests in transport mode */
406 unsigned int dasd_read_secs[32]; /* histogram of request's sizes */
407 unsigned int dasd_read_times[32]; /* histogram of requests's times */
408 unsigned int dasd_read_time1[32]; /* hist. time from build to start */
409 unsigned int dasd_read_time2[32]; /* hist. of time from start to irq */
410 unsigned int dasd_read_time3[32]; /* hist. of time from irq to end */
411 unsigned int dasd_read_nr_req[32]; /* hist. of # of requests in chanq */
412};
413
414struct dasd_profile {
415 struct dentry *dentry;
416 struct dasd_profile_info *data;
417 spinlock_t lock;
418};
419
385struct dasd_device { 420struct dasd_device {
386 /* Block device stuff. */ 421 /* Block device stuff. */
387 struct dasd_block *block; 422 struct dasd_block *block;
@@ -431,6 +466,9 @@ struct dasd_device {
431 466
432 /* default expiration time in s */ 467 /* default expiration time in s */
433 unsigned long default_expires; 468 unsigned long default_expires;
469
470 struct dentry *debugfs_dentry;
471 struct dasd_profile profile;
434}; 472};
435 473
436struct dasd_block { 474struct dasd_block {
@@ -453,9 +491,8 @@ struct dasd_block {
453 struct tasklet_struct tasklet; 491 struct tasklet_struct tasklet;
454 struct timer_list timer; 492 struct timer_list timer;
455 493
456#ifdef CONFIG_DASD_PROFILE 494 struct dentry *debugfs_dentry;
457 struct dasd_profile_info_t profile; 495 struct dasd_profile profile;
458#endif
459}; 496};
460 497
461 498
@@ -589,12 +626,13 @@ dasd_check_blocksize(int bsize)
589} 626}
590 627
591/* externals in dasd.c */ 628/* externals in dasd.c */
592#define DASD_PROFILE_ON 1 629#define DASD_PROFILE_OFF 0
593#define DASD_PROFILE_OFF 0 630#define DASD_PROFILE_ON 1
631#define DASD_PROFILE_GLOBAL_ONLY 2
594 632
595extern debug_info_t *dasd_debug_area; 633extern debug_info_t *dasd_debug_area;
596extern struct dasd_profile_info_t dasd_global_profile; 634extern struct dasd_profile_info dasd_global_profile_data;
597extern unsigned int dasd_profile_level; 635extern unsigned int dasd_global_profile_level;
598extern const struct block_device_operations dasd_device_operations; 636extern const struct block_device_operations dasd_device_operations;
599 637
600extern struct kmem_cache *dasd_page_cache; 638extern struct kmem_cache *dasd_page_cache;
@@ -662,6 +700,11 @@ void dasd_device_remove_stop_bits(struct dasd_device *, int);
662 700
663int dasd_device_is_ro(struct dasd_device *); 701int dasd_device_is_ro(struct dasd_device *);
664 702
703void dasd_profile_reset(struct dasd_profile *);
704int dasd_profile_on(struct dasd_profile *);
705void dasd_profile_off(struct dasd_profile *);
706void dasd_global_profile_reset(void);
707char *dasd_get_user_string(const char __user *, size_t);
665 708
666/* externals in dasd_devmap.c */ 709/* externals in dasd_devmap.c */
667extern int dasd_max_devindex; 710extern int dasd_max_devindex;
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 72261e4c516..eb4e034378c 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -239,7 +239,7 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp)
239 */ 239 */
240static int dasd_ioctl_reset_profile(struct dasd_block *block) 240static int dasd_ioctl_reset_profile(struct dasd_block *block)
241{ 241{
242 memset(&block->profile, 0, sizeof(struct dasd_profile_info_t)); 242 dasd_profile_reset(&block->profile);
243 return 0; 243 return 0;
244} 244}
245 245
@@ -248,10 +248,40 @@ static int dasd_ioctl_reset_profile(struct dasd_block *block)
248 */ 248 */
249static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp) 249static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
250{ 250{
251 if (dasd_profile_level == DASD_PROFILE_OFF) 251 struct dasd_profile_info_t *data;
252
253 data = kmalloc(sizeof(*data), GFP_KERNEL);
254 if (!data)
255 return -ENOMEM;
256
257 spin_lock_bh(&block->profile.lock);
258 if (block->profile.data) {
259 data->dasd_io_reqs = block->profile.data->dasd_io_reqs;
260 data->dasd_io_sects = block->profile.data->dasd_io_sects;
261 memcpy(data->dasd_io_secs, block->profile.data->dasd_io_secs,
262 sizeof(data->dasd_io_secs));
263 memcpy(data->dasd_io_times, block->profile.data->dasd_io_times,
264 sizeof(data->dasd_io_times));
265 memcpy(data->dasd_io_timps, block->profile.data->dasd_io_timps,
266 sizeof(data->dasd_io_timps));
267 memcpy(data->dasd_io_time1, block->profile.data->dasd_io_time1,
268 sizeof(data->dasd_io_time1));
269 memcpy(data->dasd_io_time2, block->profile.data->dasd_io_time2,
270 sizeof(data->dasd_io_time2));
271 memcpy(data->dasd_io_time2ps,
272 block->profile.data->dasd_io_time2ps,
273 sizeof(data->dasd_io_time2ps));
274 memcpy(data->dasd_io_time3, block->profile.data->dasd_io_time3,
275 sizeof(data->dasd_io_time3));
276 memcpy(data->dasd_io_nr_req,
277 block->profile.data->dasd_io_nr_req,
278 sizeof(data->dasd_io_nr_req));
279 spin_unlock_bh(&block->profile.lock);
280 } else {
281 spin_unlock_bh(&block->profile.lock);
252 return -EIO; 282 return -EIO;
253 if (copy_to_user(argp, &block->profile, 283 }
254 sizeof(struct dasd_profile_info_t))) 284 if (copy_to_user(argp, data, sizeof(*data)))
255 return -EFAULT; 285 return -EFAULT;
256 return 0; 286 return 0;
257} 287}
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index c4a6a31bd9c..6c3c5364d08 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -32,28 +32,6 @@ static struct proc_dir_entry *dasd_proc_root_entry = NULL;
32static struct proc_dir_entry *dasd_devices_entry = NULL; 32static struct proc_dir_entry *dasd_devices_entry = NULL;
33static struct proc_dir_entry *dasd_statistics_entry = NULL; 33static struct proc_dir_entry *dasd_statistics_entry = NULL;
34 34
35#ifdef CONFIG_DASD_PROFILE
36static char *
37dasd_get_user_string(const char __user *user_buf, size_t user_len)
38{
39 char *buffer;
40
41 buffer = kmalloc(user_len + 1, GFP_KERNEL);
42 if (buffer == NULL)
43 return ERR_PTR(-ENOMEM);
44 if (copy_from_user(buffer, user_buf, user_len) != 0) {
45 kfree(buffer);
46 return ERR_PTR(-EFAULT);
47 }
48 /* got the string, now strip linefeed. */
49 if (buffer[user_len - 1] == '\n')
50 buffer[user_len - 1] = 0;
51 else
52 buffer[user_len] = 0;
53 return buffer;
54}
55#endif /* CONFIG_DASD_PROFILE */
56
57static int 35static int
58dasd_devices_show(struct seq_file *m, void *v) 36dasd_devices_show(struct seq_file *m, void *v)
59{ 37{
@@ -167,6 +145,55 @@ static const struct file_operations dasd_devices_file_ops = {
167}; 145};
168 146
169#ifdef CONFIG_DASD_PROFILE 147#ifdef CONFIG_DASD_PROFILE
148static int dasd_stats_all_block_on(void)
149{
150 int i, rc;
151 struct dasd_device *device;
152
153 rc = 0;
154 for (i = 0; i < dasd_max_devindex; ++i) {
155 device = dasd_device_from_devindex(i);
156 if (IS_ERR(device))
157 continue;
158 if (device->block)
159 rc = dasd_profile_on(&device->block->profile);
160 dasd_put_device(device);
161 if (rc)
162 return rc;
163 }
164 return 0;
165}
166
167static void dasd_stats_all_block_off(void)
168{
169 int i;
170 struct dasd_device *device;
171
172 for (i = 0; i < dasd_max_devindex; ++i) {
173 device = dasd_device_from_devindex(i);
174 if (IS_ERR(device))
175 continue;
176 if (device->block)
177 dasd_profile_off(&device->block->profile);
178 dasd_put_device(device);
179 }
180}
181
182static void dasd_stats_all_block_reset(void)
183{
184 int i;
185 struct dasd_device *device;
186
187 for (i = 0; i < dasd_max_devindex; ++i) {
188 device = dasd_device_from_devindex(i);
189 if (IS_ERR(device))
190 continue;
191 if (device->block)
192 dasd_profile_reset(&device->block->profile);
193 dasd_put_device(device);
194 }
195}
196
170static void dasd_statistics_array(struct seq_file *m, unsigned int *array, int factor) 197static void dasd_statistics_array(struct seq_file *m, unsigned int *array, int factor)
171{ 198{
172 int i; 199 int i;
@@ -183,18 +210,18 @@ static void dasd_statistics_array(struct seq_file *m, unsigned int *array, int f
183static int dasd_stats_proc_show(struct seq_file *m, void *v) 210static int dasd_stats_proc_show(struct seq_file *m, void *v)
184{ 211{
185#ifdef CONFIG_DASD_PROFILE 212#ifdef CONFIG_DASD_PROFILE
186 struct dasd_profile_info_t *prof; 213 struct dasd_profile_info *prof;
187 int factor; 214 int factor;
188 215
189 /* check for active profiling */ 216 /* check for active profiling */
190 if (dasd_profile_level == DASD_PROFILE_OFF) { 217 if (!dasd_global_profile_level) {
191 seq_printf(m, "Statistics are off - they might be " 218 seq_printf(m, "Statistics are off - they might be "
192 "switched on using 'echo set on > " 219 "switched on using 'echo set on > "
193 "/proc/dasd/statistics'\n"); 220 "/proc/dasd/statistics'\n");
194 return 0; 221 return 0;
195 } 222 }
223 prof = &dasd_global_profile_data;
196 224
197 prof = &dasd_global_profile;
198 /* prevent counter 'overflow' on output */ 225 /* prevent counter 'overflow' on output */
199 for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999; 226 for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999;
200 factor *= 10); 227 factor *= 10);
@@ -245,6 +272,7 @@ static ssize_t dasd_stats_proc_write(struct file *file,
245{ 272{
246#ifdef CONFIG_DASD_PROFILE 273#ifdef CONFIG_DASD_PROFILE
247 char *buffer, *str; 274 char *buffer, *str;
275 int rc;
248 276
249 if (user_len > 65536) 277 if (user_len > 65536)
250 user_len = 65536; 278 user_len = 65536;
@@ -259,32 +287,40 @@ static ssize_t dasd_stats_proc_write(struct file *file,
259 str = skip_spaces(str + 4); 287 str = skip_spaces(str + 4);
260 if (strcmp(str, "on") == 0) { 288 if (strcmp(str, "on") == 0) {
261 /* switch on statistics profiling */ 289 /* switch on statistics profiling */
262 dasd_profile_level = DASD_PROFILE_ON; 290 rc = dasd_stats_all_block_on();
291 if (rc) {
292 dasd_stats_all_block_off();
293 goto out_error;
294 }
295 dasd_global_profile_reset();
296 dasd_global_profile_level = DASD_PROFILE_ON;
263 pr_info("The statistics feature has been switched " 297 pr_info("The statistics feature has been switched "
264 "on\n"); 298 "on\n");
265 } else if (strcmp(str, "off") == 0) { 299 } else if (strcmp(str, "off") == 0) {
266 /* switch off and reset statistics profiling */ 300 /* switch off and reset statistics profiling */
267 memset(&dasd_global_profile, 301 dasd_global_profile_level = DASD_PROFILE_OFF;
268 0, sizeof (struct dasd_profile_info_t)); 302 dasd_global_profile_reset();
269 dasd_profile_level = DASD_PROFILE_OFF; 303 dasd_stats_all_block_off();
270 pr_info("The statistics feature has been switched " 304 pr_info("The statistics feature has been switched "
271 "off\n"); 305 "off\n");
272 } else 306 } else
273 goto out_error; 307 goto out_parse_error;
274 } else if (strncmp(str, "reset", 5) == 0) { 308 } else if (strncmp(str, "reset", 5) == 0) {
275 /* reset the statistics */ 309 /* reset the statistics */
276 memset(&dasd_global_profile, 0, 310 dasd_global_profile_reset();
277 sizeof (struct dasd_profile_info_t)); 311 dasd_stats_all_block_reset();
278 pr_info("The statistics have been reset\n"); 312 pr_info("The statistics have been reset\n");
279 } else 313 } else
280 goto out_error; 314 goto out_parse_error;
281 kfree(buffer); 315 kfree(buffer);
282 return user_len; 316 return user_len;
283out_error: 317out_parse_error:
318 rc = -EINVAL;
284 pr_warning("%s is not a supported value for /proc/dasd/statistics\n", 319 pr_warning("%s is not a supported value for /proc/dasd/statistics\n",
285 str); 320 str);
321out_error:
286 kfree(buffer); 322 kfree(buffer);
287 return -EINVAL; 323 return rc;
288#else 324#else
289 pr_warning("/proc/dasd/statistics: is not activated in this kernel\n"); 325 pr_warning("/proc/dasd/statistics: is not activated in this kernel\n");
290 return user_len; 326 return user_len;