hc
2024-09-20 cf4ce59b3b70238352c7f1729f0f7223214828ad
kernel/ipc/util.c
....@@ -100,8 +100,7 @@
100100 static const struct rhashtable_params ipc_kht_params = {
101101 .head_offset = offsetof(struct kern_ipc_perm, khtnode),
102102 .key_offset = offsetof(struct kern_ipc_perm, key),
103
- .key_len = FIELD_SIZEOF(struct kern_ipc_perm, key),
104
- .locks_mul = 1,
103
+ .key_len = sizeof_field(struct kern_ipc_perm, key),
105104 .automatic_shrinking = true,
106105 };
107106
....@@ -110,7 +109,7 @@
110109 * @ids: ipc identifier set
111110 *
112111 * Set up the sequence range to use for the ipc identifier range (limited
113
- * below IPCMNI) then initialise the keys hashtable and ids idr.
112
+ * below ipc_mni) then initialise the keys hashtable and ids idr.
114113 */
115114 void ipc_init_ids(struct ipc_ids *ids)
116115 {
....@@ -120,13 +119,14 @@
120119 rhashtable_init(&ids->key_ht, &ipc_kht_params);
121120 idr_init(&ids->ipcs_idr);
122121 ids->max_idx = -1;
122
+ ids->last_idx = -1;
123123 #ifdef CONFIG_CHECKPOINT_RESTORE
124124 ids->next_id = -1;
125125 #endif
126126 }
127127
128128 #ifdef CONFIG_PROC_FS
129
-static const struct file_operations sysvipc_proc_fops;
129
+static const struct proc_ops sysvipc_proc_ops;
130130 /**
131131 * ipc_init_proc_interface - create a proc interface for sysipc types using a seq_file interface.
132132 * @path: Path in procfs
....@@ -151,7 +151,7 @@
151151 pde = proc_create_data(path,
152152 S_IRUGO, /* world readable */
153153 NULL, /* parent dir */
154
- &sysvipc_proc_fops,
154
+ &sysvipc_proc_ops,
155155 iface);
156156 if (!pde)
157157 kfree(iface);
....@@ -193,6 +193,10 @@
193193 *
194194 * The caller must own kern_ipc_perm.lock.of the new object.
195195 * 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.
196200 */
197201 static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new)
198202 {
....@@ -216,17 +220,42 @@
216220 */
217221
218222 if (next_id < 0) { /* !CHECKPOINT_RESTORE or next_id is unset */
219
- new->seq = ids->seq++;
220
- if (ids->seq > IPCID_SEQ_MAX)
221
- ids->seq = 0;
222
- idx = idr_alloc(&ids->ipcs_idr, new, 0, 0, GFP_NOWAIT);
223
+ int max_idx;
224
+
225
+ max_idx = max(ids->in_use*3/2, ipc_min_cycle);
226
+ max_idx = min(max_idx, ipc_mni);
227
+
228
+ /* allocate the idx, with a NULL struct kern_ipc_perm */
229
+ idx = idr_alloc_cyclic(&ids->ipcs_idr, NULL, 0, max_idx,
230
+ GFP_NOWAIT);
231
+
232
+ if (idx >= 0) {
233
+ /*
234
+ * idx got allocated successfully.
235
+ * Now calculate the sequence number and set the
236
+ * pointer for real.
237
+ */
238
+ if (idx <= ids->last_idx) {
239
+ ids->seq++;
240
+ if (ids->seq >= ipcid_seq_max())
241
+ ids->seq = 0;
242
+ }
243
+ ids->last_idx = idx;
244
+
245
+ new->seq = ids->seq;
246
+ /* no need for smp_wmb(), this is done
247
+ * inside idr_replace, as part of
248
+ * rcu_assign_pointer
249
+ */
250
+ idr_replace(&ids->ipcs_idr, new, idx);
251
+ }
223252 } else {
224253 new->seq = ipcid_to_seqx(next_id);
225254 idx = idr_alloc(&ids->ipcs_idr, new, ipcid_to_idx(next_id),
226255 0, GFP_NOWAIT);
227256 }
228257 if (idx >= 0)
229
- new->id = SEQ_MULTIPLIER * new->seq + idx;
258
+ new->id = (new->seq << ipcmni_seq_shift()) + idx;
230259 return idx;
231260 }
232261
....@@ -254,8 +283,8 @@
254283 /* 1) Initialize the refcount so that ipc_rcu_putref works */
255284 refcount_set(&new->refcount, 1);
256285
257
- if (limit > IPCMNI)
258
- limit = IPCMNI;
286
+ if (limit > ipc_mni)
287
+ limit = ipc_mni;
259288
260289 if (ids->in_use >= limit)
261290 return -ENOSPC;
....@@ -739,7 +768,7 @@
739768 if (total >= ids->in_use)
740769 goto out;
741770
742
- for (; pos < IPCMNI; pos++) {
771
+ for (; pos < ipc_mni; pos++) {
743772 ipc = idr_find(&ids->ipcs_idr, pos);
744773 if (ipc != NULL) {
745774 rcu_read_lock();
....@@ -855,10 +884,11 @@
855884 return seq_release_private(inode, file);
856885 }
857886
858
-static const struct file_operations sysvipc_proc_fops = {
859
- .open = sysvipc_proc_open,
860
- .read = seq_read,
861
- .llseek = seq_lseek,
862
- .release = sysvipc_proc_release,
887
+static const struct proc_ops sysvipc_proc_ops = {
888
+ .proc_flags = PROC_ENTRY_PERMANENT,
889
+ .proc_open = sysvipc_proc_open,
890
+ .proc_read = seq_read,
891
+ .proc_lseek = seq_lseek,
892
+ .proc_release = sysvipc_proc_release,
863893 };
864894 #endif /* CONFIG_PROC_FS */