s390/sysinfo: convert /proc/sysinfo to seqfile
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Mon, 3 Sep 2012 07:38:30 +0000 (09:38 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 26 Sep 2012 13:45:07 +0000 (15:45 +0200)
The current proc implementation of the /proc/sysinfo file writes all
informations contained in all system information blocks to a single
page.
This is done by calling sprintf all the time in the expectation that
everything will fit into a single page. This however is not necessarily
true if the configuration of a machine is very large.
So convert /proc/sysinfo to avoid writing into random memory regions.

For readability reasons a couple of lines are longer than 80 characters.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/kernel/sysinfo.c

index fa0eb238dac7d8940321c239d970d1245078d219..d3b543c3617a62084f274ba7299346c09f958ac1 100644 (file)
 static inline int stsi_0(void)
 {
        int rc = stsi(NULL, 0, 0, 0);
+
        return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28);
 }
 
-static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)
+static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info)
 {
        if (stsi(info, 1, 1, 1) == -ENOSYS)
-               return len;
-
+               return;
        EBCASC(info->manufacturer, sizeof(info->manufacturer));
        EBCASC(info->type, sizeof(info->type));
        EBCASC(info->model, sizeof(info->model));
@@ -41,58 +41,45 @@ static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)
        EBCASC(info->model_capacity, sizeof(info->model_capacity));
        EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap));
        EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap));
-       len += sprintf(page + len, "Manufacturer:         %-16.16s\n",
-                      info->manufacturer);
-       len += sprintf(page + len, "Type:                 %-4.4s\n",
-                      info->type);
+       seq_printf(m, "Manufacturer:         %-16.16s\n", info->manufacturer);
+       seq_printf(m, "Type:                 %-4.4s\n", info->type);
+       /*
+        * Sigh: the model field has been renamed with System z9
+        * to model_capacity and a new model field has been added
+        * after the plant field. To avoid confusing older programs
+        * the "Model:" prints "model_capacity model" or just
+        * "model_capacity" if the model string is empty .
+        */
+       seq_printf(m, "Model:                %-16.16s", info->model_capacity);
        if (info->model[0] != '\0')
-               /*
-                * Sigh: the model field has been renamed with System z9
-                * to model_capacity and a new model field has been added
-                * after the plant field. To avoid confusing older programs
-                * the "Model:" prints "model_capacity model" or just
-                * "model_capacity" if the model string is empty .
-                */
-               len += sprintf(page + len,
-                              "Model:                %-16.16s %-16.16s\n",
-                              info->model_capacity, info->model);
-       else
-               len += sprintf(page + len, "Model:                %-16.16s\n",
-                              info->model_capacity);
-       len += sprintf(page + len, "Sequence Code:        %-16.16s\n",
-                      info->sequence);
-       len += sprintf(page + len, "Plant:                %-4.4s\n",
-                      info->plant);
-       len += sprintf(page + len, "Model Capacity:       %-16.16s %08u\n",
-                      info->model_capacity, *(u32 *) info->model_cap_rating);
+               seq_printf(m, " %-16.16s", info->model);
+       seq_putc(m, '\n');
+       seq_printf(m, "Sequence Code:        %-16.16s\n", info->sequence);
+       seq_printf(m, "Plant:                %-4.4s\n", info->plant);
+       seq_printf(m, "Model Capacity:       %-16.16s %08u\n",
+                  info->model_capacity, *(u32 *) info->model_cap_rating);
        if (info->model_perm_cap[0] != '\0')
-               len += sprintf(page + len,
-                              "Model Perm. Capacity: %-16.16s %08u\n",
-                              info->model_perm_cap,
-                              *(u32 *) info->model_perm_cap_rating);
+               seq_printf(m, "Model Perm. Capacity: %-16.16s %08u\n",
+                          info->model_perm_cap,
+                          *(u32 *) info->model_perm_cap_rating);
        if (info->model_temp_cap[0] != '\0')
