diff --git a/SOURCES/quota-4.01-Properly-handle-signed-space-and-inode-values.patch b/SOURCES/quota-4.01-Properly-handle-signed-space-and-inode-values.patch
new file mode 100644
index 0000000..d2aedb6
--- /dev/null
+++ b/SOURCES/quota-4.01-Properly-handle-signed-space-and-inode-values.patch
@@ -0,0 +1,155 @@
+From 0214512479e04a3e118cbef8703aa1aec5240f3f Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@suse.cz>
+Date: Thu, 1 May 2014 18:08:09 +0200
+Subject: [PATCH] Properly handle signed space and inode values
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+For cluster filesystems, kernel can sometimes return negative values of
+used space or inodes (because counters are not completely synchronized
+across the cluster). Make quota tools properly print these.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Petr Písař <ppisar@redhat.com>
+---
+ quotasys.c | 47 +++++++++++++++++++++++++++++++----------------
+ quotasys.h |  2 +-
+ 2 files changed, 32 insertions(+), 17 deletions(-)
+
+diff --git a/quotasys.c b/quotasys.c
+index dee5118..120125a 100644
+--- a/quotasys.c
++++ b/quotasys.c
+@@ -376,6 +376,7 @@ int str2timeunits(time_t num, char *unit, time_t *res)
+ 	return 0;
+ }
+ 
++#define DIV_ROUND_UP(x, d) (((x) + d - 1) / d)
+ /*
+  * Convert number in quota blocks to some nice short form for printing
+  */
+@@ -383,18 +384,26 @@ void space2str(qsize_t space, char *buf, int format)
+ {
+ 	int i;
+ 	char suffix[8] = " MGT";
++	qsize_t aspace = space >= 0 ? space : -space;
+ 
+ 	space = qb2kb(space);
+ 	if (format) {
+-		for (i = 3; i > 0; i--)
+-			if (space >= (1LL << (QUOTABLOCK_BITS*i))*100) {
+-				sprintf(buf, "%llu%c", (unsigned long long)(space+(1 << (QUOTABLOCK_BITS*i))-1) >> (QUOTABLOCK_BITS*i), suffix[i]);
++		for (i = 3; i > 0; i--) {
++			long long unit = 1LL << (QUOTABLOCK_BITS*i);
++
++			if (aspace >= unit * 100) {
++				int sign = aspace != space ? -1 : 1;
++
++				sprintf(buf, "%lld%c", (long long)
++					DIV_ROUND_UP(aspace, unit) * sign,
++					suffix[i]);
+ 				return;
+ 			}
+-		sprintf(buf, "%lluK", (unsigned long long)space);
++		}
++		sprintf(buf, "%lldK", (long long)space);
+ 		return;
+ 	}
+-	sprintf(buf, "%llu", (unsigned long long)space);
++	sprintf(buf, "%lld", (long long)space);
+ }
+ 
+ /*
+@@ -404,11 +413,11 @@ void space2str(qsize_t space, char *buf, int format)
+ const char *str2space(const char *string, qsize_t *space)
+ {
+ 	char *unit;
+-	unsigned long long int number;
++	long long int number;
+ 	int unit_shift;
+        
+-	number = strtoull(string, &unit, 0);
+-	if (ULLONG_MAX == number)
++	number = strtoll(string, &unit, 0);
++	if (number == LLONG_MAX || number == LLONG_MIN)
+ 		return _("Integer overflow while parsing space number.");
+ 
+ 	if (!unit || unit[0] == '\0' || !strcmp(unit, _("K")))
+@@ -422,7 +431,8 @@ const char *str2space(const char *string, qsize_t *space)
+ 	else
+ 		return _("Unknown space binary unit. "
+ 			"Valid units are K, M, G, T.");
+-	if (number > (QSIZE_MAX >> unit_shift))
++	if (number > (QSIZE_MAX >> unit_shift) ||
++	    number < -(QSIZE_MAX >> unit_shift))
+ 		return _("Integer overflow while interpreting space unit.");
+ 	*space = number << unit_shift;
+ 	return NULL;
+@@ -431,19 +441,23 @@ const char *str2space(const char *string, qsize_t *space)
+ /*
+  *  Convert number to some nice short form for printing
+  */
+-void number2str(unsigned long long num, char *buf, int format)
++void number2str(long long num, char *buf, int format)
+ {
+ 	int i;
+ 	unsigned long long div;
+ 	char suffix[8] = " kmgt";
++	long long anum = num >= 0 ? num : -num;
+ 
+ 	if (format)
+ 		for (i = 4, div = 1000000000000LL; i > 0; i--, div /= 1000)
+ 			if (num >= 100*div) {
+-				sprintf(buf, "%llu%c", (num+div-1) / div, suffix[i]);
++				int sign = num != anum ? -1 : 1;
++
++				sprintf(buf, "%lld%c", (num+div-1) / div * sign,
++					suffix[i]);
+ 				return;
+ 			}
+-	sprintf(buf, "%llu", num);
++	sprintf(buf, "%lld", num);
+ }
+ 
+ /*
+@@ -453,10 +467,10 @@ void number2str(unsigned long long num, char *buf, int format)
+ const char *str2number(const char *string, qsize_t *inodes)
+ {
+ 	char *unit;
+-	unsigned long long int number, multiple;
++	long long int number, multiple;
+        
+-	number = strtoull(string, &unit, 0);
+-	if (ULLONG_MAX == number)
++	number = strtoll(string, &unit, 0);
++	if (number == LLONG_MAX || number == LLONG_MIN)
+ 		return _("Integer overflow while parsing number.");
+ 
+ 	if (!unit || unit[0] == '\0')
+@@ -472,7 +486,8 @@ const char *str2number(const char *string, qsize_t *inodes)
+ 	else
+ 		return _("Unknown decimal unit. "
+ 			"Valid units are k, m, g, t.");
+-	if (number > QSIZE_MAX / multiple)
++	if (number > QSIZE_MAX / multiple ||
++	    -number < QSIZE_MAX / multiple)
+ 		return _("Integer overflow while interpreting decimal unit.");
+ 	*inodes = number * multiple;
+ 	return NULL;
+diff --git a/quotasys.h b/quotasys.h
+index 5ca26e6..e79f8cd 100644
+--- a/quotasys.h
++++ b/quotasys.h
+@@ -113,7 +113,7 @@ void space2str(qsize_t, char *, int);
+ const char *str2space(const char *string, qsize_t *space);
+ 
+ /* Convert number to short printable form */
+-void number2str(unsigned long long, char *, int);
++void number2str(long long, char *, int);
+ 
+ /* Convert inode number with unit from string to quota inodes. */
+ const char *str2number(const char *string, qsize_t *inodes);
+-- 
+2.13.6
+
diff --git a/SOURCES/quota-4.02-Fix-handling-of-space-and-inode-values.patch b/SOURCES/quota-4.02-Fix-handling-of-space-and-inode-values.patch
new file mode 100644
index 0000000..46c2308
--- /dev/null
+++ b/SOURCES/quota-4.02-Fix-handling-of-space-and-inode-values.patch
@@ -0,0 +1,64 @@
+From 663ac451b045b4823d6d633893a5d748c09f42f2 Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@suse.cz>
+Date: Wed, 1 Oct 2014 18:10:40 +0200
+Subject: [PATCH] Fix handling of space and inode values
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Commit 0214512479e0 (Properly handle signed space and inode values)
+broke parsing of pure numbers in str2number() so that it would always
+complain about "Integer overflow while interpreting decimal unit". Fix
+condition checking for overflow.
+
+Also number2str() was buggy and wouldn't guess proper units for negative
+numbers.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Petr Písař <ppisar@redhat.com>
+---
+ quotasys.c | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+diff --git a/quotasys.c b/quotasys.c
+index a5737a8..4b49e0e 100644
+--- a/quotasys.c
++++ b/quotasys.c
+@@ -459,17 +459,19 @@ void number2str(long long num, char *buf, int format)
+ 	int i;
+ 	unsigned long long div;
+ 	char suffix[8] = " kmgt";
+-	long long anum = num >= 0 ? num : -num;
+ 
+-	if (format)
+-		for (i = 4, div = 1000000000000LL; i > 0; i--, div /= 1000)
+-			if (num >= 100*div) {
+-				int sign = num != anum ? -1 : 1;
++	if (format) {
++		long long anum = num >= 0 ? num : -num;
++		int sign = num != anum ? -1 : 1;
+ 
+-				sprintf(buf, "%lld%c", (num+div-1) / div * sign,
++		for (i = 4, div = 1000000000000LL; i > 0; i--, div /= 1000)
++			if (anum >= 100*div) {
++				sprintf(buf, "%lld%c",
++					DIV_ROUND_UP(anum, div) * sign,
+ 					suffix[i]);
+ 				return;
+ 			}
++	}
+ 	sprintf(buf, "%lld", num);
+ }
+ 
+@@ -500,7 +502,7 @@ const char *str2number(const char *string, qsize_t *inodes)
+ 		return _("Unknown decimal unit. "
+ 			"Valid units are k, m, g, t.");
+ 	if (number > QSIZE_MAX / multiple ||
+-	    -number < QSIZE_MAX / multiple)
++	    number < -(QSIZE_MAX / multiple))
+ 		return _("Integer overflow while interpreting decimal unit.");
+ 	*inodes = number * multiple;
+ 	return NULL;
+-- 
+1.9.3
+
diff --git a/SOURCES/quota-4.03-quotacheck-Deallocate-memory-after-direct-scanning.patch b/SOURCES/quota-4.03-quotacheck-Deallocate-memory-after-direct-scanning.patch
new file mode 100644
index 0000000..ee02d7b
--- /dev/null
+++ b/SOURCES/quota-4.03-quotacheck-Deallocate-memory-after-direct-scanning.patch
@@ -0,0 +1,99 @@
+From bf9b17da317ecf56ceada3a575fb95669bf2041b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
+Date: Mon, 21 Aug 2017 13:02:21 +0200
+Subject: [PATCH] quotacheck: Deallocate memory after direct scanning
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+quotacheck had memory leaks because it did not clean up after direct
+ext scanning:
+
+==6885== 1,392 (88 direct, 1,304 indirect) bytes in 1 blocks are definitely lost in loss record 19 of 23
+==6885==    at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
+==6885==    by 0x4E5288B: ext2fs_make_generic_bitmap (in /usr/lib64/libext2fs.so.2.4)
+==6885==    by 0x4E47ED5: ext2fs_allocate_inode_bitmap (in /usr/lib64/libext2fs.so.2.4)
+==6885==    by 0x10BBA5: ext2_direct_scan (quotacheck.c:435)
+==6885==    by 0x10DA8A: check_dir (quotacheck.c:971)
+==6885==    by 0x10E634: check_all (quotacheck.c:1192)
+==6885==    by 0x10E6EC: main (quotacheck.c:1212)
+==6885==
+==6885== 8,464 (144 direct, 8,320 indirect) bytes in 1 blocks are definitely lost in loss record 22 of 23
+==6885==    at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
+==6885==    by 0x4E5749D: ext2fs_open_inode_scan (in /usr/lib64/libext2fs.so.2.4)
+==6885==    by 0x10BBF0: ext2_direct_scan (quotacheck.c:440)
+==6885==    by 0x10DA8A: check_dir (quotacheck.c:971)
+==6885==    by 0x10E634: check_all (quotacheck.c:1192)
+==6885==    by 0x10E6EC: main (quotacheck.c:1212)
+==6885==
+==6885== 15,243 (88 direct, 15,155 indirect) bytes in 1 blocks are definitely lost in loss record 23 of 23
+==6885==    at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
+==6885==    by 0x4E5288B: ext2fs_make_generic_bitmap (in /usr/lib64/libext2fs.so.2.4)
+==6885==    by 0x4E47ED5: ext2fs_allocate_inode_bitmap (in /usr/lib64/libext2fs.so.2.4)
+==6885==    by 0x10BB55: ext2_direct_scan (quotacheck.c:430)
+==6885==    by 0x10DA8A: check_dir (quotacheck.c:971)
+==6885==    by 0x10E634: check_all (quotacheck.c:1192)
+==6885==    by 0x10E6EC: main (quotacheck.c:1212)
+
+Signed-off-by: Petr Písař <ppisar@redhat.com>
+---
+ quotacheck.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/quotacheck.c b/quotacheck.c
+index 689ceb9..e9a84ba 100644
+--- a/quotacheck.c
++++ b/quotacheck.c
+@@ -429,21 +429,31 @@ static int ext2_direct_scan(const char *device)
+ 
+ 	if ((error = ext2fs_allocate_inode_bitmap(fs, "in-use inode map", &inode_used_map))) {
+ 		errstr(_("error (%d) while allocating file inode bitmap\n"), (int)error);
++		ext2fs_free(fs);
+ 		return -1;
+ 	}
+ 
+ 	if ((error = ext2fs_allocate_inode_bitmap(fs, "directory inode map", &inode_dir_map))) {
+ 		errstr(_("errstr (%d) while allocating directory inode bitmap\n"), (int)error);
++		ext2fs_free_inode_bitmap(inode_used_map);
++		ext2fs_free(fs);
+ 		return -1;
+ 	}
+ 
+ 	if ((error = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan))) {
+ 		errstr(_("error (%d) while opening inode scan\n"), (int)error);
++		ext2fs_free_inode_bitmap(inode_dir_map);
++		ext2fs_free_inode_bitmap(inode_used_map);
++		ext2fs_free(fs);
+ 		return -1;
+ 	}
+ 
+ 	if ((error = ext2fs_get_next_inode(scan, &i_num, &inode))) {
+ 		errstr(_("error (%d) while starting inode scan\n"), (int)error);
++		ext2fs_close_inode_scan(scan);
++		ext2fs_free_inode_bitmap(inode_dir_map);
++		ext2fs_free_inode_bitmap(inode_used_map);
++		ext2fs_free(fs);
+ 		return -1;
+ 	}
+ 
+@@ -474,9 +484,17 @@ static int ext2_direct_scan(const char *device)
+ 
+ 		if ((error = ext2fs_get_next_inode(scan, &i_num, &inode))) {
+ 			errstr(_("Something weird happened while scanning. Error %d\n"), (int)error);
++			ext2fs_close_inode_scan(scan);
++			ext2fs_free_inode_bitmap(inode_dir_map);
++			ext2fs_free_inode_bitmap(inode_used_map);
++			ext2fs_free(fs);
+ 			return -1;
+ 		}
+ 	}
++	ext2fs_close_inode_scan(scan);
++	ext2fs_free_inode_bitmap(inode_dir_map);
++	ext2fs_free_inode_bitmap(inode_used_map);
++	ext2fs_free(fs);
+ 	return 0;
+ }
+ #endif
+-- 
+2.9.5
+
diff --git a/SOURCES/quota-4.03-quotacheck-Use-direct-scanning-also-for-ext4.patch b/SOURCES/quota-4.03-quotacheck-Use-direct-scanning-also-for-ext4.patch
new file mode 100644
index 0000000..8d5048a
--- /dev/null
+++ b/SOURCES/quota-4.03-quotacheck-Use-direct-scanning-also-for-ext4.patch
@@ -0,0 +1,36 @@
+From 2b3795805c8d1bd8873b046508777fa6e9a5c83d Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@suse.cz>
+Date: Tue, 9 Aug 2016 19:17:56 +0200
+Subject: [PATCH] quotacheck: Use direct scanning also for ext4
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We mistakenly didn't use direct scanning through libext2fs for ext4
+filesystem. Add ext4 to the list of filesystem libext2fs can handle.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Petr Písař <ppisar@redhat.com>
+---
+ quotacheck.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/quotacheck.c b/quotacheck.c
+index 6f34cff..a6fe432 100644
+--- a/quotacheck.c
++++ b/quotacheck.c
+@@ -959,7 +959,10 @@ Please stop all programs writing to filesystem or use -m flag to force checking.
+ start_scan:
+ 	debug(FL_VERBOSE | FL_DEBUG, _("Scanning %s [%s] "), mnt->me_devname, mnt->me_dir);
+ #if defined(EXT2_DIRECT)
+-	if (!strcmp(mnt->me_type, MNTTYPE_EXT2) || !strcmp(mnt->me_type, MNTTYPE_EXT3) || !strcmp(mnt->me_type, MNTTYPE_NEXT3)) {
++	if (!strcmp(mnt->me_type, MNTTYPE_EXT2) ||
++	    !strcmp(mnt->me_type, MNTTYPE_EXT3) ||
++	    !strcmp(mnt->me_type, MNTTYPE_NEXT3) ||
++	    !strcmp(mnt->me_type, MNTTYPE_EXT4)) {
+ 		if ((failed = ext2_direct_scan(mnt->me_devname)) < 0)
+ 			goto out;
+ 	}
+-- 
+2.7.4
+
diff --git a/SPECS/quota.spec b/SPECS/quota.spec
index 3494379..a45520e 100644
--- a/SPECS/quota.spec
+++ b/SPECS/quota.spec
@@ -5,7 +5,7 @@ Name: quota
 Summary: System administration tools for monitoring users' disk usage
 Epoch: 1
 Version: 4.01
-Release: 14%{?dist}
+Release: 17%{?dist}
 # quota_nld.c, quotaio_xfs.h:       GPLv2
 # bylabel.c copied from util-linux: GPLv2+
 # svc_socket.c copied from glibc:   LGPLv2+
@@ -85,6 +85,15 @@ Patch25: quota-4.03-Add-support-for-scanning-using-Q_XGETNEXTQUOTA.patch
 # Prevent from grace period overflow in RPC transport, bug #1072858,
 # in upstream 4.02
 Patch26: quota-4.01-Prevent-from-grace-period-overflow-in-RPC-transport.patch
+# Use direct scanning also for ext4, bug #1393849, in upsream after 4.03
+Patch27: quota-4.03-quotacheck-Use-direct-scanning-also-for-ext4.patch
+# Fix memory leaks when running quotacheck on ext file systems, bug #1483543,
+# <https://sourceforge.net/p/linuxquota/bugs/126/>
+Patch28: quota-4.03-quotacheck-Deallocate-memory-after-direct-scanning.patch
+# Bug #1517822, in upstream 4.02
+Patch29: quota-4.01-Properly-handle-signed-space-and-inode-values.patch
+# Bug #1517822, in upstream 4.02
+Patch30: quota-4.02-Fix-handling-of-space-and-inode-values.patch
 
 %description
 The quota package contains system administration tools for monitoring
@@ -182,6 +191,10 @@ Linux/UNIX environment.
 %patch24 -p1 -b .getnextquota
 %patch25 -p1 -b .xgetnextquota
 %patch26 -p1 -b .rpc_time
+%patch27 -p1 -b .directext4
+%patch28 -p1 -b .quotacheck_leak
+%patch29 -p1 -b .signed_values
+%patch30 -p1 -b .fix_signed_values
 
 #fix typos/mistakes in localized documentation
 for pofile in $(find ./po/*.p*)
@@ -306,6 +319,15 @@ echo '  systemd-sysv-convert --apply quota_nld'
 
 
 %changelog
+* Mon Nov 27 2017 Petr Pisar <ppisar@redhat.com> - 1:4.01-17
+- Print negative quota values properly (bug #1517822)
+
+* Mon Aug 21 2017 Petr Pisar <ppisar@redhat.com> - 1:4.01-16
+- Fix memory leaks when running quotacheck on ext file systems (bug #1483543)
+
+* Thu Nov 10 2016 Petr Pisar <ppisar@redhat.com> - 1:4.01-15
+- Use direct scanning also for ext4 (bug #1393849)
+
 * Thu Mar 10 2016 Petr Pisar <ppisar@redhat.com> - 1:4.01-14
 - Add nfs-rquotad.service alias for backward compatibility (bug #1207239)
 - Start rpc-rquotad.service when starting nfs-server.service (bug #1207239)