diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index 47ae4c4d924c..d3467412a6f6 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -411,6 +411,39 @@ struct cgroup_freezer_state {
 	int nr_frozen_tasks;
 };
 
+#define CGROUP_NS_HASH_COUNT 2048
+#define BALLOON_CGROUP_HASH_COUNT 2048
+struct cgroup_ns_entry {
+	struct hlist_node hnode;
+	struct cgroup *cgroup;
+	struct ipc_namespace *ipc_ns;
+	struct net *net_ns;
+	struct pid_namespace *pid_ns;
+};
+
+struct balloon_cgroup_entry {
+	struct hlist_node hnode;
+	struct cgroup *balloon_cgroup;
+	struct cgroup *cgroup;
+};
+
+extern struct hlist_head *cg_ns_map;
+extern struct hlist_head *balloon_to_cgroup;
+extern int cg_ns_insert(struct cgroup *cgroup, struct ipc_namespace *ipc_ns,
+				struct net *net_ns, struct pid_namespace *pid_ns);
+extern struct cgroup *find_shared_cg(struct ipc_namespace *ipc_ns, struct net *net_ns,
+				struct pid_namespace *pid_ns, const struct cgroup *cgroup);
+extern int delete_cg_ns_node(struct hlist_head *head, struct cgroup *cgroup);
+
+extern int init_hash_balloon_cg(void);
+extern unsigned int find_balloon_index_from_cgroup(struct cgroup *cgroup);
+extern struct cgroup *find_balloon_from_cgroup(struct cgroup *cgroup);
+extern int insert_cgroup_to_balloon(struct hlist_head *head, struct cgroup *cgroup,
+				struct cgroup *balloon_cgroup);
+extern int init_balloon_cgroup_to_balloon(struct hlist_head *head, struct cgroup *balloon_cgroup);
+extern int delete_balloon_cgroup_node(struct hlist_head *head, struct cgroup *cgroup);
+
+extern struct cgroup *balloon_cgroup_create(unsigned int index);
 struct cgroup {
 	/* self css with NULL ->ss, points back to this cgroup */
 	struct cgroup_subsys_state self;
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index f8ef47f8a634..534561016008 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -70,6 +70,7 @@ extern struct file_system_type cgroup_fs_type;
 extern struct cgroup_root cgrp_dfl_root;
 extern struct css_set init_css_set;
 extern spinlock_t css_set_lock;
+extern struct cgroup *init_balloon;
 
 #define SUBSYS(_x) extern struct cgroup_subsys _x ## _cgrp_subsys;
 #include <linux/cgroup_subsys.h>
@@ -858,3 +859,4 @@ struct cgroup *task_get_cgroup1(struct task_struct *tsk, int hierarchy_id);
 struct cgroup_of_peak *of_peak(struct kernfs_open_file *of);
 
 #endif /* _LINUX_CGROUP_H */
+extern int free_oldest_volume(struct cgroup *target_cgroup, unsigned int limit);
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index cb5280e6cc21..84d6bdb8d3f5 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -301,5 +301,10 @@ static __inline__ int inet_mask_len(__be32 mask)
 	return 32 - ffz(~hmask);
 }
 
-
+extern unsigned long devinet_size(struct ipv4_devconf *ipv4_p);
+extern int devinet_move(struct ipv4_devconf *ipv4_p, struct mem_cgroup *from,
+				struct mem_cgroup *to);
+extern int ipv6_dev_move(struct inet6_dev *in_dev, struct mem_cgroup  *from,
+				struct mem_cgroup  *to);
+extern unsigned long ipv6_size(struct inet6_dev *in_dev);
 #endif /* _LINUX_INETDEVICE_H */
diff --git a/include/linux/ipc.h b/include/linux/ipc.h
index 9b1434247aab..2180e6fb2741 100644
--- a/include/linux/ipc.h
+++ b/include/linux/ipc.h
@@ -10,6 +10,8 @@
 
 /* used by in-kernel data structures */
 struct kern_ipc_perm {
+	struct cgroup *cgroup;
+	unsigned int residual_time;
 	spinlock_t	lock;
 	bool		deleted;
 	int		id;
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index e8240cf2611a..437f7100204c 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -12,6 +12,8 @@
 #include <linux/rhashtable-types.h>
 #include <linux/sysctl.h>
 #include <linux/percpu_counter.h>
+#include <linux/cgroup-defs.h>
+#include <linux/msg.h>
 
 struct user_namespace;
 
@@ -211,3 +213,16 @@ static inline bool setup_ipc_sysctls(struct ipc_namespace *ns)
 
 #endif /* CONFIG_SYSVIPC_SYSCTL */
 #endif
+void free_recycle_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
+	       void (*free)(struct ipc_namespace *, struct kern_ipc_perm *), unsigned int limit);
+extern int ipc_sem_move_check(struct ipc_namespace *ns, struct cgroup *cgrp);
+extern void ipc_sem_free(struct ipc_namespace *ns, unsigned int limit);
+
+extern int ipc_shm_move_check(struct ipc_namespace *ns, struct cgroup *cgrp);
+extern int ipc_shm_folio_move(struct inode *inode, struct mem_cgroup *from, struct mem_cgroup *to);
+extern unsigned long shm_total_pages(struct inode *inode);
+extern void ipc_shm_free(struct ipc_namespace *ns, unsigned int limit);
+
+extern int ipc_msq_move_check(struct ipc_namespace *ns, struct cgroup *cgrp);
+extern int ipc_msg_move(struct msg_msg *msg, struct mem_cgroup *from, struct mem_cgroup *to);
+extern void ipc_msq_free(struct ipc_namespace *ns, unsigned int limit);
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 2ef94c74847d..b65a58f0bfb2 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -23,6 +23,8 @@
 #include <linux/writeback.h>
 #include <linux/page-flags.h>
 #include <linux/shrinker.h>
+#include <linux/device.h>
+#include <linux/cgroup-defs.h>
 
 struct mem_cgroup;
 struct obj_cgroup;
@@ -1952,4 +1954,20 @@ static inline void mem_cgroup_exit_user_fault(void)
 
 #endif /* CONFIG_MEMCG_V1 */
 
+extern int _obj_cgroup_move(struct kmem_cache *s, struct slab *slab,
+					void **p, int objects, struct obj_cgroup *to);
+extern int kmem_cache_move(struct kmem_cache *s, void *addr,
+					 int objects, struct mem_cgroup *to);
+extern int obj_cgroup_move(void *addr, struct mem_cgroup *from, struct mem_cgroup *to);
+extern int kmem_folio_move(struct folio *folio,  struct mem_cgroup *from, struct mem_cgroup *to);
+
+extern struct mem_cgroup *get_cg_from_cgrp(struct cgroup *cgrp, const char *subsys_name);
+
+#define RECYCLE_MEM_MAX (1 << 15)
+extern long recycle_max_limit;
+extern int page_set_balloon_max(struct mem_cgroup *memcg);
+extern int kmem_cgroup_move(void *addr, struct mem_cgroup *from, struct mem_cgroup *to);
+extern unsigned long caculate_space(void *addr);
+int check_balloon_limits(unsigned long mem_delta, struct mem_cgroup *memcg_balloon);
+
 #endif /* _LINUX_MEMCONTROL_H */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ca5f0dda733b..00c0f96f64b9 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2092,6 +2092,9 @@ struct net_device {
 	char			name[IFNAMSIZ];
 	struct netdev_name_node	*name_node;
 	struct dev_ifalias	__rcu *ifalias;
+
+	struct cgroup *cgroup;
+	unsigned int residual_time;
 	/*
 	 *	I/O specific fields
 	 *	FIXME: Merge these and struct ifmap into one
@@ -5229,3 +5232,4 @@ extern struct net_device *blackhole_netdev;
 #define DEV_STATS_READ(DEV, FIELD) atomic_long_read(&(DEV)->stats.__##FIELD)
 
 #endif	/* _LINUX_NETDEVICE_H */
+extern int net_device_move_check(struct net *ns, struct cgroup *cgrp);
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index f9f9931e02d6..13e29f1d814f 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -124,3 +124,4 @@ static inline bool task_is_in_init_pid_ns(struct task_struct *tsk)
 }
 
 #endif /* _LINUX_PID_NS_H */
+extern void check_pid_zombie(struct pid_namespace *pid_ns, struct cgroup *cgrp);
diff --git a/include/linux/sem.h b/include/linux/sem.h
index c4deefe42aeb..e002b248cdf9 100644
--- a/include/linux/sem.h
+++ b/include/linux/sem.h
@@ -7,11 +7,13 @@
 
 struct task_struct;
 
+struct sem_array;
 #ifdef CONFIG_SYSVIPC
 
 extern int copy_semundo(unsigned long clone_flags, struct task_struct *tsk);
 extern void exit_sem(struct task_struct *tsk);
 
+extern struct sem_array *find_sem_from_perm(struct kern_ipc_perm *perm);
 #else
 
 static inline int copy_semundo(unsigned long clone_flags, struct task_struct *tsk)
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index a44f262a7384..1c648a808fa1 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -601,3 +601,5 @@ static inline void neigh_update_is_router(struct neighbour *neigh, u32 flags,
 	}
 }
 #endif
+extern int neigh_move(struct neigh_parms *neigh_p, struct mem_cgroup *from, struct mem_cgroup *to);
+extern unsigned long neigh_size(struct neigh_parms *neigh_p);
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index e67b483cc8bb..297c1c9869f3 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -556,3 +556,4 @@ static inline void net_ns_init(void) {}
 #endif
 
 #endif /* __NET_NET_NAMESPACE_H */
+extern void net_device_free(struct net *ns, unsigned int limit);
diff --git a/ipc/msg.c b/ipc/msg.c
index fd08b3cb36d7..c3ef9c550ec9 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -40,6 +40,7 @@
 #include <linux/ipc_namespace.h>
 #include <linux/rhashtable.h>
 #include <linux/percpu_counter.h>
+#include <linux/memcontrol.h>
 
 #include <asm/current.h>
 #include <linux/uaccess.h>
@@ -98,6 +99,8 @@ struct msg_sender {
 #define SEARCH_NUMBER		5
 
 #define msg_ids(ns)	((ns)->ids[IPC_MSG_IDS])
+struct msg_queue *find_msq_from_perm(struct kern_ipc_perm *perm);
+static int ipc_msq_move(struct msg_queue *msq, struct mem_cgroup *from, struct mem_cgroup *to);
 
 static inline struct msg_queue *msq_obtain_object(struct ipc_namespace *ns, int id)
 {
@@ -295,9 +298,67 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
 	ipc_rcu_putref(&msq->q_perm, msg_rcu_free);
 }
 
+static int ipc_msq_size(struct msg_queue *msq)
+{
+	return caculate_space(msq);
+}
+
+static void msg_tag(struct kern_ipc_perm *ipcp, struct nsproxy *ns)
+{
+	struct msg_queue *msq;
+	struct mem_cgroup *memcg_owner, *memcg_recycle;
+	struct cgroup *cgrp_owner, *balloon_cgrp, *shared_cgrp;
+	unsigned int balloon_index;
+
+	memcg_owner = mem_cgroup_from_task(current);
+	if (!memcg_owner)
+		return;
+
+	cgrp_owner = memcg_owner->css.cgroup;
+	if (!cgrp_owner)
+		return;
+
+	shared_cgrp = find_shared_cg(ns->ipc_ns, NULL, NULL, cgrp_owner);
+	cg_ns_insert(cgrp_owner, ns->ipc_ns, NULL, NULL);
+
+	if (!ipcp)
+		return;
+	if (!shared_cgrp) {
+		balloon_index = find_balloon_index_from_cgroup(cgrp_owner);
+		if (balloon_index > BALLOON_CGROUP_HASH_COUNT) {
+			ipcp->cgroup = cgrp_owner;
+			ipcp->residual_time = 0;
+			return;
+		}
+		insert_cgroup_to_balloon(&balloon_to_cgroup[balloon_index], cgrp_owner, NULL);
+	} else {
+		balloon_cgrp = find_balloon_from_cgroup(shared_cgrp);
+		balloon_index = find_balloon_index_from_cgroup(shared_cgrp);
+		insert_cgroup_to_balloon(&balloon_to_cgroup[balloon_index],
+						cgrp_owner, balloon_cgrp);
+
+		if (ipcp->cgroup && balloon_cgrp && ipcp->cgroup == balloon_cgrp) {
+			msq = find_msq_from_perm(ipcp);
+			if (!msq)
+				return;
+			memcg_recycle = get_cg_from_cgrp(balloon_cgrp, "memory");
+			ipc_msq_move(msq, memcg_recycle, memcg_owner);
+		}
+	}
+	ipcp->cgroup = cgrp_owner;
+	ipcp->residual_time = 0;
+}
+
+extern void ipc_msq_free(struct ipc_namespace *ns, unsigned int limit)
+{
+	free_recycle_ipcs(ns, &msg_ids(ns), freeque, limit);
+}
+
 long ksys_msgget(key_t key, int msgflg)
 {
 	struct ipc_namespace *ns;
+	int err;
+	struct kern_ipc_perm *ipcp;
 	static const struct ipc_ops msg_ops = {
 		.getnew = newque,
 		.associate = security_msg_queue_associate,
@@ -309,7 +370,20 @@ long ksys_msgget(key_t key, int msgflg)
 	msg_params.key = key;
 	msg_params.flg = msgflg;
 
-	return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params);
+	err = ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params);
+	if (err >= 0) {
+		down_write(&msg_ids(ns).rwsem);
+		ipcp = ipc_findkey(&msg_ids(ns), key);
+
+		msg_tag(ipcp, current->nsproxy);
+		if (!ipcp)
+			goto no_lock;
+		ipc_unlock(ipcp);
+
+no_lock:
+		up_write(&msg_ids(ns).rwsem);
+	}
+	return err;
 }
 
 SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg)
@@ -1374,3 +1448,106 @@ void __init msg_init(void)
 				"       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n",
 				IPC_MSG_IDS, sysvipc_msg_proc_show);
 }
+
+struct msg_queue *find_msq_from_perm(struct kern_ipc_perm *perm)
+{
+	struct msg_queue *msq = container_of(perm, struct msg_queue, q_perm);
+	return msq;
+}
+
+static int ipc_msq_move(struct msg_queue *msq, struct mem_cgroup *from, struct mem_cgroup *to)
+{
+	struct msg_msg *msg, *t;
+	int err = 0;
+
+	list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) {
+		err = ipc_msg_move(msg, from, to);
+		if (err < 0)
+			return err;
+	}
+	err = kmem_cgroup_move(msq, from, to);
+	return err;
+}
+
+int ipc_msq_move_check(struct ipc_namespace *ns, struct cgroup *cgrp)
+{
+	struct ipc_ids *ids;
+	struct kern_ipc_perm *perm;
+	int next_id, i;
+	int total, in_use;
+	struct msg_queue *msq;
+	unsigned int balloon_index;
+	struct cgroup *balloon_cgroup;
+	unsigned long mem_volume;
+	struct mem_cgroup *memcg_to, *memcg_from = get_cg_from_cgrp(cgrp, "memory");
+
+	ids = &msg_ids(ns);
+	if (ids == NULL)
+		return 0;
+
+	if (memcg_from == NULL)
+		return 0;
+
+	in_use = ids->in_use;
+	balloon_cgroup = find_balloon_from_cgroup(cgrp);
+
+	for (total = 0, next_id = 0; total < in_use; next_id++) {
+		perm = idr_find(&ids->ipcs_idr, next_id);
+		if (perm == NULL)
+			continue;
+
+		msq = find_msq_from_perm(perm);
+		if (msq == NULL)
+			continue;
+
+		if (perm->cgroup == NULL) {
+			down_write(&msg_ids(ns).rwsem);
+			rcu_read_lock();
+			ipc_lock_object(perm);
+			freeque(ns, perm);
+			up_write(&msg_ids(ns).rwsem);
+			total++;
+			continue;
+		}
+
+		if (balloon_cgroup && perm->cgroup == balloon_cgroup)
+			perm->residual_time++;
+
+		if (perm->cgroup == cgrp) {
+			if (!balloon_cgroup) {
+				balloon_index = find_balloon_index_from_cgroup(cgrp);
+				balloon_cgroup = balloon_cgroup_create(balloon_index);
+				init_balloon_cgroup_to_balloon(&balloon_to_cgroup[balloon_index],
+								balloon_cgroup);
+				memcg_to = get_cg_from_cgrp(balloon_cgroup, "memory");
+				page_set_balloon_max(memcg_to);
+			}
+			memcg_to = get_cg_from_cgrp(balloon_cgroup, "memory");
+			if (!memcg_to)
+				return 0;
+
+			mem_volume = ipc_msq_size(msq);
+			if (check_balloon_limits(mem_volume, memcg_to)) {
+				for (i = 5; i > 0; i--) {
+					free_oldest_volume(cgrp, i);
+					cond_resched();
+					if (!check_balloon_limits(mem_volume, memcg_to))
+						goto move_resources;
+				}
+				down_write(&msg_ids(ns).rwsem);
+				rcu_read_lock();
+				ipc_lock_object(perm);
+				freeque(ns, perm);
+				up_write(&msg_ids(ns).rwsem);
+				total++;
+				continue;
+			}
+move_resources:
+			perm->cgroup = balloon_cgroup;
+			perm->residual_time = 1;
+			ipc_msq_move(msq, memcg_from, memcg_to);
+		}
+		total++;
+	}
+	return 0;
+}
diff --git a/ipc/msgutil.c b/ipc/msgutil.c
index c7be0c792647..459a9610e9ea 100644
--- a/ipc/msgutil.c
+++ b/ipc/msgutil.c
@@ -15,6 +15,7 @@
 #include <linux/proc_ns.h>
 #include <linux/uaccess.h>
 #include <linux/sched.h>
+#include <linux/memcontrol.h>
 
 #include "util.h"
 
@@ -193,3 +194,24 @@ void free_msg(struct msg_msg *msg)
 		seg = tmp;
 	}
 }
+
+extern int ipc_msg_move(struct msg_msg *msg, struct mem_cgroup *from, struct mem_cgroup *to)
+{
+	struct msg_msgseg *seg;
+	int err;
+
+	seg = msg->next;
+	err = kmem_cgroup_move(msg, from, to);
+	if (err < 0)
+		return err;
+	while (seg != NULL) {
+		struct msg_msgseg *tmp = seg->next;
+
+		cond_resched();
+		err = kmem_cgroup_move(seg, from, to);
+		if (err < 0)
+			return err;
+		seg = tmp;
+	}
+	return err;
+}
diff --git a/ipc/namespace.c b/ipc/namespace.c
index 6ecc30effd3e..d8421bcc8f08 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -16,6 +16,8 @@
 #include <linux/user_namespace.h>
 #include <linux/proc_ns.h>
 #include <linux/sched/task.h>
+#include <linux/cgroup-defs.h>
+#include <linux/cgroup.h>
 
 #include "util.h"
 
@@ -256,3 +258,28 @@ const struct proc_ns_operations ipcns_operations = {
 	.install	= ipcns_install,
 	.owner		= ipcns_owner,
 };
+
+void free_recycle_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
+	       void (*free)(struct ipc_namespace *, struct kern_ipc_perm *), unsigned int limit)
+{
+	struct kern_ipc_perm *perm;
+	int next_id;
+	int total, in_use;
+
+	down_write(&ids->rwsem);
+
+	in_use = ids->in_use;
+
+	for (total = 0, next_id = 0; total < in_use; next_id++) {
+		perm = idr_find(&ids->ipcs_idr, next_id);
+		if (perm == NULL)
+			continue;
+		if (perm->residual_time >= limit) {
+			rcu_read_lock();
+			ipc_lock_object(perm);
+			free(ns, perm);
+		}
+		total++;
+	}
+	up_write(&ids->rwsem);
+}
diff --git a/ipc/sem.c b/ipc/sem.c
index a39cdc7bf88f..32bae46952ca 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -87,6 +87,9 @@
 #include <linux/sched/wake_q.h>
 #include <linux/nospec.h>
 #include <linux/rhashtable.h>
+#include <linux/cgroup-defs.h>
+#include <linux/memcontrol.h>
+#include <linux/page_counter.h>
 
 #include <linux/uaccess.h>
 #include "util.h"
@@ -599,9 +602,171 @@ static int sem_more_checks(struct kern_ipc_perm *ipcp, struct ipc_params *params
 	return 0;
 }
 
