.. | .. |
---|
100 | 100 | static const struct rhashtable_params ipc_kht_params = { |
---|
101 | 101 | .head_offset = offsetof(struct kern_ipc_perm, khtnode), |
---|
102 | 102 | .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), |
---|
105 | 104 | .automatic_shrinking = true, |
---|
106 | 105 | }; |
---|
107 | 106 | |
---|
.. | .. |
---|
110 | 109 | * @ids: ipc identifier set |
---|
111 | 110 | * |
---|
112 | 111 | * 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. |
---|
114 | 113 | */ |
---|
115 | 114 | void ipc_init_ids(struct ipc_ids *ids) |
---|
116 | 115 | { |
---|
.. | .. |
---|
120 | 119 | rhashtable_init(&ids->key_ht, &ipc_kht_params); |
---|
121 | 120 | idr_init(&ids->ipcs_idr); |
---|
122 | 121 | ids->max_idx = -1; |
---|
| 122 | + ids->last_idx = -1; |
---|
123 | 123 | #ifdef CONFIG_CHECKPOINT_RESTORE |
---|
124 | 124 | ids->next_id = -1; |
---|
125 | 125 | #endif |
---|
126 | 126 | } |
---|
127 | 127 | |
---|
128 | 128 | #ifdef CONFIG_PROC_FS |
---|
129 | | -static const struct file_operations sysvipc_proc_fops; |
---|
| 129 | +static const struct proc_ops sysvipc_proc_ops; |
---|
130 | 130 | /** |
---|
131 | 131 | * ipc_init_proc_interface - create a proc interface for sysipc types using a seq_file interface. |
---|
132 | 132 | * @path: Path in procfs |
---|
.. | .. |
---|
151 | 151 | pde = proc_create_data(path, |
---|
152 | 152 | S_IRUGO, /* world readable */ |
---|
153 | 153 | NULL, /* parent dir */ |
---|
154 | | - &sysvipc_proc_fops, |
---|
| 154 | + &sysvipc_proc_ops, |
---|
155 | 155 | iface); |
---|
156 | 156 | if (!pde) |
---|
157 | 157 | kfree(iface); |
---|
.. | .. |
---|
193 | 193 | * |
---|
194 | 194 | * The caller must own kern_ipc_perm.lock.of the new object. |
---|
195 | 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. |
---|
196 | 200 | */ |
---|
197 | 201 | static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new) |
---|
198 | 202 | { |
---|
.. | .. |
---|
216 | 220 | */ |
---|
217 | 221 | |
---|
218 | 222 | 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 | + } |
---|
223 | 252 | } else { |
---|
224 | 253 | new->seq = ipcid_to_seqx(next_id); |
---|
225 | 254 | idx = idr_alloc(&ids->ipcs_idr, new, ipcid_to_idx(next_id), |
---|
226 | 255 | 0, GFP_NOWAIT); |
---|
227 | 256 | } |
---|
228 | 257 | if (idx >= 0) |
---|
229 | | - new->id = SEQ_MULTIPLIER * new->seq + idx; |
---|
| 258 | + new->id = (new->seq << ipcmni_seq_shift()) + idx; |
---|
230 | 259 | return idx; |
---|
231 | 260 | } |
---|
232 | 261 | |
---|
.. | .. |
---|
254 | 283 | /* 1) Initialize the refcount so that ipc_rcu_putref works */ |
---|
255 | 284 | refcount_set(&new->refcount, 1); |
---|
256 | 285 | |
---|
257 | | - if (limit > IPCMNI) |
---|
258 | | - limit = IPCMNI; |
---|
| 286 | + if (limit > ipc_mni) |
---|
| 287 | + limit = ipc_mni; |
---|
259 | 288 | |
---|
260 | 289 | if (ids->in_use >= limit) |
---|
261 | 290 | return -ENOSPC; |
---|
.. | .. |
---|
739 | 768 | if (total >= ids->in_use) |
---|
740 | 769 | goto out; |
---|
741 | 770 | |
---|
742 | | - for (; pos < IPCMNI; pos++) { |
---|
| 771 | + for (; pos < ipc_mni; pos++) { |
---|
743 | 772 | ipc = idr_find(&ids->ipcs_idr, pos); |
---|
744 | 773 | if (ipc != NULL) { |
---|
745 | 774 | rcu_read_lock(); |
---|
.. | .. |
---|
855 | 884 | return seq_release_private(inode, file); |
---|
856 | 885 | } |
---|
857 | 886 | |
---|
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, |
---|
863 | 893 | }; |
---|
864 | 894 | #endif /* CONFIG_PROC_FS */ |
---|