diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-17 19:56:17 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-17 19:56:17 -0500 |
commit | fa7f578076a8814caa5371e9f4949e408140766d (patch) | |
tree | 8021be6f956e8a259523c394a01183797ce04422 /ipc | |
parent | 2dcd9c71c1ffa9a036e09047f60e08383bb0abb6 (diff) | |
parent | d1b069f5febc850556cf49e9bb9092d3179c5be5 (diff) |
Merge branch 'akpm' (patches from Andrew)
Merge more updates from Andrew Morton:
- a bit more MM
- procfs updates
- dynamic-debug fixes
- lib/ updates
- checkpatch
- epoll
- nilfs2
- signals
- rapidio
- PID management cleanup and optimization
- kcov updates
- sysvipc updates
- quite a few misc things all over the place
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (94 commits)
EXPERT Kconfig menu: fix broken EXPERT menu
include/asm-generic/topology.h: remove unused parent_node() macro
arch/tile/include/asm/topology.h: remove unused parent_node() macro
arch/sparc/include/asm/topology_64.h: remove unused parent_node() macro
arch/sh/include/asm/topology.h: remove unused parent_node() macro
arch/ia64/include/asm/topology.h: remove unused parent_node() macro
drivers/pcmcia/sa1111_badge4.c: avoid unused function warning
mm: add infrastructure for get_user_pages_fast() benchmarking
sysvipc: make get_maxid O(1) again
sysvipc: properly name ipc_addid() limit parameter
sysvipc: duplicate lock comments wrt ipc_addid()
sysvipc: unteach ids->next_id for !CHECKPOINT_RESTORE
initramfs: use time64_t timestamps
drivers/watchdog: make use of devm_register_reboot_notifier()
kernel/reboot.c: add devm_register_reboot_notifier()
kcov: update documentation
Makefile: support flag -fsanitizer-coverage=trace-cmp
kcov: support comparison operands collection
kcov: remove pointless current != NULL check
kernel/panic.c: add TAINT_AUX
...
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/sem.c | 1 | ||||
-rw-r--r-- | ipc/shm.c | 1 | ||||
-rw-r--r-- | ipc/util.c | 97 | ||||
-rw-r--r-- | ipc/util.h | 26 |
4 files changed, 75 insertions, 50 deletions
@@ -515,6 +515,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) | |||
515 | sma->sem_nsems = nsems; | 515 | sma->sem_nsems = nsems; |
516 | sma->sem_ctime = ktime_get_real_seconds(); | 516 | sma->sem_ctime = ktime_get_real_seconds(); |
517 | 517 | ||
518 | /* ipc_addid() locks sma upon success. */ | ||
518 | retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni); | 519 | retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni); |
519 | if (retval < 0) { | 520 | if (retval < 0) { |
520 | call_rcu(&sma->sem_perm.rcu, sem_rcu_free); | 521 | call_rcu(&sma->sem_perm.rcu, sem_rcu_free); |
@@ -601,6 +601,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) | |||
601 | shp->shm_file = file; | 601 | shp->shm_file = file; |
602 | shp->shm_creator = current; | 602 | shp->shm_creator = current; |
603 | 603 | ||
604 | /* ipc_addid() locks shp upon success. */ | ||
604 | error = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); | 605 | error = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); |
605 | if (error < 0) | 606 | if (error < 0) |
606 | goto no_id; | 607 | goto no_id; |
diff --git a/ipc/util.c b/ipc/util.c index 79b30eee32cd..ff045fec8d83 100644 --- a/ipc/util.c +++ b/ipc/util.c | |||
@@ -116,13 +116,16 @@ int ipc_init_ids(struct ipc_ids *ids) | |||
116 | int err; | 116 | int err; |
117 | ids->in_use = 0; | 117 | ids->in_use = 0; |
118 | ids->seq = 0; | 118 | ids->seq = 0; |
119 | ids->next_id = -1; | ||
120 | init_rwsem(&ids->rwsem); | 119 | init_rwsem(&ids->rwsem); |
121 | err = rhashtable_init(&ids->key_ht, &ipc_kht_params); | 120 | err = rhashtable_init(&ids->key_ht, &ipc_kht_params); |
122 | if (err) | 121 | if (err) |
123 | return err; | 122 | return err; |
124 | idr_init(&ids->ipcs_idr); | 123 | idr_init(&ids->ipcs_idr); |
125 | ids->tables_initialized = true; | 124 | ids->tables_initialized = true; |
125 | ids->max_id = -1; | ||
126 | #ifdef CONFIG_CHECKPOINT_RESTORE | ||
127 | ids->next_id = -1; | ||
128 | #endif | ||
126 | return 0; | 129 | return 0; |
127 | } | 130 | } |
128 | 131 | ||
@@ -186,41 +189,51 @@ static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key) | |||
186 | return NULL; | 189 | return NULL; |
187 | } | 190 | } |
188 | 191 | ||
189 | /** | 192 | #ifdef CONFIG_CHECKPOINT_RESTORE |
190 | * ipc_get_maxid - get the last assigned id | 193 | /* |
191 | * @ids: ipc identifier set | 194 | * Specify desired id for next allocated IPC object. |
192 | * | ||
193 | * Called with ipc_ids.rwsem held. | ||
194 | */ | 195 | */ |
195 | int ipc_get_maxid(struct ipc_ids *ids) | 196 | #define ipc_idr_alloc(ids, new) \ |
197 | idr_alloc(&(ids)->ipcs_idr, (new), \ | ||
198 | (ids)->next_id < 0 ? 0 : ipcid_to_idx((ids)->next_id),\ | ||
199 | 0, GFP_NOWAIT) | ||
200 | |||
201 | static inline int ipc_buildid(int id, struct ipc_ids *ids, | ||
202 | struct kern_ipc_perm *new) | ||
196 | { | 203 | { |
197 | struct kern_ipc_perm *ipc; | 204 | if (ids->next_id < 0) { /* default, behave as !CHECKPOINT_RESTORE */ |
198 | int max_id = -1; | 205 | new->seq = ids->seq++; |
199 | int total, id; | 206 | if (ids->seq > IPCID_SEQ_MAX) |
207 | ids->seq = 0; | ||
208 | } else { | ||
209 | new->seq = ipcid_to_seqx(ids->next_id); | ||
210 | ids->next_id = -1; | ||
211 | } | ||
200 | 212 | ||
201 | if (ids->in_use == 0) | 213 | return SEQ_MULTIPLIER * new->seq + id; |
202 | return -1; | 214 | } |
203 | 215 | ||
204 | if (ids->in_use == IPCMNI) | 216 | #else |
205 | return IPCMNI - 1; | 217 | #define ipc_idr_alloc(ids, new) \ |
218 | idr_alloc(&(ids)->ipcs_idr, (new), 0, 0, GFP_NOWAIT) | ||
206 | 219 | ||
207 | /* Look for the last assigned id */ | 220 | static inline int ipc_buildid(int id, struct ipc_ids *ids, |
208 | total = 0; | 221 | struct kern_ipc_perm *new) |
209 | for (id = 0; id < IPCMNI && total < ids->in_use; id++) { | 222 | { |
210 | ipc = idr_find(&ids->ipcs_idr, id); | 223 | new->seq = ids->seq++; |
211 | if (ipc != NULL) { | 224 | if (ids->seq > IPCID_SEQ_MAX) |
212 | max_id = id; | 225 | ids->seq = 0; |
213 | total++; | 226 | |
214 | } | 227 | return SEQ_MULTIPLIER * new->seq + id; |
215 | } | ||
216 | return max_id; | ||
217 | } | 228 | } |
218 | 229 | ||
230 | #endif /* CONFIG_CHECKPOINT_RESTORE */ | ||
231 | |||
219 | /** | 232 | /** |
220 | * ipc_addid - add an ipc identifier | 233 | * ipc_addid - add an ipc identifier |
221 | * @ids: ipc identifier set | 234 | * @ids: ipc identifier set |
222 | * @new: new ipc permission set | 235 | * @new: new ipc permission set |
223 | * @size: limit for the number of used ids | 236 | * @limit: limit for the number of used ids |
224 | * | 237 | * |
225 | * Add an entry 'new' to the ipc ids idr. The permissions object is | 238 | * Add an entry 'new' to the ipc ids idr. The permissions object is |
226 | * initialised and the first free entry is set up and the id assigned | 239 | * initialised and the first free entry is set up and the id assigned |
@@ -229,17 +242,16 @@ int ipc_get_maxid(struct ipc_ids *ids) | |||
229 | * | 242 | * |
230 | * Called with writer ipc_ids.rwsem held. | 243 | * Called with writer ipc_ids.rwsem held. |
231 | */ | 244 | */ |
232 | int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size) | 245 | int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit) |
233 | { | 246 | { |
234 | kuid_t euid; | 247 | kuid_t euid; |
235 | kgid_t egid; | 248 | kgid_t egid; |
236 | int id, err; | 249 | int id, err; |
237 | int next_id = ids->next_id; | ||
238 | 250 | ||
239 | if (size > IPCMNI) | 251 | if (limit > IPCMNI) |
240 | size = IPCMNI; | 252 | limit = IPCMNI; |
241 | 253 | ||
242 | if (!ids->tables_initialized || ids->in_use >= size) | 254 | if (!ids->tables_initialized || ids->in_use >= limit) |
243 | return -ENOSPC; | 255 | return -ENOSPC; |
244 | 256 | ||
245 | idr_preload(GFP_KERNEL); | 257 | idr_preload(GFP_KERNEL); |
@@ -254,9 +266,7 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size) | |||
254 | new->cuid = new->uid = euid; | 266 | new->cuid = new->uid = euid; |
255 | new->gid = new->cgid = egid; | 267 | new->gid = new->cgid = egid; |
256 | 268 | ||
257 | id = idr_alloc(&ids->ipcs_idr, new, | 269 | id = ipc_idr_alloc(ids, new); |
258 | (next_id < 0) ? 0 : ipcid_to_idx(next_id), 0, | ||
259 | GFP_NOWAIT); | ||
260 | idr_preload_end(); | 270 | idr_preload_end(); |
261 | 271 | ||
262 | if (id >= 0 && new->key != IPC_PRIVATE) { | 272 | if (id >= 0 && new->key != IPC_PRIVATE) { |
@@ -274,17 +284,11 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size) | |||
274 | } | 284 | } |
275 | 285 | ||
276 | ids->in_use++; | 286 | ids->in_use++; |
287 | if (id > ids->max_id) | ||
288 | ids->max_id = id; | ||
277 | 289 | ||
278 | if (next_id < 0) { | 290 | new->id = ipc_buildid(id, ids, new); |
279 | new->seq = ids->seq++; | ||
280 | if (ids->seq > IPCID_SEQ_MAX) | ||
281 | ids->seq = 0; | ||
282 | } else { | ||
283 | new->seq = ipcid_to_seqx(next_id); | ||
284 | ids->next_id = -1; | ||
285 | } | ||
286 | 291 | ||
287 | new->id = ipc_buildid(id, new->seq); | ||
288 | return id; | 292 | return id; |
289 | } | 293 | } |
290 | 294 | ||
@@ -429,6 +433,15 @@ void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp) | |||
429 | ipc_kht_remove(ids, ipcp); | 433 | ipc_kht_remove(ids, ipcp); |
430 | ids->in_use--; | 434 | ids->in_use--; |
431 | ipcp->deleted = true; | 435 | ipcp->deleted = true; |
436 | |||
437 | if (unlikely(lid == ids->max_id)) { | ||
438 | do { | ||
439 | lid--; | ||
440 | if (lid == -1) | ||
441 | break; | ||
442 | } while (!idr_find(&ids->ipcs_idr, lid)); | ||
443 | ids->max_id = lid; | ||
444 | } | ||
432 | } | 445 | } |
433 | 446 | ||
434 | /** | 447 | /** |
diff --git a/ipc/util.h b/ipc/util.h index 579112d90016..89b8ec176fc4 100644 --- a/ipc/util.h +++ b/ipc/util.h | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/unistd.h> | 14 | #include <linux/unistd.h> |
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/ipc_namespace.h> | ||
16 | 17 | ||
17 | #define SEQ_MULTIPLIER (IPCMNI) | 18 | #define SEQ_MULTIPLIER (IPCMNI) |
18 | 19 | ||
@@ -99,9 +100,6 @@ void __init ipc_init_proc_interface(const char *path, const char *header, | |||
99 | /* must be called with ids->rwsem acquired for writing */ | 100 | /* must be called with ids->rwsem acquired for writing */ |
100 | int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); | 101 | int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); |
101 | 102 | ||
102 | /* must be called with ids->rwsem acquired for reading */ | ||
103 | int ipc_get_maxid(struct ipc_ids *); | ||
104 | |||
105 | /* must be called with both locks acquired. */ | 103 | /* must be called with both locks acquired. */ |
106 | void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *); | 104 | void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *); |
107 | 105 | ||
@@ -111,6 +109,23 @@ void ipc_set_key_private(struct ipc_ids *, struct kern_ipc_perm *); | |||
111 | /* must be called with ipcp locked */ | 109 | /* must be called with ipcp locked */ |
112 | int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg); | 110 | int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg); |
113 | 111 | ||
112 | /** | ||
113 | * ipc_get_maxid - get the last assigned id | ||
114 | * @ids: ipc identifier set | ||
115 | * | ||
116 | * Called with ipc_ids.rwsem held for reading. | ||
117 | */ | ||
118 | static inline int ipc_get_maxid(struct ipc_ids *ids) | ||
119 | { | ||
120 | if (ids->in_use == 0) | ||
121 | return -1; | ||
122 | |||
123 | if (ids->in_use == IPCMNI) | ||
124 | return IPCMNI - 1; | ||
125 | |||
126 | return ids->max_id; | ||
127 | } | ||
128 | |||
114 | /* | 129 | /* |
115 | * For allocation that need to be freed by RCU. | 130 | * For allocation that need to be freed by RCU. |
116 | * Objects are reference counted, they start with reference count 1. | 131 | * Objects are reference counted, they start with reference count 1. |
@@ -146,11 +161,6 @@ extern struct msg_msg *load_msg(const void __user *src, size_t len); | |||
146 | extern struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst); | 161 | extern struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst); |
147 | extern int store_msg(void __user *dest, struct msg_msg *msg, size_t len); | 162 | extern int store_msg(void __user *dest, struct msg_msg *msg, size_t len); |
148 | 163 | ||
149 | static inline int ipc_buildid(int id, int seq) | ||
150 | { | ||
151 | return SEQ_MULTIPLIER * seq + id; | ||
152 | } | ||
153 | |||
154 | static inline int ipc_checkid(struct kern_ipc_perm *ipcp, int uid) | 164 | static inline int ipc_checkid(struct kern_ipc_perm *ipcp, int uid) |
155 | { | 165 | { |
156 | return uid / SEQ_MULTIPLIER != ipcp->seq; | 166 | return uid / SEQ_MULTIPLIER != ipcp->seq; |