-               len += sprintf(page + len,
-                              "Model Temp. Capacity: %-16.16s %08u\n",
-                              info->model_temp_cap,
-                              *(u32 *) info->model_temp_cap_rating);
+               seq_printf(m, "Model Temp. Capacity: %-16.16s %08u\n",
+                          info->model_temp_cap,
+                          *(u32 *) info->model_temp_cap_rating);
        if (info->cai) {
-               len += sprintf(page + len,
-                              "Capacity Adj. Ind.:   %d\n",
-                              info->cai);
-               len += sprintf(page + len, "Capacity Ch. Reason:  %d\n",
-                              info->ccr);
+               seq_printf(m, "Capacity Adj. Ind.:   %d\n", info->cai);
+               seq_printf(m, "Capacity Ch. Reason:  %d\n", info->ccr);
        }
-       return len;
 }
 
-static int stsi_15_1_x(struct sysinfo_15_1_x *info, char *page, int len)
+static void stsi_15_1_x(struct seq_file *m, struct sysinfo_15_1_x *info)
 {
        static int max_mnest;
        int i, rc;
 
-       len += sprintf(page + len, "\n");
+       seq_putc(m, '\n');
        if (!MACHINE_HAS_TOPOLOGY)
-               return len;
+               return;
        if (max_mnest) {
                stsi(info, 15, 1, max_mnest);
        } else {
@@ -102,181 +89,142 @@ static int stsi_15_1_x(struct sysinfo_15_1_x *info, char *page, int len)
                                break;
                }
        }
-       len += sprintf(page + len, "CPU Topology HW:     ");
+       seq_printf(m, "CPU Topology HW:     ");
        for (i = 0; i < TOPOLOGY_NR_MAG; i++)
-               len += sprintf(page + len, " %d", info->mag[i]);
-       len += sprintf(page + len, "\n");
+               seq_printf(m, " %d", info->mag[i]);
+       seq_putc(m, '\n');
 #ifdef CONFIG_SCHED_MC
        store_topology(info);
-       len += sprintf(page + len, "CPU Topology SW:     ");
+       seq_printf(m, "CPU Topology SW:     ");
        for (i = 0; i < TOPOLOGY_NR_MAG; i++)
-               len += sprintf(page + len, " %d", info->mag[i]);
-       len += sprintf(page + len, "\n");
+               seq_printf(m, " %d", info->mag[i]);
+       seq_putc(m, '\n');
 #endif
-       return len;
 }
 
