Patch "fs/quota: handle overflows of sysctl fs.quota.* and report as unsigned long" has been added to the 4.4-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    fs/quota: handle overflows of sysctl fs.quota.* and report as unsigned long

to the 4.4-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     fs-quota-handle-overflows-of-sysctl-fs.quota.-and-re.patch
and it can be found in the queue-4.4 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit a4d246b363b0e4e924e3bff2631e677c11a608b5
Author: Konstantin Khlebnikov <khlebnikov@xxxxxxxxxxxxxx>
Date:   Sun Nov 10 12:49:06 2019 +0300

    fs/quota: handle overflows of sysctl fs.quota.* and report as unsigned long
    
    [ Upstream commit 6fcbcec9cfc7b3c6a2c1f1a23ebacedff7073e0a ]
    
    Quota statistics counted as 64-bit per-cpu counter. Reading sums per-cpu
    fractions as signed 64-bit int, filters negative values and then reports
    lower half as signed 32-bit int.
    
    Result may looks like:
    
    fs.quota.allocated_dquots = 22327
    fs.quota.cache_hits = -489852115
    fs.quota.drops = -487288718
    fs.quota.free_dquots = 22083
    fs.quota.lookups = -486883485
    fs.quota.reads = 22327
    fs.quota.syncs = 335064
    fs.quota.writes = 3088689
    
    Values bigger than 2^31-1 reported as negative.
    
    All counters except "allocated_dquots" and "free_dquots" are monotonic,
    thus they should be reported as is without filtering negative values.
    
    Kernel doesn't have generic helper for 64-bit sysctl yet,
    let's use at least unsigned long.
    
    Link: https://lore.kernel.org/r/157337934693.2078.9842146413181153727.stgit@buzz
    Signed-off-by: Konstantin Khlebnikov <khlebnikov@xxxxxxxxxxxxxx>
    Signed-off-by: Jan Kara <jack@xxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 7430cb0e21a7..b7d5e254792c 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2783,68 +2783,73 @@ EXPORT_SYMBOL(dquot_quotactl_sysfile_ops);
 static int do_proc_dqstats(struct ctl_table *table, int write,
 		     void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-	unsigned int type = (int *)table->data - dqstats.stat;
+	unsigned int type = (unsigned long *)table->data - dqstats.stat;
+	s64 value = percpu_counter_sum(&dqstats.counter[type]);
+
+	/* Filter negative values for non-monotonic counters */
+	if (value < 0 && (type == DQST_ALLOC_DQUOTS ||
+			  type == DQST_FREE_DQUOTS))
+		value = 0;
 
 	/* Update global table */
-	dqstats.stat[type] =
-			percpu_counter_sum_positive(&dqstats.counter[type]);
-	return proc_dointvec(table, write, buffer, lenp, ppos);
+	dqstats.stat[type] = value;
+	return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
 }
 
 static struct ctl_table fs_dqstats_table[] = {
 	{
 		.procname	= "lookups",
 		.data		= &dqstats.stat[DQST_LOOKUPS],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
 	{
 		.procname	= "drops",
 		.data		= &dqstats.stat[DQST_DROPS],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
 	{
 		.procname	= "reads",
 		.data		= &dqstats.stat[DQST_READS],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
 	{
 		.procname	= "writes",
 		.data		= &dqstats.stat[DQST_WRITES],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
 	{
 		.procname	= "cache_hits",
 		.data		= &dqstats.stat[DQST_CACHE_HITS],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
 	{
 		.procname	= "allocated_dquots",
 		.data		= &dqstats.stat[DQST_ALLOC_DQUOTS],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
 	{
 		.procname	= "free_dquots",
 		.data		= &dqstats.stat[DQST_FREE_DQUOTS],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
 	{
 		.procname	= "syncs",
 		.data		= &dqstats.stat[DQST_SYNCS],
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(unsigned long),
 		.mode		= 0444,
 		.proc_handler	= do_proc_dqstats,
 	},
diff --git a/include/linux/quota.h b/include/linux/quota.h
index b2505acfd3c0..b34412df1542 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -253,7 +253,7 @@ enum {
 };
 
 struct dqstats {
-	int stat[_DQST_DQSTAT_LAST];
+	unsigned long stat[_DQST_DQSTAT_LAST];
 	struct percpu_counter counter[_DQST_DQSTAT_LAST];
 };
 



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux