[PATCH RFC 4/5] vm_cgroup: shared memory accounting

2014-07-03 Thread Vladimir Davydov
Address space that contributes to memory overcommit consists of two
parts - private writable mappings and shared memory. This patch adds
shared memory accounting.

Each shmem inode holds a reference to the vm cgroup it is accounted to.
The reference is initialized with the current cgroup on shmem inode
creation and released only on shmem inode destruction. For simplicity,
shmem inodes accounted to a vm cgroup are not re-charged to the parent
on css offline yet, so offline cgroups will be hanging in memory until
all inodes accounted to it die.

Signed-off-by: Vladimir Davydov 
---
 include/linux/shmem_fs.h  |6 ++
 include/linux/vm_cgroup.h |   32 
 mm/shmem.c|   39 +--
 mm/vm_cgroup.c|   36 
 4 files changed, 107 insertions(+), 6 deletions(-)

diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 4d1771c2d29f..b87f8b35ad40 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -7,6 +7,8 @@
 #include 
 #include 
 
+struct vm_cgroup;
+
 /* inode in-kernel data */
 
 struct shmem_inode_info {
@@ -21,6 +23,10 @@ struct shmem_inode_info {
struct list_headswaplist;   /* chain of maybes on swap */
struct simple_xattrsxattrs; /* list of xattrs */
struct inodevfs_inode;
+#ifdef CONFIG_CGROUP_VM
+   struct vm_cgroup*vmcg;  /* vm_cgroup this inode is
+  accounted to */
+#endif
 };
 
 struct shmem_sb_info {
diff --git a/include/linux/vm_cgroup.h b/include/linux/vm_cgroup.h
index 34ed936a0a10..582f051091bd 100644
--- a/include/linux/vm_cgroup.h
+++ b/include/linux/vm_cgroup.h
@@ -2,6 +2,7 @@
 #define _LINUX_VM_CGROUP_H
 
 struct mm_struct;
+struct shmem_inode_info;
 
 #ifdef CONFIG_CGROUP_VM
 static inline bool vm_cgroup_disabled(void)
@@ -17,6 +18,16 @@ extern int vm_cgroup_charge_memory_mm(struct mm_struct *mm,
  unsigned long nr_pages);
 extern void vm_cgroup_uncharge_memory_mm(struct mm_struct *mm,
 unsigned long nr_pages);
+
+#ifdef CONFIG_SHMEM
+extern void shmem_init_vm_cgroup(struct shmem_inode_info *info);
+extern void shmem_release_vm_cgroup(struct shmem_inode_info *info);
+extern int vm_cgroup_charge_shmem(struct shmem_inode_info *info,
+ unsigned long nr_pages);
+extern void vm_cgroup_uncharge_shmem(struct shmem_inode_info *info,
+unsigned long nr_pages);
+#endif
+
 #else /* !CONFIG_CGROUP_VM */
 static inline bool vm_cgroup_disabled(void)
 {
@@ -42,6 +53,27 @@ static inline void vm_cgroup_uncharge_memory_mm(struct 
mm_struct *mm,
unsigned long nr_pages)
 {
 }
+
+#ifdef CONFIG_SHMEM
+static inline void shmem_init_vm_cgroup(struct shmem_inode_info *info)
+{
+}
+
+static inline void shmem_release_vm_cgroup(struct shmem_inode_info *info)
+{
+}
+
+static inline int vm_cgroup_charge_shmem(struct shmem_inode_info *info,
+unsigned long nr_pages)
+{
+}
+
+static inline void vm_cgroup_uncharge_shmem(struct shmem_inode_info *info,
+   unsigned long nr_pages)
+{
+}
+#endif
+
 #endif /* CONFIG_CGROUP_VM */
 
 #endif /* _LINUX_VM_CGROUP_H */
diff --git a/mm/shmem.c b/mm/shmem.c
index 4e28eb1222cd..3968cdf1d254 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -66,6 +66,7 @@ static struct vfsmount *shm_mnt;
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -130,6 +131,27 @@ static inline struct shmem_sb_info *SHMEM_SB(struct 
super_block *sb)
return sb->s_fs_info;
 }
 
+static inline int __shmem_acct_memory(struct shmem_inode_info *info,
+ long pages)
+{
+   int ret;
+
+   ret = vm_cgroup_charge_shmem(info, pages);
+   if (ret)
+   return ret;
+   ret = security_vm_enough_memory_mm(current->mm, pages);
+   if (ret)
+   vm_cgroup_uncharge_shmem(info, pages);
+   return ret;
+}
+
+static inline void __shmem_unacct_memory(struct shmem_inode_info *info,
+long pages)
+{
+   vm_unacct_memory(pages);
+   vm_cgroup_uncharge_shmem(info, pages);
+}
+
 /*
  * shmem_file_setup pre-accounts the whole fixed size of a VM object,
  * for shared memory and for shared anonymous (/dev/zero) mappings
@@ -141,7 +163,7 @@ static inline int shmem_acct_size(struct inode *inode)
struct shmem_inode_info *info = SHMEM_I(inode);
 
return (info->flags & VM_NORESERVE) ?
-   0 : security_vm_enough_memory_mm(current->mm, 
VM_ACCT(inode->i_size));
+   0 : __shmem_acct_memory(info, VM_ACCT(inode->i_size));
 }
 
 static inline void shmem_unacct_size(struct inode *inode)
@@ -149,7 +171,7 @@ static 

[PATCH RFC 4/5] vm_cgroup: shared memory accounting

2014-07-03 Thread Vladimir Davydov
Address space that contributes to memory overcommit consists of two
parts - private writable mappings and shared memory. This patch adds
shared memory accounting.

Each shmem inode holds a reference to the vm cgroup it is accounted to.
The reference is initialized with the current cgroup on shmem inode
creation and released only on shmem inode destruction. For simplicity,
shmem inodes accounted to a vm cgroup are not re-charged to the parent
on css offline yet, so offline cgroups will be hanging in memory until
all inodes accounted to it die.

Signed-off-by: Vladimir Davydov vdavy...@parallels.com
---
 include/linux/shmem_fs.h  |6 ++
 include/linux/vm_cgroup.h |   32 
 mm/shmem.c|   39 +--
 mm/vm_cgroup.c|   36 
 4 files changed, 107 insertions(+), 6 deletions(-)

diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 4d1771c2d29f..b87f8b35ad40 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -7,6 +7,8 @@
 #include linux/percpu_counter.h
 #include linux/xattr.h
 
+struct vm_cgroup;
+
 /* inode in-kernel data */
 
 struct shmem_inode_info {
@@ -21,6 +23,10 @@ struct shmem_inode_info {
struct list_headswaplist;   /* chain of maybes on swap */
struct simple_xattrsxattrs; /* list of xattrs */
struct inodevfs_inode;
+#ifdef CONFIG_CGROUP_VM
+   struct vm_cgroup*vmcg;  /* vm_cgroup this inode is
+  accounted to */
+#endif
 };
 
 struct shmem_sb_info {
diff --git a/include/linux/vm_cgroup.h b/include/linux/vm_cgroup.h
index 34ed936a0a10..582f051091bd 100644
--- a/include/linux/vm_cgroup.h
+++ b/include/linux/vm_cgroup.h
@@ -2,6 +2,7 @@
 #define _LINUX_VM_CGROUP_H
 
 struct mm_struct;
+struct shmem_inode_info;
 
 #ifdef CONFIG_CGROUP_VM
 static inline bool vm_cgroup_disabled(void)
@@ -17,6 +18,16 @@ extern int vm_cgroup_charge_memory_mm(struct mm_struct *mm,
  unsigned long nr_pages);
 extern void vm_cgroup_uncharge_memory_mm(struct mm_struct *mm,
 unsigned long nr_pages);
+
+#ifdef CONFIG_SHMEM
+extern void shmem_init_vm_cgroup(struct shmem_inode_info *info);
+extern void shmem_release_vm_cgroup(struct shmem_inode_info *info);
+extern int vm_cgroup_charge_shmem(struct shmem_inode_info *info,
+ unsigned long nr_pages);
+extern void vm_cgroup_uncharge_shmem(struct shmem_inode_info *info,
+unsigned long nr_pages);
+#endif
+
 #else /* !CONFIG_CGROUP_VM */
 static inline bool vm_cgroup_disabled(void)
 {
@@ -42,6 +53,27 @@ static inline void vm_cgroup_uncharge_memory_mm(struct 
mm_struct *mm,
unsigned long nr_pages)
 {
 }
+
+#ifdef CONFIG_SHMEM
+static inline void shmem_init_vm_cgroup(struct shmem_inode_info *info)
+{
+}
+
+static inline void shmem_release_vm_cgroup(struct shmem_inode_info *info)
+{
+}
+
+static inline int vm_cgroup_charge_shmem(struct shmem_inode_info *info,
+unsigned long nr_pages)
+{
+}
+
+static inline void vm_cgroup_uncharge_shmem(struct shmem_inode_info *info,
+   unsigned long nr_pages)
+{
+}
+#endif
+
 #endif /* CONFIG_CGROUP_VM */
 
 #endif /* _LINUX_VM_CGROUP_H */
diff --git a/mm/shmem.c b/mm/shmem.c
index 4e28eb1222cd..3968cdf1d254 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -66,6 +66,7 @@ static struct vfsmount *shm_mnt;
 #include linux/highmem.h
 #include linux/seq_file.h
 #include linux/magic.h
+#include linux/vm_cgroup.h
 
 #include asm/uaccess.h
 #include asm/pgtable.h
@@ -130,6 +131,27 @@ static inline struct shmem_sb_info *SHMEM_SB(struct 
super_block *sb)
return sb-s_fs_info;
 }
 
+static inline int __shmem_acct_memory(struct shmem_inode_info *info,
+ long pages)
+{
+   int ret;
+
+   ret = vm_cgroup_charge_shmem(info, pages);
+   if (ret)
+   return ret;
+   ret = security_vm_enough_memory_mm(current-mm, pages);
+   if (ret)
+   vm_cgroup_uncharge_shmem(info, pages);
+   return ret;
+}
+
+static inline void __shmem_unacct_memory(struct shmem_inode_info *info,
+long pages)
+{
+   vm_unacct_memory(pages);
+   vm_cgroup_uncharge_shmem(info, pages);
+}
+
 /*
  * shmem_file_setup pre-accounts the whole fixed size of a VM object,
  * for shared memory and for shared anonymous (/dev/zero) mappings
@@ -141,7 +163,7 @@ static inline int shmem_acct_size(struct inode *inode)
struct shmem_inode_info *info = SHMEM_I(inode);
 
return (info-flags  VM_NORESERVE) ?
-   0 : security_vm_enough_memory_mm(current-mm, 
VM_ACCT(inode-i_size));
+   0 :