+struct sem_array *find_sem_from_perm(struct kern_ipc_perm *perm)
+{
+	struct sem_array *sma = container_of(perm, struct sem_array, sem_perm);
+	return sma;
+}
+
+static unsigned long ipc_sem_size(struct sem_array *sma)
+{
+	return caculate_space(sma);
+}
+
+static int ipc_sem_move(struct sem_array *sma, struct mem_cgroup *from, struct mem_cgroup *to)
+{
+	return obj_cgroup_move(sma, from, to);
+}
+
+void ipc_sem_free(struct ipc_namespace *ns, unsigned int limit)
+{
+	free_recycle_ipcs(ns, &sem_ids(ns), freeary, limit);
+}
+
+int ipc_sem_move_check(struct ipc_namespace *ns, struct cgroup *cgrp)
+{
+	struct ipc_ids *ids;
+	struct kern_ipc_perm *perm;
+	int next_id, i;
+	int total, in_use;
+	struct sem_array *sma;
+	unsigned long mem_volume;
+	unsigned int balloon_index;
+	struct cgroup *balloon_cgroup;
+	struct mem_cgroup *memcg_to, *memcg_from = get_cg_from_cgrp(cgrp, "memory");
+
+	ids =  &sem_ids(ns);
+
+	if (ids == NULL)
+		return 0;
+
+	if (memcg_from == NULL)
+		return 0;
+
+	in_use = ids->in_use;
+	balloon_cgroup = find_balloon_from_cgroup(cgrp);
+
+	for (total = 0, next_id = 0; total < in_use; next_id++) {
+		perm = idr_find(&ids->ipcs_idr, next_id);
+		if (perm == NULL)
+			continue;
+
+		sma = find_sem_from_perm(perm);
+
+		if (sma == NULL)
+			continue;
+
+
+		if (perm->cgroup == NULL) {
+			down_write(&sem_ids(ns).rwsem);
+			rcu_read_lock();
+			ipc_lock_object(perm);
+			freeary(ns, perm);
+			up_write(&sem_ids(ns).rwsem);
+			total++;
+			continue;
+		}
+		if (balloon_cgroup && perm->cgroup == balloon_cgroup)
+			perm->residual_time++;
+
+		if (perm->cgroup == cgrp) { //belongs to the exiting cgorup.
+			if (!balloon_cgroup) {
+				balloon_index = find_balloon_index_from_cgroup(cgrp);
+				balloon_cgroup = balloon_cgroup_create(balloon_index);
+				if (balloon_cgroup == NULL)
+					return 0;
+
+				init_balloon_cgroup_to_balloon(&balloon_to_cgroup[balloon_index],
+							balloon_cgroup);
+				memcg_to = get_cg_from_cgrp(balloon_cgroup, "memory");
+				if (memcg_to == NULL)
+					return 0;
+
+				page_set_balloon_max(memcg_to);
+			}
+			memcg_to = get_cg_from_cgrp(balloon_cgroup, "memory");
+			if (!memcg_to)
+				return 0;
+
+			mem_volume = ipc_sem_size(sma);
+			if (check_balloon_limits(mem_volume, memcg_to)) {
+				for (i = 5; i > 0; i--) {
+					free_oldest_volume(cgrp, i);
+					cond_resched();
+					if (!check_balloon_limits(mem_volume, memcg_to))
+						goto move_resources;
+				}
+				down_write(&sem_ids(ns).rwsem);
+				rcu_read_lock();
+				ipc_lock_object(perm);
+				freeary(ns, perm);
+				up_write(&sem_ids(ns).rwsem);
+				total++;
+				continue;
+			}
+move_resources:
+			perm->cgroup = balloon_cgroup;
+			perm->residual_time = 1;
+			ipc_sem_move(sma, memcg_from, memcg_to);
+		}
+		total++;
+	}
+	return 0;
+}
+
+
+static void sem_tag(struct kern_ipc_perm *ipcp, struct nsproxy *ns)
+{
+	struct sem_array *sma;
+	struct mem_cgroup *memcg_owner, *memcg_recycle;
+	struct cgroup *cgrp_owner, *balloon_cgrp, *shared_cgrp;
+	unsigned int balloon_index;
+
+	memcg_owner = mem_cgroup_from_task(current);
+	if (!memcg_owner)
+		return;
+
+	cgrp_owner = memcg_owner->css.cgroup;
+	if (!cgrp_owner)
+		return;
+
+	shared_cgrp = find_shared_cg(ns->ipc_ns, NULL, NULL, cgrp_owner);
+	cg_ns_insert(cgrp_owner, ns->ipc_ns, NULL, NULL);
+
+	if (!ipcp)
+		return;
+
+	if (!shared_cgrp) {
+		balloon_index = find_balloon_index_from_cgroup(cgrp_owner);
+
+		if (balloon_index > BALLOON_CGROUP_HASH_COUNT) {
+			ipcp->cgroup = cgrp_owner;
+			ipcp->residual_time = 0;
+			return;
+		}
+		insert_cgroup_to_balloon(&balloon_to_cgroup[balloon_index], cgrp_owner, NULL);
+	} else {
+		balloon_cgrp = find_balloon_from_cgroup(shared_cgrp);
+		balloon_index = find_balloon_index_from_cgroup(shared_cgrp);
+		insert_cgroup_to_balloon(&balloon_to_cgroup[balloon_index], cgrp_owner,
+						balloon_cgrp);
+		if (ipcp->cgroup && balloon_cgrp && ipcp->cgroup == balloon_cgrp) {
+			sma = find_sem_from_perm(ipcp);
+			if (!sma)
+				return;
+			memcg_recycle = get_cg_from_cgrp(balloon_cgrp, "memory");
+			ipc_sem_move(sma, memcg_recycle, memcg_owner);
+		}
+	}
+	ipcp->cgroup = cgrp_owner;
+	ipcp->residual_time = 0;
+}
+
 long ksys_semget(key_t key, int nsems, int semflg)
 {
 	struct ipc_namespace *ns;
+	int err;
+	struct kern_ipc_perm *ipcp;
 	static const struct ipc_ops sem_ops = {
 		.getnew = newary,
 		.associate = security_sem_associate,
@@ -618,7 +783,20 @@ long ksys_semget(key_t key, int nsems, int semflg)
 	sem_params.flg = semflg;
 	sem_params.u.nsems = nsems;
 
-	return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params);
+	err = ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params);
+	if (err >= 0) {
+		down_write(&sem_ids(ns).rwsem);
+		ipcp = ipc_findkey(&sem_ids(ns), key);
+
+		sem_tag(ipcp, current->nsproxy);
+
+		if (!ipcp)
+			goto no_lock;
+		ipc_unlock(ipcp);
+no_lock:
+		up_write(&sem_ids(ns).rwsem);
+	}
+	return err;
 }
 
 SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg)
diff --git a/ipc/shm.c b/ipc/shm.c
index 99564c870084..315601fdd0ea 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -45,6 +45,7 @@
 #include <linux/mount.h>
 #include <linux/ipc_namespace.h>
 #include <linux/rhashtable.h>
+#include <linux/memcontrol.h>
 
 #include <linux/uaccess.h>
 
@@ -102,6 +103,7 @@ static int newseg(struct ipc_namespace *, struct ipc_params *);
 static void shm_open(struct vm_area_struct *vma);
 static void shm_close(struct vm_area_struct *vma);
 static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp);
+static int ipc_shm_move(struct shmid_kernel *shp, struct mem_cgroup *from, struct mem_cgroup *to);
 #ifdef CONFIG_PROC_FS
 static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
 #endif
@@ -820,9 +822,90 @@ static int shm_more_checks(struct kern_ipc_perm *ipcp, struct ipc_params *params
 	return 0;
 }
 
+static struct shmid_kernel *find_shp_from_perm(struct kern_ipc_perm *perm)
+{
+	struct shmid_kernel *shp = container_of(perm, struct shmid_kernel, shm_perm);
+	return shp;
+}
+
+static unsigned long ipc_shm_size(struct shmid_kernel *shp)
+{
+	unsigned long space = 0;
+	struct file *file;
+	struct inode *inode;
+
+	space += caculate_space(shp);
+
+	file = shp->shm_file;
+	if (!file)
+		return space;
+
+	inode = file->f_inode;
+	if (!inode)
+		return space;
+
+	space += shm_total_pages(inode) * PAGE_SIZE;
+
+	return space;
+}
+
+void shm_tag(struct kern_ipc_perm *ipcp, struct nsproxy *ns)
+{
+	struct shmid_kernel *shp;
+	struct mem_cgroup *memcg_owner, *memcg_recycle;
+	struct cgroup *cgrp_owner, *balloon_cgrp, *shared_cgrp;
+	unsigned int balloon_index;
+
+	memcg_owner = mem_cgroup_from_task(current);
+	if (!memcg_owner)
+		return;
+
+	cgrp_owner = memcg_owner->css.cgroup;
+	if (!cgrp_owner)
+		return;
+
+	shared_cgrp = find_shared_cg(ns->ipc_ns, NULL, NULL, cgrp_owner);
+	cg_ns_insert(cgrp_owner, ns->ipc_ns, NULL, NULL);
+
+	if (!ipcp)
+		return;
+	if (!shared_cgrp) {
+		balloon_index = find_balloon_index_from_cgroup(cgrp_owner);
+		if (balloon_index > BALLOON_CGROUP_HASH_COUNT) {
+			ipcp->cgroup = cgrp_owner;
+			ipcp->residual_time = 0;
+			return;
+		}
+		insert_cgroup_to_balloon(&balloon_to_cgroup[balloon_index], cgrp_owner, NULL);
+	} else {
+		balloon_cgrp = find_balloon_from_cgroup(shared_cgrp);
+		balloon_index = find_balloon_index_from_cgroup(shared_cgrp);
+		insert_cgroup_to_balloon(&balloon_to_cgroup[balloon_index], cgrp_owner,
+					balloon_cgrp);
+
+		if (ipcp->cgroup && balloon_cgrp && ipcp->cgroup == balloon_cgrp) {
+			shp = find_shp_from_perm(ipcp);
+			if (!shp)
+				return;
+			memcg_recycle = get_cg_from_cgrp(balloon_cgrp, "memory");
+			ipc_shm_move(shp, memcg_recycle, memcg_owner);
+		}
+	}
+	ipcp->cgroup = cgrp_owner;
+	ipcp->residual_time = 0;
+}
+
+extern void ipc_shm_free(struct ipc_namespace *ns, unsigned int limit)
+{
+	free_recycle_ipcs(ns, &shm_ids(ns), do_shm_rmid, limit);
+}
+
 long ksys_shmget(key_t key, size_t size, int shmflg)
 {
 	struct ipc_namespace *ns;
+	int err;
+	struct kern_ipc_perm *ipcp;
+
 	static const struct ipc_ops shm_ops = {
 		.getnew = newseg,
 		.associate = security_shm_associate,
@@ -836,7 +919,19 @@ long ksys_shmget(key_t key, size_t size, int shmflg)
 	shm_params.flg = shmflg;
 	shm_params.u.size = size;
 
-	return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params);
+	err = ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params);
+	if (err >= 0) {
+		down_write(&shm_ids(ns).rwsem);
+		ipcp = ipc_findkey(&shm_ids(ns), key);
+
+		shm_tag(ipcp, current->nsproxy);
+		if (!ipcp)
+			goto no_lock;
+		ipc_unlock(ipcp);
+no_lock:
+		up_write(&shm_ids(ns).rwsem);
+	}
+	return err;
 }
 
 SYSCALL_DEFINE3(shmget, key_t, key, size_t, size, int, shmflg)
@@ -1873,3 +1968,108 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
 	return 0;
 }
 #endif
