proc: less code duplication in /proc/*/cmdline
authorAlexey Dobriyan <adobriyan@gmail.com>
Fri, 24 Feb 2017 23:00:20 +0000 (15:00 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 25 Feb 2017 01:46:56 +0000 (17:46 -0800)
After staring at this code for a while I've figured using small 2-entry
array describing ARGV and ENVP is the way to address code duplication
critique.

Link: http://lkml.kernel.org/r/20170105185724.GA12027@avx2
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/proc/base.c

index b73b4de8fb36468cc7153f4a95f4460bd28aff4c..4ecb5edc3c612263524b409ed992f4c7e6fd418d 100644 (file)
@@ -291,102 +291,70 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf,
                        rv      += nr_read;
                }
        } else {
-               /*
-                * Command line (1 string) occupies ARGV and maybe
-                * extends into ENVP.
-                */
-               if (len1 + len2 <= *pos)
-                       goto skip_argv_envp;
-               if (len1 <= *pos)
-                       goto skip_argv;
-
-               p = arg_start + *pos;
-               len = len1 - *pos;
-               while (count > 0 && len > 0) {
-                       unsigned int _count, l;
-                       int nr_read;
-                       bool final;
-
-                       _count = min3(count, len, PAGE_SIZE);
-                       nr_read = access_remote_vm(mm, p, page, _count, 0);
-                       if (nr_read < 0)
-                               rv = nr_read;
-                       if (nr_read <= 0)
-                               goto out_free_page;
-
-                       /*
-                        * Command line can be shorter than whole ARGV
-                        * even if last "marker" byte says it is not.
-                        */
-                       final = false;
-                       l = strnlen(page, nr_read);
-                       if (l < nr_read) {
-                               nr_read = l;
-                               final = true;
-                       }
-
-                       if (copy_to_user(buf, page, nr_read)) {
-                               rv = -EFAULT;
-                               goto out_free_page;
-                       }
-
-                       p       += nr_read;
-                       len     -= nr_read;
-                       buf     += nr_read;
-                       count   -= nr_read;
-                       rv      += nr_read;
-
-                       if (final)
-                               goto out_free_page;
-               }
-skip_argv:
                /*
                 * Command line (1 string) occupies ARGV and
                 * extends into ENVP.
                 */
-               if (len1 <= *pos) {
-                       p = env_start + *pos - len1;
-                       len = len1 + len2 - *pos;
-               } else {
-                       p = env_start;
-                       len = len2;
+               struct {
+                       unsigned long p;
+                       unsigned long len;
+               } cmdline[2] = {
+                       { .p = arg_start, .len = len1 },
+                       { .p = env_start, .len = len2 },
+               };
+               loff_t pos1 = *pos;
+               unsigned int i;
+
+               i = 0;
+               while (i < 2 && pos1 >= cmdline[i].len) {
+                       pos1 -= cmdline[i].len;
+                       i++;
                }
-               while (count > 0 && len > 0) {
-                       unsigned int _count, l;
-                       int nr_read;
-                       bool final;
-
-                       _count = min3(count, len, PAGE_SIZE);
-                       nr_read = access_remote_vm(mm, p, page, _count, 0);
-                       if (nr_read < 0)
-                               rv = nr_read;
-                       if (nr_read <= 0)
-                               goto out_free_page;
-
-                       /* Find EOS. */
-                       final = false;
-                       l = strnlen(page, nr_read);
-                       if (l < nr_read) {
-                               nr_read = l;
-                               final = true;
-                       }
-
-                       if (copy_to_user(buf, page, nr_read)) {
-                               rv = -EFAULT;
-                               goto out_free_page;
+               while (i < 2) {
+                       p = cmdline[i].p + pos1;
+                       len = cmdline[i].len - pos1;
+                       while (count > 0 && len > 0) {
+                               unsigned int _count, l;
+                               int nr_read;
+                               bool final;
+
+                               _count = min3(count, len, PAGE_SIZE);
+                               nr_read = access_remote_vm(mm, p, page, _count, 0);
+                               if (nr_read < 0)
+                                       rv = nr_read;
+                               if (nr_read <= 0)
+                                       goto out_free_page;
+
+                               /*
+                                * Command line can be shorter than whole ARGV
+                                * even if last "marker" byte says it is not.
+                                */
+                               final = false;
+                               l = strnlen(page, nr_read);
+                               if (l < nr_read) {
+                                       nr_read = l;
+                                       final = true;
+                               }
+
+                               if (copy_to_user(buf, page, nr_read)) {
+                                       rv = -EFAULT;
+                                       goto out_free_page;
+                               }
+
+                               p       += nr_read;
+                               len     -= nr_read;
+                               buf     += nr_read;
+                               count   -= nr_read;
+                               rv      += nr_read;
+
+                               if (final)
+                                       goto out_free_page;
                        }
 
-                       p       += nr_read;
-                       len     -= nr_read;
-                       buf     += nr_read;
-                       count   -= nr_read;
-                       rv      += nr_read;
-
-                       if (final)
-                               goto out_free_page;
+                       /* Only first chunk can be read partially. */
+                       pos1 = 0;
+                       i++;
                }
-skip_argv_envp:
-               ;
        }
 
 out_free_page: