@@ -37,6 +37,8 @@ struct files_stat_struct files_stat = {
.max_files = NR_FILE
};
+DECLARE_RWSEM(file_number_sem);
+
/* SLAB cache for file structures */
static struct kmem_cache *filp_cachep __ro_after_init;
static struct kmem_cache *bfilp_cachep __ro_after_init;
@@ -102,8 +104,13 @@ EXPORT_SYMBOL_GPL(get_max_files);
static int proc_nr_files(const struct ctl_table *table, int write, void *buffer,
size_t *lenp, loff_t *ppos)
{
+ int ret;
+
+ down_read(&file_number_sem);
files_stat.nr_files = get_nr_files();
- return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
+ ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
+ up_read(&file_number_sem);
+ return ret;
}
static struct ctl_table fs_stat_sysctls[] = {
@@ -90,6 +90,7 @@ extern void __init files_maxfiles_init(void);
extern unsigned long get_max_files(void);
extern unsigned int sysctl_nr_open;
extern struct files_stat_struct files_stat;
+extern struct rw_semaphore file_number_sem;
typedef __kernel_rwf_t rwf_t;
@@ -951,18 +951,22 @@ int proc_douintvec_minmax(const struct ctl_table *table, int write,
int proc_douintvec_nropen_minmax(const struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
+ int ret;
unsigned int file_max;
struct do_proc_douintvec_minmax_conv_param param = {
.min = (unsigned int *) table->extra1,
.max = (unsigned int *) table->extra2,
};
+ down_write(&file_number_sem);
file_max = min_t(unsigned int, files_stat.max_files,
*(unsigned int *)table->extra2);
if (write)
param.max = &file_max;
- return do_proc_douintvec(table, write, buffer, lenp, ppos,
+ ret = do_proc_douintvec(table, write, buffer, lenp, ppos,
do_proc_douintvec_minmax_conv, ¶m);
+ up_write(&file_number_sem);
+ return ret;
}
/**
@@ -1150,14 +1154,20 @@ int proc_doulongvec_minmax(const struct ctl_table *table, int write,
int proc_doulongvec_maxfiles_minmax(const struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
+ int ret;
unsigned long *min = table->extra1;
unsigned long *max = table->extra2;
- unsigned long nr_open = sysctl_nr_open;
+ unsigned long nr_open;
- if (write)
+ down_write(&file_number_sem);
+ if (write) {
+ nr_open = sysctl_nr_open;
min = &nr_open;
- return __do_proc_doulongvec_minmax(table->data, table, write,
+ }
+ ret = __do_proc_doulongvec_minmax(table->data, table, write,
buffer, lenp, ppos, 1l, 1l, min, max);
+ up_write(&file_number_sem);
+ return ret;
}
/**
Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com> --- fs/file_table.c | 9 ++++++++- include/linux/fs.h | 1 + kernel/sysctl.c | 18 ++++++++++++++---- 3 files changed, 23 insertions(+), 5 deletions(-)