@@ -29,6 +29,7 @@
#include <linux/swap.h>
#include <linux/atomic.h>
+#include <linux/misc_cgroup.h>
#include "internal.h"
@@ -53,8 +54,14 @@ static void file_free_rcu(struct rcu_head *head)
static inline void file_free(struct file *f)
{
security_file_free(f);
- if (!(f->f_mode & FMODE_NOACCOUNT))
+ if (!(f->f_mode & FMODE_NOACCOUNT)) {
+ struct misc_cg *misc_cg = css_misc(f->f_css);
+
+ misc_cg_uncharge(MISC_CG_RES_NOFILE, misc_cg, 1);
+ put_misc_cg(misc_cg);
+
percpu_counter_dec(&nr_files);
+ }
call_rcu(&f->f_u.fu_rcuhead, file_free_rcu);
}
@@ -148,8 +155,20 @@ struct file *alloc_empty_file(int flags, const struct cred *cred)
}
f = __alloc_file(flags, cred);
- if (!IS_ERR(f))
+ if (!IS_ERR(f)) {
+ struct misc_cg *misc_cg = get_current_misc_cg();
+ int ret;
+
+ ret = misc_cg_try_charge(MISC_CG_RES_NOFILE, misc_cg, 1);
+ if (ret < 0) {
+ put_misc_cg(misc_cg);
+ file_free(f);
+ goto out;
+ }
+
percpu_counter_inc(&nr_files);
+ f->f_css = &misc_cg->css;
+ }
return f;
@@ -159,6 +178,7 @@ struct file *alloc_empty_file(int flags, const struct cred *cred)
pr_info("VFS: file-max limit %lu reached\n", get_max_files());
old_max = get_nr_files();
}
+ out:
return ERR_PTR(-ENFILE);
}
@@ -397,4 +417,5 @@ void __init files_maxfiles_init(void)
n = ((nr_pages - memreserve) * (PAGE_SIZE / 1024)) / 10;
files_stat.max_files = max_t(unsigned long, n, NR_FILE);
+ misc_cg_set_capacity(MISC_CG_RES_NOFILE, files_stat.max_files);
}
@@ -947,7 +947,9 @@ struct file {
#endif
/* needed for tty driver, and maybe others */
void *private_data;
-
+#ifdef CONFIG_CGROUP_MISC
+ struct cgroup_subsys_state *f_css;
+#endif
#ifdef CONFIG_EPOLL
/* Used by fs/eventpoll.c to link all the hooks to this file */
struct hlist_head *f_ep;
@@ -18,6 +18,7 @@ enum misc_res_type {
/* AMD SEV-ES ASIDs resource */
MISC_CG_RES_SEV_ES,
#endif
+ MISC_CG_RES_NOFILE,
MISC_CG_RES_TYPES
};
@@ -24,6 +24,7 @@ static const char *const misc_res_name[] = {
/* AMD SEV-ES ASIDs resource */
"sev_es",
#endif
+ "nofile"
};
/* Root misc cgroup */