Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 591151 Details for
Bug 831133
feature request: shm_rmid_forced
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
add shm_rmid_forced sysctl
shm.patch (text/plain), 11.02 KB, created by
Vasiliy Kulikov
on 2012-06-12 09:35:26 UTC
(
hide
)
Description:
add shm_rmid_forced sysctl
Filename:
MIME Type:
Creator:
Vasiliy Kulikov
Created:
2012-06-12 09:35:26 UTC
Size:
11.02 KB
patch
obsolete
>diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt >index 25a2f10..b7f16d3 100644 >--- a/Documentation/sysctl/kernel.txt >+++ b/Documentation/sysctl/kernel.txt >@@ -57,6 +57,7 @@ show up in /proc/sys/kernel: > - rtsig-nr > - sem > - sg-big-buff [ generic SCSI device (sg) ] >+- shm_rmid_forced > - shmall > - shmmax [ sysv ipc ] > - shmmni >@@ -443,6 +444,27 @@ kernel. This value defaults to SHMMAX. > > ============================================================== > >+shm_rmid_forced: >+ >+Linux lets you set resource limits, including how much memory one >+process can consume, via setrlimit(2). Unfortunately, shared memory >+segments are allowed to exist without association with any process, and >+thus might not be counted against any resource limits. If enabled, >+shared memory segments are automatically destroyed when their attach >+count becomes zero after a detach or a process termination. It will >+also destroy segments that were created, but never attached to, on exit >+from the process. The only use left for IPC_RMID is to immediately >+destroy an unattached segment. Of course, this breaks the way things are >+defined, so some applications might stop working. Note that this >+feature will do you no good unless you also configure your resource >+limits (in particular, RLIMIT_AS and RLIMIT_NPROC). Most systems don't >+need this. >+ >+Note that if you change this from 0 to 1, already created segments >+without users and with a dead originative process will be destroyed. >+ >+============================================================== >+ > softlockup_thresh: > > This value can be used to lower the softlockup tolerance threshold. The >diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h >index 8dd2520..42a302f 100644 >--- a/include/linux/ipc_namespace.h >+++ b/include/linux/ipc_namespace.h >@@ -42,6 +42,11 @@ struct ipc_namespace { > size_t shm_ctlall; > int shm_ctlmni; > int shm_tot; >+ /* >+ * Defines whether IPC_RMID is forced for _all_ shm segments regardless >+ * of shmctl() >+ */ >+ int shm_rmid_forced; > > struct notifier_block ipcns_nb; > >@@ -75,6 +80,7 @@ extern int register_ipcns_notifier(struct ipc_namespace *); > extern int cond_register_ipcns_notifier(struct ipc_namespace *); > extern void unregister_ipcns_notifier(struct ipc_namespace *); > extern int ipcns_notify(unsigned long); >+extern void shm_destroy_orphaned(struct ipc_namespace *ns); > #else /* CONFIG_SYSVIPC */ > static inline int register_ipcns_notifier(struct ipc_namespace *ns) > { return 0; } >@@ -82,6 +88,7 @@ static inline int cond_register_ipcns_notifier(struct ipc_namespace *ns) > { return 0; } > static inline void unregister_ipcns_notifier(struct ipc_namespace *ns) { } > static inline int ipcns_notify(unsigned long l) { return 0; } >+static inline void shm_destroy_orphaned(struct ipc_namespace *ns) {} > #endif /* CONFIG_SYSVIPC */ > > #ifdef CONFIG_POSIX_MQUEUE >diff --git a/include/linux/shm.h b/include/linux/shm.h >index eca6235..92808b8 100644 >--- a/include/linux/shm.h >+++ b/include/linux/shm.h >@@ -95,6 +95,9 @@ struct shmid_kernel /* private to the kernel */ > pid_t shm_cprid; > pid_t shm_lprid; > struct user_struct *mlock_user; >+ >+ /* The task created the shm object. NULL if the task is dead. */ >+ struct task_struct *shm_creator; > }; > > /* shm_mode upper byte flags */ >@@ -106,6 +109,7 @@ struct shmid_kernel /* private to the kernel */ > #ifdef CONFIG_SYSVIPC > long do_shmat(int shmid, char __user *shmaddr, int shmflg, unsigned long *addr); > extern int is_file_shm_hugepages(struct file *file); >+extern void exit_shm(struct task_struct *task); > #else > static inline long do_shmat(int shmid, char __user *shmaddr, > int shmflg, unsigned long *addr) >@@ -116,6 +120,9 @@ static inline int is_file_shm_hugepages(struct file *file) > { > return 0; > } >+static inline void exit_shm(struct task_struct *task) >+{ >+} > #endif > > #endif /* __KERNEL__ */ >diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c >index 7d37047..6285afc 100644 >--- a/ipc/ipc_sysctl.c >+++ b/ipc/ipc_sysctl.c >@@ -31,12 +31,37 @@ static int proc_ipc_dointvec(ctl_table *table, int write, > void __user *buffer, size_t *lenp, loff_t *ppos) > { > struct ctl_table ipc_table; >+ > memcpy(&ipc_table, table, sizeof(ipc_table)); > ipc_table.data = get_ipc(table); > > return proc_dointvec(&ipc_table, write, buffer, lenp, ppos); > } > >+static int proc_ipc_dointvec_minmax(ctl_table *table, int write, >+ void __user *buffer, size_t *lenp, loff_t *ppos) >+{ >+ struct ctl_table ipc_table; >+ >+ memcpy(&ipc_table, table, sizeof(ipc_table)); >+ ipc_table.data = get_ipc(table); >+ >+ return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); >+} >+ >+static int proc_ipc_dointvec_minmax_orphans(ctl_table *table, int write, >+ void __user *buffer, size_t *lenp, loff_t *ppos) >+{ >+ struct ipc_namespace *ns = current->nsproxy->ipc_ns; >+ int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos); >+ >+ if (err < 0) >+ return err; >+ if (ns->shm_rmid_forced) >+ shm_destroy_orphaned(ns); >+ return err; >+} >+ > static int proc_ipc_callback_dointvec(ctl_table *table, int write, > void __user *buffer, size_t *lenp, loff_t *ppos) > { >@@ -125,6 +150,8 @@ static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write, > #else > #define proc_ipc_doulongvec_minmax NULL > #define proc_ipc_dointvec NULL >+#define proc_ipc_dointvec_minmax NULL >+#define proc_ipc_dointvec_minmax_orphans NULL > #define proc_ipc_callback_dointvec NULL > #define proc_ipcauto_dointvec_minmax NULL > #endif >@@ -221,6 +248,15 @@ static struct ctl_table ipc_kern_table[] = { > .proc_handler = proc_ipc_dointvec, > .strategy = sysctl_ipc_data, > }, >+ { >+ .procname = "shm_rmid_forced", >+ .data = &init_ipc_ns.shm_rmid_forced, >+ .maxlen = sizeof(init_ipc_ns.shm_rmid_forced), >+ .mode = 0644, >+ .proc_handler = proc_ipc_dointvec_minmax_orphans, >+ .extra1 = &zero, >+ .extra2 = &one, >+ }, > { > .ctl_name = KERN_MSGMAX, > .procname = "msgmax", >diff --git a/ipc/shm.c b/ipc/shm.c >index 9f0ff6f..1c4720d 100644 >--- a/ipc/shm.c >+++ b/ipc/shm.c >@@ -74,6 +74,7 @@ void shm_init_ns(struct ipc_namespace *ns) > ns->shm_ctlmax = SHMMAX; > ns->shm_ctlall = SHMALL; > ns->shm_ctlmni = SHMMNI; >+ ns->shm_rmid_forced = 0; > ns->shm_tot = 0; > ipc_init_ids(&shm_ids(ns)); > } >@@ -104,9 +105,16 @@ void shm_exit_ns(struct ipc_namespace *ns) > } > #endif > >-void __init shm_init (void) >+static int __init ipc_ns_init(void) > { > shm_init_ns(&init_ipc_ns); >+ return 0; >+} >+ >+pure_initcall(ipc_ns_init); >+ >+void __init shm_init (void) >+{ > ipc_init_proc_interface("sysvipc/shm", > #if BITS_PER_LONG <= 32 > " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n", >@@ -130,6 +138,12 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id) > return container_of(ipcp, struct shmid_kernel, shm_perm); > } > >+static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp) >+{ >+ rcu_read_lock(); >+ spin_lock(&ipcp->shm_perm.lock); >+} >+ > static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns, > int id) > { >@@ -187,6 +201,23 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) > } > > /* >+ * shm_may_destroy - identifies whether shm segment should be destroyed now >+ * >+ * Returns true if and only if there are no active users of the segment and >+ * one of the following is true: >+ * >+ * 1) shmctl(id, IPC_RMID, NULL) was called for this shp >+ * >+ * 2) sysctl kernel.shm_rmid_forced is set to 1. >+ */ >+static bool shm_may_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) >+{ >+ return (shp->shm_nattch == 0) && >+ (ns->shm_rmid_forced || >+ (shp->shm_perm.mode & SHM_DEST)); >+} >+ >+/* > * remove the attach descriptor vma. > * free memory for segment if it is marked destroyed. > * The descriptor has already been removed from the current->mm->mmap list >@@ -206,14 +237,90 @@ static void shm_close(struct vm_area_struct *vma) > shp->shm_lprid = task_tgid_vnr(current); > shp->shm_dtim = get_seconds(); > shp->shm_nattch--; >- if(shp->shm_nattch == 0 && >- shp->shm_perm.mode & SHM_DEST) >+ if (shm_may_destroy(ns, shp)) > shm_destroy(ns, shp); > else > shm_unlock(shp); > up_write(&shm_ids(ns).rw_mutex); > } > >+/* Called with ns->shm_ids(ns).rw_mutex locked */ >+static int shm_try_destroy_current(int id, void *p, void *data) >+{ >+ struct ipc_namespace *ns = data; >+ struct kern_ipc_perm *ipcp = p; >+ struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm); >+ >+ if (shp->shm_creator != current) >+ return 0; >+ >+ /* >+ * Mark it as orphaned to destroy the segment when >+ * kernel.shm_rmid_forced is changed. >+ * It is noop if the following shm_may_destroy() returns true. >+ */ >+ shp->shm_creator = NULL; >+ >+ /* >+ * Don't even try to destroy it. If shm_rmid_forced=0 and IPC_RMID >+ * is not set, it shouldn't be deleted here. >+ */ >+ if (!ns->shm_rmid_forced) >+ return 0; >+ >+ if (shm_may_destroy(ns, shp)) { >+ shm_lock_by_ptr(shp); >+ shm_destroy(ns, shp); >+ } >+ return 0; >+} >+ >+/* Called with ns->shm_ids(ns).rw_mutex locked */ >+static int shm_try_destroy_orphaned(int id, void *p, void *data) >+{ >+ struct ipc_namespace *ns = data; >+ struct kern_ipc_perm *ipcp = p; >+ struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm); >+ >+ /* >+ * We want to destroy segments without users and with already >+ * exit'ed originating process. >+ * >+ * As shp->* are changed under rw_mutex, it's safe to skip shp locking. >+ */ >+ if (shp->shm_creator != NULL) >+ return 0; >+ >+ if (shm_may_destroy(ns, shp)) { >+ shm_lock_by_ptr(shp); >+ shm_destroy(ns, shp); >+ } >+ return 0; >+} >+ >+void shm_destroy_orphaned(struct ipc_namespace *ns) >+{ >+ down_write(&shm_ids(ns).rw_mutex); >+ if (shm_ids(ns).in_use) >+ idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns); >+ up_write(&shm_ids(ns).rw_mutex); >+} >+ >+ >+void exit_shm(struct task_struct *task) >+{ >+ struct ipc_namespace *ns = task->nsproxy->ipc_ns; >+ >+ if (shm_ids(ns).in_use == 0) >+ return; >+ >+ /* Destroy all already created segments, but not mapped yet */ >+ down_write(&shm_ids(ns).rw_mutex); >+ if (shm_ids(ns).in_use) >+ idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns); >+ up_write(&shm_ids(ns).rw_mutex); >+} >+ > static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) > { > struct file *file = vma->vm_file; >@@ -402,6 +509,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) > shp->shm_segsz = size; > shp->shm_nattch = 0; > shp->shm_file = file; >+ shp->shm_creator = current; > /* > * shmid gets reported as "inode#" in /proc/pid/maps. > * proc-ps tools use this. Changing this will break them. >@@ -948,8 +1056,7 @@ out_nattch: > shp = shm_lock(ns, shmid); > BUG_ON(IS_ERR(shp)); > shp->shm_nattch--; >- if(shp->shm_nattch == 0 && >- shp->shm_perm.mode & SHM_DEST) >+ if (shm_may_destroy(ns, shp)) > shm_destroy(ns, shp); > else > shm_unlock(shp); >diff --git a/kernel/exit.c b/kernel/exit.c >index 1c77314..d491622 100644 >--- a/kernel/exit.c >+++ b/kernel/exit.c >@@ -982,6 +982,7 @@ NORET_TYPE void do_exit(long code) > trace_sched_process_exit(tsk); > > exit_sem(tsk); >+ exit_shm(tsk); > exit_files(tsk); > exit_fs(tsk); > check_stack_usage();
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 831133
: 591151