| Nadia Derbey | b6b337a | 2008-04-29 01:00:42 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * linux/ipc/ipcns_notifier.c | 
|  | 3 | * Copyright (C) 2007 BULL SA. Nadia Derbey | 
|  | 4 | * | 
|  | 5 | * Notification mechanism for ipc namespaces: | 
|  | 6 | * The callback routine registered in the memory chain invokes the ipcns | 
|  | 7 | * notifier chain with the IPCNS_MEMCHANGED event. | 
|  | 8 | * Each callback routine registered in the ipcns namespace recomputes msgmni | 
|  | 9 | * for the owning namespace. | 
|  | 10 | */ | 
|  | 11 |  | 
|  | 12 | #include <linux/msg.h> | 
|  | 13 | #include <linux/rcupdate.h> | 
|  | 14 | #include <linux/notifier.h> | 
|  | 15 | #include <linux/nsproxy.h> | 
|  | 16 | #include <linux/ipc_namespace.h> | 
|  | 17 |  | 
|  | 18 | #include "util.h" | 
|  | 19 |  | 
|  | 20 |  | 
|  | 21 |  | 
|  | 22 | static BLOCKING_NOTIFIER_HEAD(ipcns_chain); | 
|  | 23 |  | 
|  | 24 |  | 
|  | 25 | static int ipcns_callback(struct notifier_block *self, | 
|  | 26 | unsigned long action, void *arg) | 
|  | 27 | { | 
|  | 28 | struct ipc_namespace *ns; | 
|  | 29 |  | 
|  | 30 | switch (action) { | 
|  | 31 | case IPCNS_MEMCHANGED:   /* amount of lowmem has changed */ | 
| Nadia Derbey | e2c284d | 2008-04-29 01:00:44 -0700 | [diff] [blame] | 32 | case IPCNS_CREATED: | 
|  | 33 | case IPCNS_REMOVED: | 
| Nadia Derbey | b6b337a | 2008-04-29 01:00:42 -0700 | [diff] [blame] | 34 | /* | 
|  | 35 | * It's time to recompute msgmni | 
|  | 36 | */ | 
|  | 37 | ns = container_of(self, struct ipc_namespace, ipcns_nb); | 
|  | 38 | /* | 
|  | 39 | * No need to get a reference on the ns: the 1st job of | 
|  | 40 | * free_ipc_ns() is to unregister the callback routine. | 
|  | 41 | * blocking_notifier_chain_unregister takes the wr lock to do | 
|  | 42 | * it. | 
|  | 43 | * When this callback routine is called the rd lock is held by | 
|  | 44 | * blocking_notifier_call_chain. | 
|  | 45 | * So the ipc ns cannot be freed while we are here. | 
|  | 46 | */ | 
|  | 47 | recompute_msgmni(ns); | 
|  | 48 | break; | 
|  | 49 | default: | 
|  | 50 | break; | 
|  | 51 | } | 
|  | 52 |  | 
|  | 53 | return NOTIFY_OK; | 
|  | 54 | } | 
|  | 55 |  | 
|  | 56 | int register_ipcns_notifier(struct ipc_namespace *ns) | 
|  | 57 | { | 
| Nadia Derbey | 9eefe52 | 2008-07-25 01:48:08 -0700 | [diff] [blame] | 58 | int rc; | 
|  | 59 |  | 
| Nadia Derbey | b6b337a | 2008-04-29 01:00:42 -0700 | [diff] [blame] | 60 | memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb)); | 
|  | 61 | ns->ipcns_nb.notifier_call = ipcns_callback; | 
|  | 62 | ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI; | 
| Nadia Derbey | 9eefe52 | 2008-07-25 01:48:08 -0700 | [diff] [blame] | 63 | rc = blocking_notifier_chain_register(&ipcns_chain, &ns->ipcns_nb); | 
|  | 64 | if (!rc) | 
|  | 65 | ns->auto_msgmni = 1; | 
|  | 66 | return rc; | 
| Nadia Derbey | b6b337a | 2008-04-29 01:00:42 -0700 | [diff] [blame] | 67 | } | 
|  | 68 |  | 
| Nadia Derbey | 6546bc4 | 2008-04-29 01:00:45 -0700 | [diff] [blame] | 69 | int cond_register_ipcns_notifier(struct ipc_namespace *ns) | 
|  | 70 | { | 
| Nadia Derbey | 9eefe52 | 2008-07-25 01:48:08 -0700 | [diff] [blame] | 71 | int rc; | 
|  | 72 |  | 
| Nadia Derbey | 6546bc4 | 2008-04-29 01:00:45 -0700 | [diff] [blame] | 73 | memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb)); | 
|  | 74 | ns->ipcns_nb.notifier_call = ipcns_callback; | 
|  | 75 | ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI; | 
| Nadia Derbey | 9eefe52 | 2008-07-25 01:48:08 -0700 | [diff] [blame] | 76 | rc = blocking_notifier_chain_cond_register(&ipcns_chain, | 
| Nadia Derbey | 6546bc4 | 2008-04-29 01:00:45 -0700 | [diff] [blame] | 77 | &ns->ipcns_nb); | 
| Nadia Derbey | 9eefe52 | 2008-07-25 01:48:08 -0700 | [diff] [blame] | 78 | if (!rc) | 
|  | 79 | ns->auto_msgmni = 1; | 
|  | 80 | return rc; | 
| Nadia Derbey | 6546bc4 | 2008-04-29 01:00:45 -0700 | [diff] [blame] | 81 | } | 
|  | 82 |  | 
| Nadia Derbey | 9eefe52 | 2008-07-25 01:48:08 -0700 | [diff] [blame] | 83 | void unregister_ipcns_notifier(struct ipc_namespace *ns) | 
| Nadia Derbey | b6b337a | 2008-04-29 01:00:42 -0700 | [diff] [blame] | 84 | { | 
| Nadia Derbey | 9eefe52 | 2008-07-25 01:48:08 -0700 | [diff] [blame] | 85 | blocking_notifier_chain_unregister(&ipcns_chain, &ns->ipcns_nb); | 
|  | 86 | ns->auto_msgmni = 0; | 
| Nadia Derbey | b6b337a | 2008-04-29 01:00:42 -0700 | [diff] [blame] | 87 | } | 
|  | 88 |  | 
|  | 89 | int ipcns_notify(unsigned long val) | 
|  | 90 | { | 
|  | 91 | return blocking_notifier_call_chain(&ipcns_chain, val, NULL); | 
|  | 92 | } |