+
+static int ipc_shm_move(struct shmid_kernel *shp, struct mem_cgroup *from, struct mem_cgroup *to)
+{
+	int err;
+	struct file *file;
+	struct inode *inode;
+
+	file = shp->shm_file;
+	if (!file)
+		return 0;
+
+	inode = file->f_inode;
+	if (!inode)
+		return 0;
+
+	err = obj_cgroup_move(shp, from, to);
+	err = ipc_shm_folio_move(inode, from, to);
+	return err;
+}
+
+int ipc_shm_move_check(struct ipc_namespace *ns, struct cgroup *cgrp)
+{
+	struct ipc_ids *ids;
+	struct kern_ipc_perm *perm;
+	int next_id, i;
+	int total, in_use;
+	struct shmid_kernel *shp;
+	unsigned long mem_volume;
+	unsigned int balloon_index;
+	struct cgroup *balloon_cgroup;
+	struct mem_cgroup *memcg_to, *memcg_from = get_cg_from_cgrp(cgrp, "memory");
+
+	ids =  &shm_ids(ns);
+
+	if (ids == NULL)
+		return 0;
+
+	if (memcg_from == NULL)
+		return 0;
+
+	in_use = ids->in_use;
+	balloon_cgroup = find_balloon_from_cgroup(cgrp);
+
+	for (total = 0, next_id = 0; total < in_use; next_id++) {
+		perm = idr_find(&ids->ipcs_idr, next_id);
+		if (perm == NULL) {
+			// total++;
+			continue;
+		}
+
+		shp = find_shp_from_perm(perm);
+		if (shp == NULL) {
+			// total++;
+			continue;
+		}
+		if (perm->cgroup == NULL) {
+			down_write(&shm_ids(ns).rwsem);
+			rcu_read_lock();
+			ipc_lock_object(perm);
+			do_shm_rmid(ns, perm);
+			up_write(&shm_ids(ns).rwsem);
+			total++;
+			continue;
+		}
+		if (balloon_cgroup && perm->cgroup == balloon_cgroup)
+			perm->residual_time++;
+
+		if (perm->cgroup == cgrp) {
+			if (!balloon_cgroup) {
+				balloon_index = find_balloon_index_from_cgroup(cgrp);
+				balloon_cgroup = balloon_cgroup_create(balloon_index);
+				init_balloon_cgroup_to_balloon(&balloon_to_cgroup[balloon_index],
+							balloon_cgroup);
+				memcg_to = get_cg_from_cgrp(balloon_cgroup, "memory");
+				page_set_balloon_max(memcg_to);
+			}
+			memcg_to = get_cg_from_cgrp(balloon_cgroup, "memory");
+			if (!memcg_to)
+				return 0;
+
+			mem_volume = ipc_shm_size(shp);
+			if (check_balloon_limits(mem_volume, memcg_to)) {
+				for (i = 5; i > 0; i--) {
+					free_oldest_volume(cgrp, i);
+					cond_resched();
+					if (!check_balloon_limits(mem_volume, memcg_to))
+						goto move_resources;
+				}
+				down_write(&shm_ids(ns).rwsem);
+				rcu_read_lock();
+				ipc_lock_object(perm);
+				do_shm_rmid(ns, perm);
+				up_write(&shm_ids(ns).rwsem);
+				total++;
+				continue;
+			}
+move_resources:
+			perm->cgroup = balloon_cgroup;
+			perm->residual_time = 1;
+			ipc_shm_move(shp, memcg_from, memcg_to);
+		}
+		total++;
+	}
+	return 0;
+}
diff --git a/ipc/util.c b/ipc/util.c
index 05cb9de66735..0701fa10505f 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -169,7 +169,7 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
  *
  * Called with writer ipc_ids.rwsem held.
  */
-static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
+struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
 {
 	struct kern_ipc_perm *ipcp;
 
diff --git a/ipc/util.h b/ipc/util.h
index a55d6cebe6d3..46db525455c9 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -244,6 +244,7 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
 			const struct ipc_ops *ops, struct ipc_params *params);
 void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
 		void (*free)(struct ipc_namespace *, struct kern_ipc_perm *));
