diff --git a/SOURCES/grep-2.20-egrep-fgrep-symlinks.patch b/SOURCES/grep-2.20-egrep-fgrep-symlinks.patch
new file mode 100644
index 0000000..3ca0923
--- /dev/null
+++ b/SOURCES/grep-2.20-egrep-fgrep-symlinks.patch
@@ -0,0 +1,82 @@
+--- a/src/Makefile.am	
++++ a/src/Makefile.am	
+@@ -56,7 +56,8 @@ egrep fgrep: egrep.sh Makefile
+ 	sed -e 's|[@]SHELL@|$(SHELL)|g' \
+ 	    -e "$$edit_substring" \
+ 	    -e "s|[@]grep@|$$grep|g" \
+-	    -e "s|[@]option@|$$option|g" <$(srcdir)/egrep.sh >$@-t
++	    -e "s|[@]option@|$$option|g" \
++	    -e "s|[@]cmd@|$@|g" <$(srcdir)/egrep.sh >$@-t
+ 	$(AM_V_at)chmod +x $@-t
+ 	$(AM_V_at)mv $@-t $@
+ 
+--- a/src/Makefile.in	
++++ a/src/Makefile.in	
+@@ -1541,7 +1541,8 @@ egrep fgrep: egrep.sh Makefile
+ 	sed -e 's|[@]SHELL@|$(SHELL)|g' \
+ 	    -e "$$edit_substring" \
+ 	    -e "s|[@]grep@|$$grep|g" \
+-	    -e "s|[@]option@|$$option|g" <$(srcdir)/egrep.sh >$@-t
++	    -e "s|[@]option@|$$option|g" \
++	    -e "s|[@]cmd@|$@|g" <$(srcdir)/egrep.sh >$@-t
+ 	$(AM_V_at)chmod +x $@-t
+ 	$(AM_V_at)mv $@-t $@
+ 
+--- a/src/egrep.sh	
++++ a/src/egrep.sh	
+@@ -1,5 +1,6 @@ 
+ #!@SHELL@
+ grep=grep
++unset _EXECOPT _GREPOPT
+ case $0 in
+   */*)
+     dir=${0%/*}
+@@ -8,4 +9,9 @@ case $0 in
+       grep=@grep@
+     fi;;
+ esac
+-exec $grep @option@ "$@"
++if [ "$GREP_LEGACY_EGREP_FGREP_PS" = 1 ]; then
++  _EXECOPT="-a @cmd@"
++else
++  _GREPOPT=@option@
++fi
++exec $_EXECOPT $grep $_GREPOPT "$@"
+--- a/src/grep.c	
++++ a/src/grep.c	
+@@ -26,6 +26,7 @@ 
+ #include <fcntl.h>
+ #include <inttypes.h>
+ #include <stdio.h>
++#include <string.h>
+ #include "system.h"
+ 
+ #include "argmatch.h"
+@@ -1938,6 +1939,7 @@ fgrep_to_grep_pattern (size_t len, char const *keys,
+ int
+ main (int argc, char **argv)
+ {
++  char *ptr_c;
+   char *keys;
+   size_t keycc, oldcc, keyalloc;
+   int with_filenames;
+@@ -1984,6 +1986,19 @@ main (int argc, char **argv)
+   compile = matchers[0].compile;
+   execute = matchers[0].execute;
+ 
++  /* Check if executed through symlinks egrep/fgrep */
++  if (argv[0] != NULL)
++    {
++      ptr_c = strchrnul(argv[0], ' ');
++      if (ptr_c - argv[0] >= 5)
++        {
++          if (strncmp(ptr_c - 5, "egrep", 5) == 0)
++            setmatcher ("egrep");
++          else if (strncmp(ptr_c - 5, "fgrep", 5) == 0)
++            setmatcher ("fgrep");
++        }
++    }
++
+   while (prev_optind = optind,
+          (opt = get_nondigit_option (argc, argv, &default_context)) != -1)
+     switch (opt)
diff --git a/SOURCES/grep-2.20-long-pattern-speedup.patch b/SOURCES/grep-2.20-long-pattern-speedup.patch
new file mode 100644
index 0000000..bd7ccf9
--- /dev/null
+++ b/SOURCES/grep-2.20-long-pattern-speedup.patch
@@ -0,0 +1,119 @@
+diff --git a/src/dfa.c b/src/dfa.c
+index b9b7103..cd11db6 100644
+--- a/src/dfa.c
++++ b/src/dfa.c
+@@ -3894,13 +3894,13 @@ struct must
+ };
+ 
+ static must *
+-allocmust (must *mp)
++allocmust (must *mp, size_t size)
+ {
+   must *new_mp = xmalloc (sizeof *new_mp);
+   new_mp->in = xzalloc (sizeof *new_mp->in);
+-  new_mp->left = xzalloc (2);
+-  new_mp->right = xzalloc (2);
+-  new_mp->is = xzalloc (2);
++  new_mp->left = xzalloc (size);
++  new_mp->right = xzalloc (size);
++  new_mp->is = xzalloc (size);
+   new_mp->begline = false;
+   new_mp->endline = false;
+   new_mp->prev = mp;
+@@ -3933,24 +3933,23 @@ dfamust (struct dfa *d)
+ {
+   must *mp = NULL;
+   char const *result = "";
+-  size_t ri;
+   size_t i;
+   bool exact = false;
+   bool begline = false;
+   bool endline = false;
+   struct dfamust *dm;
+ 
+-  for (ri = 0; ri < d->tindex; ++ri)
++  for (size_t ri = 0; ri < d->tindex; ++ri)
+     {
+       token t = d->tokens[ri];
+       switch (t)
+         {
+         case BEGLINE:
+-          mp = allocmust (mp);
++          mp = allocmust (mp, 2);
+           mp->begline = true;
+           break;
+         case ENDLINE:
+-          mp = allocmust (mp);
++          mp = allocmust (mp, 2);
+           mp->endline = true;
+           break;
+         case LPAREN:
+@@ -3965,7 +3964,7 @@ dfamust (struct dfa *d)
+         case BACKREF:
+         case ANYCHAR:
+         case MBCSET:
+-          mp = allocmust (mp);
++          mp = allocmust (mp, 2);
+           break;
+ 
+         case STAR:
+@@ -4082,7 +4081,6 @@ dfamust (struct dfa *d)
+           goto done;
+ 
+         default:
+-          mp = allocmust (mp);
+           if (CSET <= t)
+             {
+               /* If T is a singleton, or if case-folding in a unibyte
+@@ -4095,7 +4093,10 @@ dfamust (struct dfa *d)
+                 if (tstbit (j, *ccl))
+                   break;
+               if (! (j < NOTCHAR))
+-                break;
++                {
++                  mp = allocmust (mp, 2);
++                  break;
++                }
+               t = j;
+               while (++j < NOTCHAR)
+                 if (tstbit (j, *ccl)
+@@ -4103,12 +4104,36 @@ dfamust (struct dfa *d)
+                           && toupper (j) == toupper (t)))
+                   break;
+               if (j < NOTCHAR)
+-                break;
++                {
++                  mp = allocmust (mp, 2);
++                  break;
++                }
+             }
++
++          size_t rj = ri + 2;
++          if (d->tokens[ri + 1] == CAT)
++            {
++              for (; rj < d->tindex - 1; rj += 2)
++                {
++                  if ((rj != ri && (d->tokens[rj] <= 0
++                                    || NOTCHAR <= d->tokens[rj]))
++                      || d->tokens[rj + 1] != CAT)
++                    break;
++                }
++            }
++          mp = allocmust (mp, ((rj - ri) >> 1) + 1);
+           mp->is[0] = mp->left[0] = mp->right[0]
+             = case_fold && !d->multibyte ? toupper (t) : t;
+-          mp->is[1] = mp->left[1] = mp->right[1] = '\0';
+-          mp->in = enlist (mp->in, mp->is, 1);
++
++          for (i = 1; ri + 2 < rj; i++)
++            {
++              ri += 2;
++              t = d->tokens[ri];
++              mp->is[i] = mp->left[i] = mp->right[i]
++                = case_fold && MB_CUR_MAX == 1 ? toupper (t) : t;
++            }
++          mp->is[i] = mp->left[i] = mp->right[i] = '\0';
++          mp->in = enlist (mp->in, mp->is, i - 1);
+           break;
+         }
+     }
diff --git a/SPECS/grep.spec b/SPECS/grep.spec
index 8f9c6e3..2abc1fc 100644
--- a/SPECS/grep.spec
+++ b/SPECS/grep.spec
@@ -3,7 +3,7 @@
 Summary: Pattern matching utilities
 Name: grep
 Version: 2.20
-Release: 2%{?dist}
+Release: 3%{?dist}
 License: GPLv3+
 Group: Applications/Text
 Source: ftp://ftp.gnu.org/pub/gnu/grep/grep-%{version}.tar.xz
@@ -23,6 +23,9 @@ Patch3: grep-2.20-man-fixed-regexp-option.patch
 Patch4: grep-2.20-pcre-backported-fixes.patch
 # rhbz#1194315
 Patch5: grep-2.20-CVE-2015-1345.patch
+Patch6: grep-2.20-egrep-fgrep-symlinks.patch
+# rhbz#1413029, backported from upstream
+Patch7: grep-2.20-long-pattern-speedup.patch
 URL: http://www.gnu.org/software/grep/
 Requires(post): /sbin/install-info
 Requires(preun): /sbin/install-info
@@ -47,6 +50,8 @@ GNU grep is needed by many scripts, so it shall be installed on every system.
 %patch3 -p1 -b .man-fixed-rexexp-option
 %patch4 -p1 -b .pcre-backported-fixes
 %patch5 -p1 -b .CVE-2015-1345
+%patch6 -p1 -b .egrep-fgrep-symlinks
+%patch7 -p1 -b .long-pattern-speedup
 
 chmod 755 tests/word-multibyte
 chmod 755 tests/pcre-invalid-utf8-input
@@ -105,6 +110,13 @@ fi
 %{_libexecdir}/grepconf.sh
 
 %changelog
+* Fri Mar 24 2017 Jaroslav Škarvada <jskarvad@redhat.com> - 2.20-3
+- Speedup DFA for long patterns and fixed begline/endline matching
+  Resolves: rhbz#1413029
+- Added support for GREP_LEGACY_EGREP_FGREP_PS environmental variable which
+  controls how egrep, fgrep show in ps output
+  Resolves: rhbz#1297441
+
 * Wed Apr 29 2015 Jaroslav Škarvada <jskarvad@redhat.com> - 2.20-2
 - Fixed invalid UTF-8 byte sequence error in PCRE mode
   (by pcre-backported-fixes patch)