diff options
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/util.c | 35 | ||||
-rw-r--r-- | ipc/util.h | 8 |
2 files changed, 34 insertions, 9 deletions
diff --git a/ipc/util.c b/ipc/util.c index cf5d1087409e..71f3f3982fc8 100644 --- a/ipc/util.c +++ b/ipc/util.c | |||
@@ -119,6 +119,7 @@ void ipc_init_ids(struct ipc_ids *ids) | |||
119 | rhashtable_init(&ids->key_ht, &ipc_kht_params); | 119 | rhashtable_init(&ids->key_ht, &ipc_kht_params); |
120 | idr_init(&ids->ipcs_idr); | 120 | idr_init(&ids->ipcs_idr); |
121 | ids->max_idx = -1; | 121 | ids->max_idx = -1; |
122 | ids->last_idx = -1; | ||
122 | #ifdef CONFIG_CHECKPOINT_RESTORE | 123 | #ifdef CONFIG_CHECKPOINT_RESTORE |
123 | ids->next_id = -1; | 124 | ids->next_id = -1; |
124 | #endif | 125 | #endif |
@@ -192,6 +193,10 @@ static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key) | |||
192 | * | 193 | * |
193 | * The caller must own kern_ipc_perm.lock.of the new object. | 194 | * The caller must own kern_ipc_perm.lock.of the new object. |
194 | * On error, the function returns a (negative) error code. | 195 | * On error, the function returns a (negative) error code. |
196 | * | ||
197 | * To conserve sequence number space, especially with extended ipc_mni, | ||
198 | * the sequence number is incremented only when the returned ID is less than | ||
199 | * the last one. | ||
195 | */ | 200 | */ |
196 | static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new) | 201 | static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new) |
197 | { | 202 | { |
@@ -215,17 +220,37 @@ static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new) | |||
215 | */ | 220 | */ |
216 | 221 | ||
217 | if (next_id < 0) { /* !CHECKPOINT_RESTORE or next_id is unset */ | 222 | if (next_id < 0) { /* !CHECKPOINT_RESTORE or next_id is unset */ |
218 | new->seq = ids->seq++; | 223 | |
219 | if (ids->seq > IPCID_SEQ_MAX) | 224 | /* allocate the idx, with a NULL struct kern_ipc_perm */ |
220 | ids->seq = 0; | 225 | idx = idr_alloc(&ids->ipcs_idr, NULL, 0, 0, GFP_NOWAIT); |
221 | idx = idr_alloc(&ids->ipcs_idr, new, 0, 0, GFP_NOWAIT); | 226 | |
227 | if (idx >= 0) { | ||
228 | /* | ||
229 | * idx got allocated successfully. | ||
230 | * Now calculate the sequence number and set the | ||
231 | * pointer for real. | ||
232 | */ | ||
233 | if (idx <= ids->last_idx) { | ||
234 | ids->seq++; | ||
235 | if (ids->seq >= ipcid_seq_max()) | ||
236 | ids->seq = 0; | ||
237 | } | ||
238 | ids->last_idx = idx; | ||
239 | |||
240 | new->seq = ids->seq; | ||
241 | /* no need for smp_wmb(), this is done | ||
242 | * inside idr_replace, as part of | ||
243 | * rcu_assign_pointer | ||
244 | */ | ||
245 | idr_replace(&ids->ipcs_idr, new, idx); | ||
246 | } | ||
222 | } else { | 247 | } else { |
223 | new->seq = ipcid_to_seqx(next_id); | 248 | new->seq = ipcid_to_seqx(next_id); |
224 | idx = idr_alloc(&ids->ipcs_idr, new, ipcid_to_idx(next_id), | 249 | idx = idr_alloc(&ids->ipcs_idr, new, ipcid_to_idx(next_id), |
225 | 0, GFP_NOWAIT); | 250 | 0, GFP_NOWAIT); |
226 | } | 251 | } |
227 | if (idx >= 0) | 252 | if (idx >= 0) |
228 | new->id = (new->seq << IPCMNI_SEQ_SHIFT) + idx; | 253 | new->id = (new->seq << ipcmni_seq_shift()) + idx; |
229 | return idx; | 254 | return idx; |
230 | } | 255 | } |
231 | 256 | ||
diff --git a/ipc/util.h b/ipc/util.h index 9746886757de..8c834ed39012 100644 --- a/ipc/util.h +++ b/ipc/util.h | |||
@@ -34,13 +34,13 @@ | |||
34 | extern int ipc_mni; | 34 | extern int ipc_mni; |
35 | extern int ipc_mni_shift; | 35 | extern int ipc_mni_shift; |
36 | 36 | ||
37 | #define IPCMNI_SEQ_SHIFT ipc_mni_shift | 37 | #define ipcmni_seq_shift() ipc_mni_shift |
38 | #define IPCMNI_IDX_MASK ((1 << ipc_mni_shift) - 1) | 38 | #define IPCMNI_IDX_MASK ((1 << ipc_mni_shift) - 1) |
39 | 39 | ||
40 | #else /* CONFIG_SYSVIPC_SYSCTL */ | 40 | #else /* CONFIG_SYSVIPC_SYSCTL */ |
41 | 41 | ||
42 | #define ipc_mni IPCMNI | 42 | #define ipc_mni IPCMNI |
43 | #define IPCMNI_SEQ_SHIFT IPCMNI_SHIFT | 43 | #define ipcmni_seq_shift() IPCMNI_SHIFT |
44 | #define IPCMNI_IDX_MASK ((1 << IPCMNI_SHIFT) - 1) | 44 | #define IPCMNI_IDX_MASK ((1 << IPCMNI_SHIFT) - 1) |
45 | #endif /* CONFIG_SYSVIPC_SYSCTL */ | 45 | #endif /* CONFIG_SYSVIPC_SYSCTL */ |
46 | 46 | ||
@@ -123,8 +123,8 @@ struct pid_namespace *ipc_seq_pid_ns(struct seq_file *); | |||
123 | #define IPC_SHM_IDS 2 | 123 | #define IPC_SHM_IDS 2 |
124 | 124 | ||
125 | #define ipcid_to_idx(id) ((id) & IPCMNI_IDX_MASK) | 125 | #define ipcid_to_idx(id) ((id) & IPCMNI_IDX_MASK) |
126 | #define ipcid_to_seqx(id) ((id) >> IPCMNI_SEQ_SHIFT) | 126 | #define ipcid_to_seqx(id) ((id) >> ipcmni_seq_shift()) |
127 | #define IPCID_SEQ_MAX (INT_MAX >> IPCMNI_SEQ_SHIFT) | 127 | #define ipcid_seq_max() (INT_MAX >> ipcmni_seq_shift()) |
128 | 128 | ||
129 | /* must be called with ids->rwsem acquired for writing */ | 129 | /* must be called with ids->rwsem acquired for writing */ |
130 | int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); | 130 | int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int); |