+extern struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key);
 
 static inline int sem_check_semmni(struct ipc_namespace *ns) {
 	/*
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 2032dc501427..33a20e5562b6 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -60,6 +60,22 @@
 #include <linux/sched/deadline.h>
 #include <linux/psi.h>
 #include <net/sock.h>
+#include <linux/cgroup-defs.h>
+#include <linux/memcontrol.h>
+#include <linux/ipc_namespace.h>
+#include <linux/slab.h>
+#include <linux/sem.h>
+#include <linux/shm.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/syscalls.h>
+#include <linux/security.h>
+#include <linux/pid_namespace.h>
+#include <linux/namei.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/percpu_counter.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/cgroup.h>
@@ -5938,6 +5954,385 @@ static void kill_css(struct cgroup_subsys_state *css)
 	percpu_ref_kill_and_confirm(&css->refcnt, css_killed_ref_fn);
 }
 
+struct mem_cgroup *get_cg_from_cgrp(struct cgroup *cgrp, const char *subsys_name)
+{
+	struct cgroup_subsys_state *css;
+	struct mem_cgroup *memcg;
+
+	if (!cgrp)
+		return NULL;
+
+	for (int i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+		if (strcmp(subsys_name, cgroup_subsys_name[i]) == 0) {
+			css = cgrp->subsys[i];
+			break;
+		}
+	}
+	memcg = mem_cgroup_from_css(css);
+	return memcg;
+}
+
+static struct hlist_head *call_hash_cg_ns(struct cgroup *cgroup)
+{
+	unsigned int val = 0;
+	unsigned long location = (unsigned long)cgroup;
+
+	val = location % CGROUP_NS_HASH_COUNT;
+	return &cg_ns_map[val];
+}
+
+static int init_hash_cg_ns(void)
+{
+	int i = 0;
+
+	cg_ns_map = kmalloc(sizeof(struct hlist_head) * CGROUP_NS_HASH_COUNT, GFP_ATOMIC);
+	if (!cg_ns_map)
+		return -1;
+
+	for (i = 0; i < CGROUP_NS_HASH_COUNT; i++)
+		INIT_HLIST_HEAD(&cg_ns_map[i]);
+
+	return 0;
+}
+EXPORT_SYMBOL(cg_ns_map);
+
+int cg_ns_insert(struct cgroup *cgroup, struct ipc_namespace *ipc_ns,
+	struct net *net_ns, struct pid_namespace *pid_ns)
+{
+	struct hlist_head *hash_bucket = NULL;
+	struct cgroup_ns_entry *pNode = NULL;
+
+	hash_bucket = call_hash_cg_ns(cgroup);
+	if (!hash_bucket)
+		return -1;
+
+	hlist_for_each_entry(pNode, hash_bucket, hnode) {
+		if (!pNode)
+			return -1;
+
+		if (pNode->cgroup == cgroup) {
+			if (ipc_ns && ipc_ns != pNode->ipc_ns)
+				pNode->ipc_ns = ipc_ns;
+
+			if (net_ns && net_ns != pNode->net_ns)
+				pNode->net_ns = net_ns;
+
+			if (pid_ns && pid_ns != pNode->pid_ns)
+				pNode->pid_ns = pid_ns;
+			return 0;
+		}
+	}
+
+	pNode = kmalloc(sizeof(struct cgroup_ns_entry), GFP_ATOMIC);
+	if (!pNode)
+		return -1;
+
+	INIT_HLIST_NODE(&pNode->hnode);
+
+	pNode->cgroup = cgroup;
+	pNode->net_ns = net_ns;
+	pNode->pid_ns = pid_ns;
+	pNode->ipc_ns = ipc_ns;
+
+	hlist_add_head(&pNode->hnode, hash_bucket);
+
+	return 0;
+}
+
+static struct ipc_namespace *find_ipc_ns_from_cg(struct cgroup *cgroup)
+{
+	struct hlist_head *hash_bucket = NULL;
+	struct cgroup_ns_entry *pNode = NULL;
+
+	hash_bucket = call_hash_cg_ns(cgroup);
+	if (hash_bucket == NULL)
+		return NULL;
+
+	hlist_for_each_entry(pNode, hash_bucket, hnode) {
+		if (pNode->cgroup == cgroup)
+			return pNode->ipc_ns;
+	}
+	return NULL;
+}
+
+static struct net *find_net_ns_from_cg(struct cgroup *cgroup)
+{
+	struct hlist_head *hash_bucket = NULL;
+	struct cgroup_ns_entry *pNode = NULL;
+
+	hash_bucket = call_hash_cg_ns(cgroup);
+	if (hash_bucket == NULL)
+		return NULL;
+
+	hlist_for_each_entry(pNode, hash_bucket, hnode) {
+		if (pNode->cgroup == cgroup)
+			return pNode->net_ns;
+	}
+	return NULL;
+}
+
+struct cgroup *find_shared_cg(struct ipc_namespace *ipc_ns, struct net *net_ns,
+		struct pid_namespace *pid_ns, const struct cgroup *cgroup)
+{
+	struct cgroup_ns_entry *pNode = NULL;
+	int i;
+
+	if (!cg_ns_map)
+		return NULL;
+
+	if (ipc_ns == &init_ipc_ns || net_ns ==  &init_net || pid_ns ==  &init_pid_ns)
+		return NULL;
+
+	for (i = 0; i < CGROUP_NS_HASH_COUNT; i++) {
+		hlist_for_each_entry(pNode, &cg_ns_map[i], hnode) {
+			if (!pNode)
+				return NULL;
+			if (ipc_ns) {
+				if (pNode->ipc_ns == ipc_ns && pNode->cgroup != cgroup)
+					return pNode->cgroup;
+			}
+
+			if (net_ns) {
+				if (pNode->net_ns == net_ns && pNode->cgroup != cgroup)
+					return pNode->cgroup;
+			}
+
+			if (pid_ns) {
+				if (pNode->pid_ns == pid_ns && pNode->cgroup != cgroup)
+					return pNode->cgroup;
+			}
+		}
+	}
+	return NULL;
+}
+
+int delete_cg_ns_node(struct hlist_head *head, struct cgroup *cgroup)
+{
+	struct cgroup_ns_entry *pNode = NULL;
+
+	if (!cg_ns_map)
+		return -1;
+
+	if (!head)
+		return -1;
+	hlist_for_each_entry(pNode, head, hnode) {
+		if (pNode->cgroup == cgroup) {
+			hlist_del(&pNode->hnode);
+			return 0;
+		}
+	}
+	return 0;
+}
+
+int init_hash_balloon_cg(void)
+{
+	int i = 0;
+
+	balloon_to_cgroup = kmalloc(sizeof(struct hlist_head) * BALLOON_CGROUP_HASH_COUNT,
+					GFP_ATOMIC);
+	if (balloon_to_cgroup == NULL)
+		return -1;
+
+	for (i = 0; i < BALLOON_CGROUP_HASH_COUNT; i++)
+		INIT_HLIST_HEAD(&balloon_to_cgroup[i]);
+
+	return 0;
+}
+EXPORT_SYMBOL(balloon_to_cgroup);
+
+unsigned int find_balloon_index_from_cgroup(struct cgroup *cgroup)
+{
+	struct hlist_node *first;
+	struct balloon_cgroup_entry *balloon_cg;
+	int i;
+
+	if (!balloon_to_cgroup)
+		return -1;
+
+	for (i = 0; i < BALLOON_CGROUP_HASH_COUNT; i++) {
+		first = (&balloon_to_cgroup[i])->first;
+		if (!first)
+			break;
+
+		hlist_for_each_entry(balloon_cg, &balloon_to_cgroup[i], hnode) {
+			if (balloon_cg->cgroup == cgroup)
+				return i;
+		}
+	}
+	return i;
+}
+
+struct cgroup *find_balloon_from_cgroup(struct cgroup *cgroup)
+{
+	struct hlist_node *first;
+	struct balloon_cgroup_entry *balloon_cg;
+	int i;
+
+	if (!balloon_to_cgroup)
+		return NULL;
+
+	for (i = 0; i < BALLOON_CGROUP_HASH_COUNT; i++) {
+		first = (&balloon_to_cgroup[i])->first;
+		if (!first)
+			break;
+
+		hlist_for_each_entry(balloon_cg, &balloon_to_cgroup[i], hnode) {
+			if (balloon_cg->cgroup == cgroup)
+				return balloon_cg->balloon_cgroup;
+		}
+	}
+	return NULL;
+}
+
+int insert_cgroup_to_balloon(struct hlist_head *head, struct cgroup *cgroup,
+		struct cgroup *balloon_cgroup)
+{
+	struct balloon_cgroup_entry *pNode;
+
+	hlist_for_each_entry(pNode, head, hnode) {
+		if (!pNode)
+			continue;
+
+		if (pNode->cgroup == cgroup)
+			return 0;
+	}
+	pNode = kmalloc(sizeof(struct balloon_cgroup_entry), GFP_ATOMIC);
+	if (pNode == NULL)
+		return -1;
+
+	INIT_HLIST_NODE(&pNode->hnode);
+	pNode->cgroup = cgroup;
+	pNode->balloon_cgroup = balloon_cgroup;
+	hlist_add_head(&pNode->hnode, head);
+
+	return 0;
+}
+
+int delete_balloon_cgroup_node(struct hlist_head *head, struct cgroup *cgroup)
+{
+	struct balloon_cgroup_entry *pNode;
+
+	hlist_for_each_entry(pNode, head, hnode) {
+		if (!pNode)
+			continue;
+
+		if (pNode->cgroup == cgroup) {
+			hlist_del(&pNode->hnode);
+			return 0;
+		}
+	}
+	return 0;
+}
+
+int init_balloon_cgroup_to_balloon(struct hlist_head *head, struct cgroup *balloon_cgroup)
+{
+	struct balloon_cgroup_entry *pNode;
+
+	if (!head)
+		return -1;
+	hlist_for_each_entry(pNode, head, hnode) {
+		pNode->balloon_cgroup  = balloon_cgroup;
+	}
+	return 0;
+}
+
+static int memcg_ipc_net_pid_check(struct cgroup *cgrp)
+{
+	struct ipc_namespace *ipc_ns;
+	struct net *net_ns;
+	struct pid_namespace *pid_ns;
+	struct hlist_head *hash_bucket;
+	struct cgroup_ns_entry *pNode;
+	struct task_struct *tmp, *reaper, *pos;
+	struct cgroup *to;
+	int balloon_index;
+
+	hash_bucket = call_hash_cg_ns(cgrp);
+	if (!hash_bucket)
+		return 0;
+
+	hlist_for_each_entry(pNode, hash_bucket, hnode) {
+		if (!pNode)
+			continue;
+
+		if (pNode->cgroup != cgrp)
+			continue;
+
+		ipc_ns = pNode->ipc_ns;
+		net_ns = pNode->net_ns;
+		pid_ns = pNode->pid_ns;
+
+		if (ipc_ns) {
+			if (ipc_ns->used_sems != 0)
+				ipc_sem_move_check(ipc_ns, cgrp);
+
+			if (ipc_ns->shm_tot != 0)
+				ipc_shm_move_check(ipc_ns, cgrp);
+
+			ipc_msq_move_check(ipc_ns, cgrp);
+		}
+		if (net_ns) {
+			if (!list_empty(&net_ns->dev_base_head))
+				net_device_move_check(net_ns, cgrp);
+		}
+
+		if (pid_ns && pid_ns != &init_pid_ns) {
+			reaper = pid_ns->child_reaper;
+
+			if (!reaper)
+				break;
+
+			if (list_empty(&reaper->children))
+				break;
+
+			list_for_each_entry_safe(pos, tmp, &reaper->children, sibling) {
+				if (!pos)
+					continue;
+				to = task_cgroup(pos, pids_cgrp_id);
+				if (pos->exit_state == EXIT_ZOMBIE && to == cgrp)
+					release_task(pos);
+			}
+		}
+		break;
+	}
+	delete_cg_ns_node(hash_bucket, cgrp);
+	balloon_index = find_balloon_index_from_cgroup(cgrp);
+	delete_balloon_cgroup_node(&balloon_to_cgroup[balloon_index], cgrp);
+	return 0;
+}
+
+static void ipc_residual_clear(struct ipc_namespace *ipc_ns, unsigned int limit)
+{
+	if (ipc_ns->used_sems != 0)
+		ipc_sem_free(ipc_ns, limit);
+
+	if (ipc_ns->shm_tot != 0)
+		ipc_shm_free(ipc_ns, limit);
+
+	ipc_msq_free(ipc_ns, limit);
+}
+
+static void net_residual_clear(struct net *net_ns, unsigned int limit)
+{
+	net_device_free(net_ns, limit);
+}
+
+extern int free_oldest_volume(struct cgroup *target_cgroup, unsigned int limit)
+{
+	struct ipc_namespace *ipc_ns;
+	struct net *net_ns;
+
+	ipc_ns = find_ipc_ns_from_cg(target_cgroup);
+	net_ns = find_net_ns_from_cg(target_cgroup);
+
+	if (ipc_ns)
+		ipc_residual_clear(ipc_ns, limit);
+
+	if (net_ns)
+		net_residual_clear(net_ns, limit);
+	return 0;
+}
+
 /**
  * cgroup_destroy_locked - the first stage of cgroup destruction
  * @cgrp: cgroup to be destroyed
@@ -6043,6 +6438,8 @@ int cgroup_rmdir(struct kernfs_node *kn)
 	if (!cgrp)
 		return 0;
 
+	memcg_ipc_net_pid_check(cgrp);
+
 	ret = cgroup_destroy_locked(cgrp);
 	if (!ret)
 		TRACE_CGROUP_PATH(rmdir, cgrp);
@@ -6058,6 +6455,105 @@ static struct kernfs_syscall_ops cgroup_kf_syscall_ops = {
 	.show_path		= cgroup_show_path,
 };
 
+struct cgroup *init_balloon;
+struct hlist_head *cg_ns_map;
+struct hlist_head *balloon_to_cgroup;
+
+struct cgroup *balloon_cgroup_create(unsigned int index)
+{
+	struct kernfs_node *balloon_root_kn;
+	char balloon_name[10];
+	struct cgroup *cgrp = ERR_PTR(-ENOENT);
+	struct cgroup *balloon_root_cgrp;
+	int ret;
+
+	balloon_root_cgrp = init_balloon;
+	if (!balloon_root_cgrp)
+		return NULL;
+
+	if (balloon_root_cgrp->subtree_control == 0) {
+		balloon_root_cgrp->subtree_control |= 16;
+		ret = cgroup_apply_control(balloon_root_cgrp);
+		cgroup_finalize_control(balloon_root_cgrp, ret);
+	}
+
+	balloon_root_kn = balloon_root_cgrp->kn;
+	if (!balloon_root_kn)
+		return NULL;
+
+	sprintf(balloon_name, "%u.service", index);
+
+	cgrp = cgroup_create(balloon_root_cgrp, balloon_name, 0x755);
+
+	if (!cgrp)
+		return NULL;
+	/*
+	 * This extra ref will be put in cgroup_free_fn() and guarantees
+	 * that @cgrp->kn is always accessible.
+	 */
+	kernfs_get(cgrp->kn);
+
+	ret = css_populate_dir(&cgrp->self);
+	if (ret)
+		goto out_destroy;
+
+	ret = cgroup_apply_control_enable(cgrp);
+
+	if (ret)
+		goto out_destroy;
+	/* let's create and online css's */
+	kernfs_activate(cgrp->kn);
+	ret = 0;
+
+	goto out_unlock;
+
+out_destroy:
+	cgroup_destroy_locked(cgrp);
+	return NULL;
+
+out_unlock:
+	return cgrp;
+}
+
+static void recycle_cgroup_create(void)
+{
+	struct kernfs_node *root_kn;
+	struct cgroup *cgrp = ERR_PTR(-ENOENT);
+	struct cgroup *root_cgrp;
+	int ret;
+
+	root_cgrp = current_cgns_cgroup_dfl();
+	root_kn = root_cgrp->kn;
+	cgrp = cgroup_create(root_cgrp, "balloon.slice", 0x0744);
+	/*
+	 * This extra ref will be put in cgroup_free_fn() and guarantees
+	 * that @cgrp->kn is always accessible.
+	 */
+	kernfs_get(cgrp->kn);
+
+	ret = css_populate_dir(&cgrp->self);
+	if (ret)
+		goto out_destroy;
+
+	ret = cgroup_apply_control_enable(cgrp);
+	if (ret)
+		goto out_destroy;
+	/* let's create and online css's */
+	kernfs_activate(cgrp->kn);
+	ret = 0;
+
+	goto out_unlock;
+
+out_destroy:
+	cgroup_destroy_locked(cgrp);
+
+out_unlock:
+	init_balloon = cgrp;
+	init_hash_cg_ns();
+	init_hash_balloon_cg();
+}
+EXPORT_SYMBOL(init_balloon);
+
 static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early)
 {
 	struct cgroup_subsys_state *css;
@@ -6248,7 +6744,7 @@ int __init cgroup_init(void)
 #ifdef CONFIG_CPUSETS
 	WARN_ON(register_filesystem(&cpuset_fs_type));
 #endif
-
+	recycle_cgroup_create();
 	return 0;
 }
 