-static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
+static void stsi_1_2_2(struct seq_file *m, struct sysinfo_1_2_2 *info)
 {
        struct sysinfo_1_2_2_extension *ext;
        int i;
 
        if (stsi(info, 1, 2, 2) == -ENOSYS)
-               return len;
+               return;
        ext = (struct sysinfo_1_2_2_extension *)
                ((unsigned long) info + info->acc_offset);
-
-       len += sprintf(page + len, "CPUs Total:           %d\n",
-                      info->cpus_total);
-       len += sprintf(page + len, "CPUs Configured:      %d\n",
-                      info->cpus_configured);
-       len += sprintf(page + len, "CPUs Standby:         %d\n",
-                      info->cpus_standby);
-       len += sprintf(page + len, "CPUs Reserved:        %d\n",
-                      info->cpus_reserved);
-
-       if (info->format == 1) {
-               /*
-                * Sigh 2. According to the specification the alternate
-                * capability field is a 32 bit floating point number
-                * if the higher order 8 bits are not zero. Printing
-                * a floating point number in the kernel is a no-no,
-                * always print the number as 32 bit unsigned integer.
-                * The user-space needs to know about the strange
-                * encoding of the alternate cpu capability.
-                */
-               len += sprintf(page + len, "Capability:           %u %u\n",
-                              info->capability, ext->alt_capability);
-               for (i = 2; i <= info->cpus_total; i++)
-                       len += sprintf(page + len,
-                                      "Adjustment %02d-way:    %u %u\n",
-                                      i, info->adjustment[i-2],
-                                      ext->alt_adjustment[i-2]);
-
-       } else {
-               len += sprintf(page + len, "Capability:           %u\n",
-                              info->capability);
-               for (i = 2; i <= info->cpus_total; i++)
-                       len += sprintf(page + len,
-                                      "Adjustment %02d-way:    %u\n",
-                                      i, info->adjustment[i-2]);
+       seq_printf(m, "CPUs Total:           %d\n", info->cpus_total);
+       seq_printf(m, "CPUs Configured:      %d\n", info->cpus_configured);
+       seq_printf(m, "CPUs Standby:         %d\n", info->cpus_standby);
+       seq_printf(m, "CPUs Reserved:        %d\n", info->cpus_reserved);
+       /*
+        * Sigh 2. According to the specification the alternate
+        * capability field is a 32 bit floating point number
+        * if the higher order 8 bits are not zero. Printing
+        * a floating point number in the kernel is a no-no,
+        * always print the number as 32 bit unsigned integer.
+        * The user-space needs to know about the strange
+        * encoding of the alternate cpu capability.
+        */
+       seq_printf(m, "Capability:           %u", info->capability);
+       if (info->format == 1)
+               seq_printf(m, " %u", ext->alt_capability);
+       seq_putc(m, '\n');
+       for (i = 2; i <= info->cpus_total; i++) {
+               seq_printf(m, "Adjustment %02d-way:    %u",
+                          i, info->adjustment[i-2]);
+               if (info->format == 1)
+                       seq_printf(m, " %u", ext->alt_adjustment[i-2]);
+               seq_putc(m, '\n');
        }
-
-       if (info->secondary_capability != 0)
-               len += sprintf(page + len, "Secondary Capability: %d\n",
-                              info->secondary_capability);
-       return len;
+       if (info->secondary_capability)
+               seq_printf(m, "Secondary Capability: %d\n",
+                          info->secondary_capability);
 }
 
-static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len)
+static void stsi_2_2_2(struct seq_file *m, struct sysinfo_2_2_2 *info)
 {
        if (stsi(info, 2, 2, 2) == -ENOSYS)
-               return len;
-
+               return;
        EBCASC(info->name, sizeof(info->name));
-
-       len += sprintf(page + len, "\n");
-       len += sprintf(page + len, "LPAR Number:          %d\n",
-                      info->lpar_number);
-
-       len += sprintf(page + len, "LPAR Characteristics: ");
+       seq_putc(m, '\n');
+       seq_printf(m, "LPAR Number:          %d\n", info->lpar_number);
+       seq_printf(m, "LPAR Characteristics: ");
        if (info->characteristics & LPAR_CHAR_DEDICATED)
-               len += sprintf(page + len, "Dedicated ");
+               seq_printf(m, "Dedicated ");
        if (info->characteristics & LPAR_CHAR_SHARED)
-               len += sprintf(page + len, "Shared ");
+               seq_printf(m, "Shared ");
        if (info->characteristics & LPAR_CHAR_LIMITED)
-               len += sprintf(page + len, "Limited ");
-       len += sprintf(page + len, "\n");
-
-       len += sprintf(page + len, "LPAR Name:            %-8.8s\n",
-                      info->name);
-
-       len += sprintf(page + len, "LPAR Adjustment:      %d\n",
-                      info->caf);
-
-       len += sprintf(page + len, "LPAR CPUs Total:      %d\n",
-                      info->cpus_total);
-       len += sprintf(page + len, "LPAR CPUs Configured: %d\n",
-                      info->cpus_configured);
-       len += sprintf(page + len, "LPAR CPUs Standby:    %d\n",
-                      info->cpus_standby);
-       len += sprintf(page + len, "LPAR CPUs Reserved:   %d\n",
-                      info->cpus_reserved);
-       len += sprintf(page + len, "LPAR CPUs Dedicated:  %d\n",
-                      info->cpus_dedicated);
-       len += sprintf(page + len, "LPAR CPUs Shared:     %d\n",
-                      info->cpus_shared);
-       return len;
+               seq_printf(m, "Limited ");
+       seq_putc(m, '\n');
+       seq_printf(m, "LPAR Name:            %-8.8s\n", info->name);
+       seq_printf(m, "LPAR Adjustment:      %d\n", info->caf);
+       seq_printf(m, "LPAR CPUs Total:      %d\n", info->cpus_total);
+       seq_printf(m, "LPAR CPUs Configured: %d\n", info->cpus_configured);
+       seq_printf(m, "LPAR CPUs Standby:    %d\n", info->cpus_standby);
+       seq_printf(m, "LPAR CPUs Reserved:   %d\n", info->cpus_reserved);
+       seq_printf(m, "LPAR CPUs Dedicated:  %d\n", info->cpus_dedicated);
+       seq_printf(m, "LPAR CPUs Shared:     %d\n", info->cpus_shared);
 }
 