diff --git a/kernel/cgroup/pids.c b/kernel/cgroup/pids.c
index 8f61114c36dd..6275c110da26 100644
--- a/kernel/cgroup/pids.c
+++ b/kernel/cgroup/pids.c
@@ -273,10 +273,47 @@ static void pids_event(struct pids_cgroup *pids_forking,
 static int pids_can_fork(struct task_struct *task, struct css_set *cset)
 {
 	struct pids_cgroup *pids, *pids_over_limit;
-	int err;
+	struct cgroup_subsys_state *css;
+	int err, balloon_index;
+	struct pid_namespace *pid_ns;
+	struct pid *pid;
+	struct cgroup *cgrp_owner, *shared_cgrp, *balloon_cgrp;
+
+	css = cset->subsys[pids_cgrp_id];
+	pids = css_pids(css);
 
-	pids = css_pids(cset->subsys[pids_cgrp_id]);
 	err = pids_try_charge(pids, 1, &pids_over_limit);
+	pid = task->thread_pid;
+	if (!pid)
+		return 0;
+
+	pid_ns = pid->numbers[pid->level].ns;
+	if (!pid_ns)
+		return 0;
+
+	cgrp_owner = css->cgroup;
+	if (!cgrp_owner)
+		return 0;
+
+	if (pid_ns != &init_pid_ns) {
+		shared_cgrp = find_shared_cg(task->nsproxy->ipc_ns, task->nsproxy->net_ns,
+						pid_ns, cgrp_owner);
+		cg_ns_insert(cgrp_owner, task->nsproxy->ipc_ns, task->nsproxy->net_ns, pid_ns);
+
+		if (!shared_cgrp) {
+			balloon_index = find_balloon_index_from_cgroup(cgrp_owner);
+			if (balloon_index > BALLOON_CGROUP_HASH_COUNT)
+				return err;
+			insert_cgroup_to_balloon(&balloon_to_cgroup[balloon_index], cgrp_owner,
+							NULL);
+		} else {
+			balloon_cgrp = find_balloon_from_cgroup(shared_cgrp);
+			balloon_index = find_balloon_index_from_cgroup(shared_cgrp);
+			insert_cgroup_to_balloon(&balloon_to_cgroup[balloon_index], cgrp_owner,
+							balloon_cgrp);
+		}
+	}
+
 	if (err)
 		pids_event(pids, pids_over_limit);
 
diff --git a/kernel/exit.c b/kernel/exit.c
index 619f0014c33b..3a84aeaceb51 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -70,6 +70,7 @@
 #include <linux/sysfs.h>
 #include <linux/user_events.h>
 #include <linux/uaccess.h>
+#include <linux/memcontrol.h>
 
 #include <uapi/linux/wait.h>
 
@@ -1972,3 +1973,27 @@ __weak __function_aligned void abort(void)
 	panic("Oops failed to kill thread");
 }
 EXPORT_SYMBOL(abort);
+
+void check_pid_zombie(struct pid_namespace *pid_ns, struct cgroup *cgrp)
+{
+	struct task_struct *tmp, *reaper, *pos;
+	struct cgroup *to;
+
+	if (!pid_ns)
+		return;
+
+	reaper = pid_ns->child_reaper;
+	if (!reaper)
+		return;
+
+	if (list_empty(&reaper->children))
+		return;
+
+	list_for_each_entry_safe(pos, tmp, &reaper->children, sibling) {
+		if (!pos)
+			continue;
+		to = task_cgroup(pos, pids_cgrp_id);
+		if (pos->exit_state == EXIT_ZOMBIE && to == cgrp)
+			release_task(pos);
+	}
+}
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 79e6cb1d5c48..6d23531d3e6c 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1618,6 +1618,13 @@ static struct ctl_table kern_table[] = {
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
 	},
+	{
+		.procname	= "recycle_max_limit",
+		.data		= &recycle_max_limit,
+		.maxlen		= sizeof(long),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
 #ifdef CONFIG_PROC_SYSCTL
 	{
 		.procname	= "tainted",
diff --git a/mm/memcontrol-v1.c b/mm/memcontrol-v1.c
index 44803cbea38a..35e1a6fbbee8 100644
--- a/mm/memcontrol-v1.c
+++ b/mm/memcontrol-v1.c
@@ -757,7 +757,7 @@ static void memcg1_charge_statistics(struct mem_cgroup *memcg, int nr_pages);
  * This function doesn't do "charge" to new cgroup and doesn't do "uncharge"
  * from old cgroup.
  */
-static int mem_cgroup_move_account(struct folio *folio,
+int mem_cgroup_move_account(struct folio *folio,
 				   bool compound,
 				   struct mem_cgroup *from,
 				   struct mem_cgroup *to)
diff --git a/mm/memcontrol-v1.h b/mm/memcontrol-v1.h
index 3bb8b3030e61..9b81724c3239 100644
--- a/mm/memcontrol-v1.h
+++ b/mm/memcontrol-v1.h
@@ -101,6 +101,10 @@ void memcg1_oom_finish(struct mem_cgroup *memcg, bool locked);
 void memcg1_oom_recover(struct mem_cgroup *memcg);
 
 void memcg1_commit_charge(struct folio *folio, struct mem_cgroup *memcg);
+int mem_cgroup_move_account(struct folio *folio,
+				   bool compound,
+				   struct mem_cgroup *from,
+				   struct mem_cgroup *to);
 void memcg1_swapout(struct folio *folio, struct mem_cgroup *memcg);
 void memcg1_uncharge_batch(struct mem_cgroup *memcg, unsigned long pgpgout,
 			   unsigned long nr_memory, int nid);
@@ -139,6 +143,10 @@ static inline void memcg1_oom_recover(struct mem_cgroup *memcg) {}
 
 static inline void memcg1_commit_charge(struct folio *folio,
 					struct mem_cgroup *memcg) {}
+static inline int mem_cgroup_move_account(struct folio *folio,
+				   bool compound,
+				   struct mem_cgroup *from,
+				   struct mem_cgroup *to) { return 0; }
 
 static inline void memcg1_swapout(struct folio *folio, struct mem_cgroup *memcg) {}
 
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index bda6f75d22ff..bd82ca25a602 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -63,6 +63,7 @@
 #include <linux/seq_buf.h>
 #include <linux/sched/isolation.h>
 #include <linux/kmemleak.h>
+#include <linux/kernfs.h>
 #include "internal.h"
 #include <net/sock.h>
 #include <net/ip.h>
@@ -72,6 +73,8 @@
 #include <linux/uaccess.h>
 
 #include <trace/events/vmscan.h>
+long recycle_max_limit = RECYCLE_MEM_MAX;
+EXPORT_SYMBOL(recycle_max_limit);
 
 struct cgroup_subsys memory_cgrp_subsys __read_mostly;
 EXPORT_SYMBOL(memory_cgrp_subsys);
@@ -5446,3 +5449,198 @@ static int __init mem_cgroup_swap_init(void)
 subsys_initcall(mem_cgroup_swap_init);
 
 #endif /* CONFIG_SWAP */
+int _obj_cgroup_move(struct kmem_cache *s, struct slab *slab,
+					void **p, int objects, struct obj_cgroup *to)
+{
+	struct slabobj_ext *obj_exts;
+	int i;
+
+	obj_exts = slab_obj_exts(slab);
+	if (!obj_exts)
+		return 0;
+
+	for (i = 0; i < objects; i++) {
+		struct obj_cgroup *objcg;
+		unsigned int off;
+
+		off = obj_to_index(s, slab, p[i]);
+		objcg = obj_exts[off].objcg;
+		if (!objcg)
+			continue;
+		obj_exts[off].objcg = to;
+		obj_cgroup_uncharge(objcg, obj_full_size(s));
+		obj_cgroup_charge(to, GFP_KERNEL, obj_full_size(s));
+		mod_objcg_state(objcg, slab_pgdat(slab), cache_vmstat_idx(s),
+				-obj_full_size(s));
+		mod_objcg_state(to, slab_pgdat(slab), cache_vmstat_idx(s),
+				obj_full_size(s));
+	}
+	return 0;
+}
+
+int kmem_cache_move(struct kmem_cache *s, void *addr, int objects, struct mem_cgroup *to)
+{
+	s = cache_from_obj(s, addr);
+	return _obj_cgroup_move(s, virt_to_slab(addr), &addr, objects, to->objcg);
+}
+int kmem_folio_move(struct folio *folio,  struct mem_cgroup *from, struct mem_cgroup *to)
+{
+	struct obj_cgroup *objcg_to, *objcg_from;
+	int ret;
+	unsigned int order;
+	unsigned long space;
+
+	objcg_to = to->objcg;
+	if (!from || !to)
+		return 0;
+
+	if (!objcg_to)
+		return 0;
+
+	objcg_from = from->objcg;
+	if (!objcg_from)
+		return 0;
+
+	space = mem_cgroup_margin(to);
+	order = folio_order(folio);
+	if (space < (1 << order))
+		return -1;
+
+	__mem_cgroup_uncharge(folio);
+	ret = charge_memcg(folio, to, GFP_KERNEL & ~__GFP_DIRECT_RECLAIM);
+
+	return ret;
+}
+
+int kmem_cgroup_move(void *addr, struct mem_cgroup *from, struct mem_cgroup *to)
+{
+	struct folio *folio;
+	struct obj_cgroup *objcg_to, *objcg_from;
+	struct slab *slab;
+	struct kmem_cache *s;
+	unsigned int order;
+	int ret = 0;
+
+	folio = virt_to_folio(addr);
+
+	if (folio == NULL)
+		return 0;
+
+	objcg_to = to->objcg;
+	objcg_from = from->objcg;
+	if (objcg_to == NULL || objcg_from == NULL)
+		return 0;
+
+	if (folio_test_slab(folio)) {
+		slab = folio_slab(folio);
+		if (slab == NULL)
+			return 0;
+
+		s = slab->slab_cache;
+		if (s == NULL)
+			return 0;
+
+		ret = _obj_cgroup_move(s, virt_to_slab((void *)addr), &addr, 1, objcg_to);
+	} else {
+		order = folio_order(folio);
+
+		ret = obj_cgroup_charge_pages(objcg_to, GFP_KERNEL & ~__GFP_DIRECT_RECLAIM,
+							1 << order);
+		if (!ret) {
+			folio->memcg_data = (unsigned long)objcg_to |
+				MEMCG_DATA_KMEM;
+			obj_cgroup_uncharge_pages(objcg_from, 1 << order);
+			return 0;
+		}
+	}
+	return ret;
+}
+EXPORT_SYMBOL(kmem_cgroup_move);
+
+int page_set_balloon_max(struct mem_cgroup *memcg)
+{
+	xchg(&memcg->memory.max, recycle_max_limit);
+	return 0;
+}
+
+/**
+ * caculate_space - Calculate how much memory the given object occupies.
+ * @addr: the address of the given object.
+ *
+ * Returns the maximum amount of memory @addr occupies, in
+ * bytes.
+ */
+unsigned long caculate_space(void *addr)
+{
+	struct vm_struct *area;
+	unsigned long space;
+
+	if (is_vmalloc_addr(addr)) {
+		area = find_vm_area(addr);
+		if (area == NULL)
+			return 0;
+		space = area->nr_pages * PAGE_SIZE;
+	} else {
+		struct folio *folio;
+		struct slab *slab;
+		struct kmem_cache *s;
+		unsigned int order;
+
+		folio = virt_to_folio(addr);
+
+		if (folio == NULL)
+			return 0;
+
+		if (folio_test_slab(folio)) {
+			slab = folio_slab(folio);
+			if (slab == NULL)
+				return 0;
+
+			s = slab->slab_cache;
+			if (s == NULL)
+				return 0;
+
+			space = obj_full_size(s);
+		} else {
+			order = folio_order(folio);
+			space = (1 << order) * PAGE_SIZE;
+		}
+	}
+	return space;
+}
+
+int check_balloon_limits(unsigned long mem_delta, struct mem_cgroup *memcg_balloon)
+{
+	if (mem_cgroup_margin(memcg_balloon)*PAGE_SIZE < mem_delta)
+		return 1;
+
+	return 0;
+}
+
+int obj_cgroup_move(void *addr, struct mem_cgroup *from, struct mem_cgroup *to)
+{
+	struct vm_struct *area;
+	int i, ret;
+	struct page *page;
+	struct folio *folio;
+
+	if (is_vmalloc_addr(addr)) {
+		area = find_vm_area(addr);
+		if (area == NULL)
+			return 0;
+
+		for (i = 0; i < area->nr_pages; i++) {
+			page = area->pages[i];
+
+			if (!page)
+				return 0;
+			folio = page_folio(page);
+			try_charge(to, GFP_KERNEL & ~__GFP_DIRECT_RECLAIM, 1);
+			mem_cgroup_move_account(folio, 0, from, to);
+		}
+	} else {
+		ret = kmem_cgroup_move(addr, from, to);
+	}
+	return ret;
+}
+
diff --git a/mm/shmem.c b/mm/shmem.c
index c994fee2156f..c15d2c67b4e1 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -40,6 +40,8 @@
 #include <linux/fs_parser.h>
 #include <linux/swapfile.h>
 #include <linux/iversion.h>
+#include <linux/memcontrol.h>
+#include <linux/ipc_namespace.h>
 #include "swap.h"
 
 static struct vfsmount *shm_mnt __ro_after_init;
@@ -5374,3 +5376,66 @@ struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
 	return page;
 }
 EXPORT_SYMBOL_GPL(shmem_read_mapping_page_gfp);
+
+extern unsigned long shm_total_pages(struct inode *inode)
+{
+	struct address_space *mapping = inode->i_mapping;
+	loff_t lstart = 0;
+	pgoff_t start = (lstart + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	pgoff_t end = -1;
+	struct folio_batch fbatch;
+	struct folio *folio;
+	pgoff_t indices[PAGEVEC_SIZE];
+	pgoff_t index;
+	int i;
+	unsigned long pages = 0;
+
+	folio_batch_init(&fbatch);
+	index = start;
+	while (index < end && find_lock_entries(mapping, &index, end - 1,
+			&fbatch, indices)) {
+		for (i = 0; i < folio_batch_count(&fbatch); i++) {
+			folio = fbatch.folios[i];
+			if (!folio)
+				continue;
+			folio_unlock(folio);
+			folio_put(folio);
+			pages += 1;
+		}
+		fbatch.nr = 0;
+	}
+	return pages;
+}
+
+extern int ipc_shm_folio_move(struct inode *inode, struct mem_cgroup *from, struct mem_cgroup *to)
+{
+	struct address_space *mapping = inode->i_mapping;
+	loff_t lstart = 0;
+	pgoff_t start = (lstart + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	pgoff_t end = -1;
+	struct folio_batch fbatch;
+	pgoff_t indices[PAGEVEC_SIZE];
+	struct folio *folio;
+	pgoff_t index;
+	int i;
+	int err = 0;
+
+	folio_batch_init(&fbatch);
+	index = start;
+	while (index < end && find_lock_entries(mapping, &index, end - 1,
+			&fbatch, indices)) {
+		for (i = 0; i < folio_batch_count(&fbatch); i++) {
+			folio = fbatch.folios[i];
+			if (!folio)
+				continue;
+
+			folio_unlock(folio);
+			folio_put(folio);
+			if (err < 0)
+				continue;
+			err = kmem_folio_move(folio, from, to);
+		}
+		fbatch.nr = 0;
+	}
+	return err;
+}
diff --git a/mm/slab.h b/mm/slab.h
index f22fb760b286..5efc82c3bc73 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -591,6 +591,7 @@ bool __memcg_slab_post_alloc_hook(struct kmem_cache *s, struct list_lru *lru,
 				  gfp_t flags, size_t size, void **p);
 void __memcg_slab_free_hook(struct kmem_cache *s, struct slab *slab,
 			    void **p, int objects, struct slabobj_ext *obj_exts);
+struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x);
 #endif
 
 size_t __ksize(const void *objp);
diff --git a/mm/slub.c b/mm/slub.c
index e474a6717827..9e8d201097ba 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -4645,7 +4645,7 @@ static inline struct kmem_cache *virt_to_cache(const void *obj)
 	return slab->slab_cache;
 }
 
-static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x)
+struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x)
 {
 	struct kmem_cache *cachep;
 
diff --git a/net/core/dev.c b/net/core/dev.c
index 05d9624f360f..53588bfe2d0e 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -159,6 +159,11 @@
 #include <net/page_pool/helpers.h>
 #include <net/rps.h>
 #include <linux/phy_link_topology.h>
+#include <linux/memcontrol.h>
+#include <linux/ref_tracker.h>
+#include <linux/inetdevice.h>
+#include <linux/cgroup.h>
+#include <net/neighbour.h>
 
 #include "dev.h"
 #include "net-sysfs.h"
@@ -170,7 +175,7 @@ static int netif_rx_internal(struct sk_buff *skb);
 static int call_netdevice_notifiers_extack(unsigned long val,
 					   struct net_device *dev,
 					   struct netlink_ext_ack *extack);
-
+static int net_device_move(struct net_device *dev, struct mem_cgroup *from, struct mem_cgroup *to);
 static DEFINE_MUTEX(ifalias_mutex);
 
 /* protects napi_hash addition/deletion and napi_gen_id */
@@ -399,6 +404,33 @@ static void list_netdevice(struct net_device *dev)
 {
 	struct netdev_name_node *name_node;
 	struct net *net = dev_net(dev);
+	struct mem_cgroup *memcg;
+	struct nsproxy *ns;
+	struct cgroup *cgrp_owner, *shared_cgrp, *balloon_cgrp;
+	int balloon_index;
+
+	memcg = mem_cgroup_from_task(current);
+
+	cgrp_owner = memcg->css.cgroup;
+	ns = current->nsproxy;
+	shared_cgrp = find_shared_cg(NULL, ns->net_ns, NULL, cgrp_owner);
+	cg_ns_insert(cgrp_owner, NULL, ns->net_ns, NULL);
+	if (!shared_cgrp) {
+		balloon_index = find_balloon_index_from_cgroup(cgrp_owner);
+		if (balloon_index > BALLOON_CGROUP_HASH_COUNT) {
+			dev->cgroup = cgrp_owner;
+			dev->residual_time = 0;
+			return;
+		}
+		insert_cgroup_to_balloon(&balloon_to_cgroup[balloon_index], cgrp_owner, NULL);
+	} else {
+		balloon_cgrp = find_balloon_from_cgroup(shared_cgrp);
+		balloon_index = find_balloon_index_from_cgroup(shared_cgrp);
+		insert_cgroup_to_balloon(&balloon_to_cgroup[balloon_index], cgrp_owner,
+					balloon_cgrp);
+	}
+	dev->cgroup = cgrp_owner;
+	dev->residual_time = 0;
 
 	ASSERT_RTNL();
 
@@ -752,6 +784,46 @@ int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
 }
 EXPORT_SYMBOL_GPL(dev_fill_forward_path);
 
+static unsigned long net_device_size(struct net_device *dev)
+{
+	struct inet6_dev *i6_dev;
+	struct in_device *i4_dev;
+	unsigned long space = 0;
+
+	if (!dev)
+		return 0;
+
+	space += caculate_space(dev->_tx);
+	space += caculate_space(dev->_rx);
+	if (rcu_dereference_protected(dev->ingress_queue, 1))
+		space += caculate_space(rcu_dereference_protected(dev->ingress_queue, 1));
+
+	if (rcu_access_pointer(dev->ifalias))
+		space += caculate_space(rcu_access_pointer(dev->ifalias));
+
+	if (&dev->napi_list) {
+		struct napi_struct *p, *n;
+		struct sk_buff *skb;
+
+		list_for_each_entry_safe(p, n, &dev->napi_list, dev_list) {
+			skb = p->skb;
+			space += kmem_cache_size(net_hotdata.skbuff_cache);  //obj_full_size(s)
+		}
+	}
+	space += caculate_space(dev);
+
+	i4_dev = dev->ip_ptr;
+	if (i4_dev) {
+		space += neigh_size(i4_dev->arp_parms);
+		space += devinet_size(&i4_dev->cnf);
+	}
+
+	i6_dev = __in6_dev_get(dev);
+	if (i6_dev)
+		space += ipv6_size(i6_dev);
+	return space;
+}
+
 /**
  *	__dev_get_by_name	- find a device by its name
  *	@net: the applicable net namespace
@@ -767,9 +839,36 @@ EXPORT_SYMBOL_GPL(dev_fill_forward_path);
 struct net_device *__dev_get_by_name(struct net *net, const char *name)
 {
 	struct netdev_name_node *node_name;
+	struct net_device *dev;
+	struct mem_cgroup *memcg_owner, *memcg_recycle;
+	struct cgroup *cgrp_owner, *balloon_cgrp;
 
 	node_name = netdev_name_node_lookup(net, name);
-	return node_name ? node_name->dev : NULL;
+
+	if (!node_name)
+		return NULL;
+
+	dev = node_name->dev;
+
+	balloon_cgrp = find_balloon_from_cgroup(dev->cgroup);
+	if (dev->cgroup && balloon_cgrp && dev->cgroup == balloon_cgrp) {
+		memcg_owner = mem_cgroup_from_task(current);
+		if (!memcg_owner)
+			return NULL;
+
+		cgrp_owner = memcg_owner->css.cgroup;
+		if (!cgrp_owner)
+			return NULL;
+
+		memcg_recycle = get_cg_from_cgrp(balloon_cgrp, "memory");
+		if (!memcg_recycle)
+			return NULL;
+		net_device_move(dev, memcg_recycle, memcg_owner);
+		dev->cgroup = cgrp_owner;
+		dev->residual_time = 0;
+	}
+
+	return dev;
 }
 EXPORT_SYMBOL(__dev_get_by_name);
 
@@ -846,11 +945,31 @@ EXPORT_SYMBOL(netdev_get_by_name);
 struct net_device *__dev_get_by_index(struct net *net, int ifindex)
 {
 	struct net_device *dev;
+	struct mem_cgroup *memcg_owner, *memcg_recycle;
+	struct cgroup *cgrp_owner, *balloon_cgrp;
 	struct hlist_head *head = dev_index_hash(net, ifindex);
 
 	hlist_for_each_entry(dev, head, index_hlist)
-		if (dev->ifindex == ifindex)
+		if (dev->ifindex == ifindex) {
+			balloon_cgrp = find_balloon_from_cgroup(dev->cgroup);
+			if (dev->cgroup && balloon_cgrp && dev->cgroup == balloon_cgrp) {
+				memcg_owner = mem_cgroup_from_task(current);
+				if (!memcg_owner)
+					return NULL;
+
+				cgrp_owner = memcg_owner->css.cgroup;
+				if (!cgrp_owner)
+					return NULL;
+
+				memcg_recycle = get_cg_from_cgrp(balloon_cgrp, "memory");
+				if (!memcg_recycle)
+					return NULL;
+				net_device_move(dev, memcg_recycle, memcg_owner);
+				dev->cgroup = cgrp_owner;
+				dev->residual_time = 0;
+			}
 			return dev;
+		}
 
 	return NULL;
 }
@@ -12150,3 +12269,144 @@ static int __init net_dev_init(void)
 }
 
 subsys_initcall(net_dev_init);
+
+static int _net_device_move(struct net_device *dev, struct mem_cgroup *from, struct mem_cgroup *to)
+{
+	int err;
+	struct inet6_dev *i6_dev;
+	struct in_device *i4_dev;
+
+	err = obj_cgroup_move(dev->_tx, from, to);
+	err = obj_cgroup_move(dev->_rx, from, to);
+	if (err < 0)
+		return err;
+
+	if (rcu_dereference_protected(dev->ingress_queue, 1))
+		err = kmem_cgroup_move(rcu_dereference_protected(dev->ingress_queue, 1), from, to);
+
+	if (rcu_access_pointer(dev->ifalias))
+		err = kmem_cgroup_move(rcu_access_pointer(dev->ifalias), from, to);
+
+	if (&dev->napi_list) {
+		struct napi_struct *p, *n;
+		struct sk_buff *skb;
+
+		list_for_each_entry_safe(p, n, &dev->napi_list, dev_list) {
+			skb = p->skb;
+			err = kmem_cache_move(net_hotdata.skbuff_cache, skb, 1, to);
+		}
+	}
+	err = obj_cgroup_move(dev, from, to);
+	if (err < 0)
+		return err;
+
+	i4_dev = dev->ip_ptr;
+	if (i4_dev) {
+		err = neigh_move(i4_dev->arp_parms, from, to);
+		err = devinet_move(&i4_dev->cnf, from, to);
+	}
+	if (err < 0)
+		return err;
+
+	i6_dev = __in6_dev_get(dev);
+	if (i6_dev)
+		err = ipv6_dev_move(i6_dev, from, to);
+
+	return err;
+}
+
+static int net_device_move(struct net_device *dev, struct mem_cgroup *from, struct mem_cgroup *to)
+{
+	int err;
+
+	err = _net_device_move(dev, from, to);
+	return err;
+}
+
+extern int net_device_move_check(struct net *ns, struct cgroup *cgrp)
+{
+	int i;
+	struct net_device *ndev, *aux;
+	unsigned long mem_volume;
+	unsigned int balloon_index;
+	struct mem_cgroup *memcg_to, *memcg_from;
+	struct cgroup *balloon_cgroup;
+
+	memcg_from = get_cg_from_cgrp(cgrp, "memory");
+	if (!memcg_from)
+		return 0;
+
+	balloon_cgroup = find_balloon_from_cgroup(cgrp);
+
+	for_each_netdev_safe(ns, ndev, aux) {
+		if (!ndev)
+			continue;
+		if (balloon_cgroup && ndev->cgroup == balloon_cgroup)
+			ndev->residual_time++;
+
+		if (ndev->cgroup == cgrp) {
+			if (!balloon_cgroup) {
+				balloon_index = find_balloon_index_from_cgroup(cgrp);
+				balloon_cgroup = balloon_cgroup_create(balloon_index);
+				if (!balloon_cgroup)
+					return 0;
+
+				init_balloon_cgroup_to_balloon(&balloon_to_cgroup[balloon_index],
+						balloon_cgroup);
+				memcg_to = get_cg_from_cgrp(balloon_cgroup, "memory");
+				page_set_balloon_max(memcg_to);
+			}
+			memcg_to = get_cg_from_cgrp(balloon_cgroup, "memory");
+			if (!memcg_to)
+				return 0;
+
+			mem_volume = net_device_size(ndev);
+			if (check_balloon_limits(mem_volume, memcg_to)) {
+				for (i = 5; i > 0; i++) {
+					free_oldest_volume(cgrp, i);
+					cond_resched();
+					if (!check_balloon_limits(mem_volume, memcg_to))
+						goto move_resources;
+				}
+				LIST_HEAD(dev_kill_list);
+
+				rtnl_lock();
+				if (ndev->netns_local)
+					continue;
+				if (ndev->rtnl_link_ops && ndev->rtnl_link_ops->dellink)
+					ndev->rtnl_link_ops->dellink(ndev, &dev_kill_list);
+				else
+					unregister_netdevice_queue(ndev, &dev_kill_list);
+				unregister_netdevice_many(&dev_kill_list);
+				rtnl_unlock();
+			}
+move_resources:
+			ndev->cgroup = balloon_cgroup;
+			ndev->residual_time = 1;
+			net_device_move(ndev, memcg_from, memcg_to);
+		}
+	}
+	return 0;
+}
+
+extern void net_device_free(struct net *ns, unsigned int limit)
+{
+	struct net_device *ndev, *aux;
+	LIST_HEAD(dev_kill_list);
+
+	rtnl_lock();
+
+	for_each_netdev_safe(ns, ndev, aux) {
+		if (ndev->residual_time >= limit) {
+			if (ndev->netns_local)
+				continue;
+			if (ndev->rtnl_link_ops && ndev->rtnl_link_ops->dellink)
+				ndev->rtnl_link_ops->dellink(ndev, &dev_kill_list);
+			else
+				unregister_netdevice_queue(ndev, &dev_kill_list);
+			continue;
+		}
+	}
+	unregister_netdevice_many(&dev_kill_list);
+	rtnl_unlock();
+}
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 77b819cd995b..44cdf1e3661a 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -38,6 +38,7 @@
 #include <linux/log2.h>
 #include <linux/inetdevice.h>
 #include <net/addrconf.h>
+#include <linux/memcontrol.h>
 
 #include <trace/events/neigh.h>
 
@@ -3901,3 +3902,37 @@ static int __init neigh_init(void)
 }
 
 subsys_initcall(neigh_init);
+
+extern unsigned long neigh_size(struct neigh_parms *neigh_p)
+{
+	int space;
+	struct neigh_sysctl_table *neigh_st;
+
+	if (!neigh_p)
+		return 0;
+
+	neigh_st = neigh_p->sysctl_table;
+	if (!neigh_st)
+		return 0;
+
+	space += caculate_space(neigh_st);
+	space += caculate_space(neigh_st->sysctl_header);
+	return space;
+}
+
+extern int neigh_move(struct neigh_parms *neigh_p, struct mem_cgroup *from, struct mem_cgroup *to)
+{
+	int err;
+	struct neigh_sysctl_table *neigh_st;
+
+	if (!neigh_p)
+		return 0;
+
+	neigh_st = neigh_p->sysctl_table;
+	if (!neigh_st)
+		return 0;
+
+	err = kmem_cgroup_move(neigh_st, from, to);
+	err = kmem_cgroup_move(neigh_st->sysctl_header, from, to);
+	return err;
+}
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index ab76744383cf..3a49801f04f4 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -53,6 +53,7 @@
 #endif
 #include <linux/kmod.h>
 #include <linux/netconf.h>
+#include <linux/memcontrol.h>
 
 #include <net/arp.h>
 #include <net/ip.h>
@@ -2803,3 +2804,37 @@ void __init devinet_init(void)
 		      inet_netconf_dump_devconf,
 		      RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED);
 }
+
+extern unsigned long devinet_size(struct ipv4_devconf *ipv4_p)
+{
+	unsigned long space;
+	struct devinet_sysctl_table *devinet_st;
+
+	if (!ipv4_p)
+		return 0;
+
+	devinet_st = ipv4_p->sysctl;
+	if (!devinet_st)
+		return 0;
+
+	space += caculate_space(devinet_st);
+	space += caculate_space(devinet_st->sysctl_header);
+	return space;
+}
+
+extern int devinet_move(struct ipv4_devconf *ipv4_p, struct mem_cgroup *from, struct mem_cgroup *to)
+{
+	int err;
+	struct devinet_sysctl_table *devinet_st;
+
+	if (!ipv4_p)
+		return 0;
+
+	devinet_st = ipv4_p->sysctl;
+	if (!devinet_st)
+		return 0;
+
+	err = kmem_cgroup_move(devinet_st, from, to);
+	err = kmem_cgroup_move(devinet_st->sysctl_header, from, to);
+	return err;
+}
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index d680beb91b0a..e144f2f357b3 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -91,6 +91,7 @@
 #include <linux/seq_file.h>
 #include <linux/export.h>
 #include <linux/ioam6.h>
+#include <linux/memcontrol.h>
 
 #define IPV6_MAX_STRLEN \
 	sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")
@@ -7528,3 +7529,59 @@ void addrconf_cleanup(void)
 
 	destroy_workqueue(addrconf_wq);
 }
+
+extern unsigned long ipv6_size(struct inet6_dev *in_dev)
+{
+	int space = 0;
+	struct ctl_table *table;
+	struct ipv6_devconf *p = &in_dev->cnf;
+
+	space += caculate_space(in_dev);
+	if (!in_dev->nd_parms)
+		return space;
+
+	space += neigh_size(in_dev->nd_parms);
+	if (!in_dev->stats.icmpv6msgdev)
+		return space;
+
+	space += caculate_space(in_dev->stats.icmpv6msgdev);
+	table = p->sysctl_header->ctl_table_arg;
+	if (!table)
+		return space;
+
+	space += caculate_space(table);
+	if (!p->sysctl_header)
+		return space;
+
+	space += caculate_space(p->sysctl_header);
+
+	return space;
+}
+
+extern int ipv6_dev_move(struct inet6_dev *in_dev, struct mem_cgroup *from, struct mem_cgroup  *to)
+{
+	int err;
+	struct ctl_table *table;
+	struct ipv6_devconf *p = &in_dev->cnf;
+
+	err = kmem_cgroup_move(in_dev, from, to);
+	if (!in_dev->nd_parms)
+		return 0;
+
+	err = neigh_move(in_dev->nd_parms, from, to);
+	if (!in_dev->stats.icmpv6msgdev)
+		return 0;
+
+	err = kmem_cgroup_move(in_dev->stats.icmpv6msgdev, from, to);
+	table = p->sysctl_header->ctl_table_arg;
+	if (!table)
+		return 0;
+
+	err = kmem_cgroup_move(table, from, to);
+	if (!p->sysctl_header)
+		return 0;
+
+	err = kmem_cgroup_move(p->sysctl_header, from, to);
+
+	return err;
+}