-static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len)
+static void stsi_3_2_2(struct seq_file *m, struct sysinfo_3_2_2 *info)
 {
        int i;
 
        if (stsi(info, 3, 2, 2) == -ENOSYS)
-               return len;
+               return;
        for (i = 0; i < info->count; i++) {
                EBCASC(info->vm[i].name, sizeof(info->vm[i].name));
                EBCASC(info->vm[i].cpi, sizeof(info->vm[i].cpi));
-               len += sprintf(page + len, "\n");
-               len += sprintf(page + len, "VM%02d Name:            %-8.8s\n",
-                              i, info->vm[i].name);
-               len += sprintf(page + len, "VM%02d Control Program: %-16.16s\n",
-                              i, info->vm[i].cpi);
-
-               len += sprintf(page + len, "VM%02d Adjustment:      %d\n",
-                              i, info->vm[i].caf);
-
-               len += sprintf(page + len, "VM%02d CPUs Total:      %d\n",
-                              i, info->vm[i].cpus_total);
-               len += sprintf(page + len, "VM%02d CPUs Configured: %d\n",
-                              i, info->vm[i].cpus_configured);
-               len += sprintf(page + len, "VM%02d CPUs Standby:    %d\n",
-                              i, info->vm[i].cpus_standby);
-               len += sprintf(page + len, "VM%02d CPUs Reserved:   %d\n",
-                              i, info->vm[i].cpus_reserved);
+               seq_putc(m, '\n');
+               seq_printf(m, "VM%02d Name:            %-8.8s\n", i, info->vm[i].name);
+               seq_printf(m, "VM%02d Control Program: %-16.16s\n", i, info->vm[i].cpi);
+               seq_printf(m, "VM%02d Adjustment:      %d\n", i, info->vm[i].caf);
+               seq_printf(m, "VM%02d CPUs Total:      %d\n", i, info->vm[i].cpus_total);
+               seq_printf(m, "VM%02d CPUs Configured: %d\n", i, info->vm[i].cpus_configured);
+               seq_printf(m, "VM%02d CPUs Standby:    %d\n", i, info->vm[i].cpus_standby);
+               seq_printf(m, "VM%02d CPUs Reserved:   %d\n", i, info->vm[i].cpus_reserved);
        }
-       return len;
 }
 
-static int proc_read_sysinfo(char *page, char **start,
-                            off_t off, int count,
-                            int *eof, void *data)
+static int sysinfo_show(struct seq_file *m, void *v)
 {
-       unsigned long info = get_zeroed_page(GFP_KERNEL);
-       int level, len;
+       void *info = (void *)get_zeroed_page(GFP_KERNEL);
+       int level;
 
        if (!info)
                return 0;
-
-       len = 0;
        level = stsi_0();
        if (level >= 1)
-               len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len);
-
+               stsi_1_1_1(m, info);
        if (level >= 1)
-               len = stsi_15_1_x((struct sysinfo_15_1_x *) info, page, len);
-
+               stsi_15_1_x(m, info);
        if (level >= 1)
-               len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len);
-
+               stsi_1_2_2(m, info);
        if (level >= 2)
-               len = stsi_2_2_2((struct sysinfo_2_2_2 *) info, page, len);
-
+               stsi_2_2_2(m, info);
        if (level >= 3)
-               len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len);
+               stsi_3_2_2(m, info);
+       free_page((unsigned long)info);
+       return 0;
+}
 
-       free_page(info);
-       return len;
+static int sysinfo_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, sysinfo_show, NULL);
 }
 
-static __init int create_proc_sysinfo(void)
+static const struct file_operations sysinfo_fops = {
+       .open           = sysinfo_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int __init sysinfo_create_proc(void)
 {
-       create_proc_read_entry("sysinfo", 0444, NULL,
-                              proc_read_sysinfo, NULL);
+       proc_create("sysinfo", 0444, NULL, &sysinfo_fops);
        return 0;
 }
-device_initcall(create_proc_sysinfo);
+device_initcall(sysinfo_create_proc);
 
 /*
  * Service levels interface.