@@ -113,8 +113,10 @@ void *klp_shadow_get(void *obj, unsigned long id)
113
113
}
114
114
EXPORT_SYMBOL_GPL (klp_shadow_get );
115
115
116
- static void * __klp_shadow_get_or_alloc (void * obj , unsigned long id , void * data ,
117
- size_t size , gfp_t gfp_flags , bool warn_on_exist )
116
+ static void * __klp_shadow_get_or_alloc (void * obj , unsigned long id ,
117
+ size_t size , gfp_t gfp_flags ,
118
+ klp_shadow_ctor_t ctor , void * ctor_data ,
119
+ bool warn_on_exist )
118
120
{
119
121
struct klp_shadow * new_shadow ;
120
122
void * shadow_data ;
@@ -125,18 +127,15 @@ static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data,
125
127
if (shadow_data )
126
128
goto exists ;
127
129
128
- /* Allocate a new shadow variable for use inside the lock below */
130
+ /*
131
+ * Allocate a new shadow variable. Fill it with zeroes by default.
132
+ * More complex setting can be done by @ctor function. But it is
133
+ * called only when the buffer is really used (under klp_shadow_lock).
134
+ */
129
135
new_shadow = kzalloc (size + sizeof (* new_shadow ), gfp_flags );
130
136
if (!new_shadow )
131
137
return NULL ;
132
138
133
- new_shadow -> obj = obj ;
134
- new_shadow -> id = id ;
135
-
136
- /* Initialize the shadow variable if data provided */
137
- if (data )
138
- memcpy (new_shadow -> data , data , size );
139
-
140
139
/* Look for <obj, id> again under the lock */
141
140
spin_lock_irqsave (& klp_shadow_lock , flags );
142
141
shadow_data = klp_shadow_get (obj , id );
@@ -150,6 +149,22 @@ static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data,
150
149
goto exists ;
151
150
}
152
151
152
+ new_shadow -> obj = obj ;
153
+ new_shadow -> id = id ;
154
+
155
+ if (ctor ) {
156
+ int err ;
157
+
158
+ err = ctor (obj , new_shadow -> data , ctor_data );
159
+ if (err ) {
160
+ spin_unlock_irqrestore (& klp_shadow_lock , flags );
161
+ kfree (new_shadow );
162
+ pr_err ("Failed to construct shadow variable <%p, %lx> (%d)\n" ,
163
+ obj , id , err );
164
+ return NULL ;
165
+ }
166
+ }
167
+
153
168
/* No <obj, id> found, so attach the newly allocated one */
154
169
hash_add_rcu (klp_shadow_hash , & new_shadow -> node ,
155
170
(unsigned long )new_shadow -> obj );
@@ -170,64 +185,84 @@ static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data,
170
185
* klp_shadow_alloc() - allocate and add a new shadow variable
171
186
* @obj: pointer to parent object
172
187
* @id: data identifier
173
- * @data: pointer to data to attach to parent
174
188
* @size: size of attached data
175
189
* @gfp_flags: GFP mask for allocation
190
+ * @ctor: custom constructor to initialize the shadow data (optional)
191
+ * @ctor_data: pointer to any data needed by @ctor (optional)
192
+ *
193
+ * Allocates @size bytes for new shadow variable data using @gfp_flags.
194
+ * The data are zeroed by default. They are further initialized by @ctor
195
+ * function if it is not NULL. The new shadow variable is then added
196
+ * to the global hashtable.
176
197
*
177
- * Allocates @size bytes for new shadow variable data using @gfp_flags
178
- * and copies @size bytes from @data into the new shadow variable's own
179
- * data space. If @data is NULL, @size bytes are still allocated, but
180
- * no copy is performed. The new shadow variable is then added to the
181
- * global hashtable.
198
+ * If an existing <obj, id> shadow variable can be found, this routine will
199
+ * issue a WARN, exit early and return NULL.
182
200
*
183
- * If an existing <obj, id> shadow variable can be found, this routine
184
- * will issue a WARN, exit early and return NULL.
201
+ * This function guarantees that the constructor function is called only when
202
+ * the variable did not exist before. The cost is that @ctor is called
203
+ * in atomic context under a spin lock.
185
204
*
186
205
* Return: the shadow variable data element, NULL on duplicate or
187
206
* failure.
188
207
*/
189
- void * klp_shadow_alloc (void * obj , unsigned long id , void * data ,
190
- size_t size , gfp_t gfp_flags )
208
+ void * klp_shadow_alloc (void * obj , unsigned long id ,
209
+ size_t size , gfp_t gfp_flags ,
210
+ klp_shadow_ctor_t ctor , void * ctor_data )
191
211
{
192
- return __klp_shadow_get_or_alloc (obj , id , data , size , gfp_flags , true);
212
+ return __klp_shadow_get_or_alloc (obj , id , size , gfp_flags ,
213
+ ctor , ctor_data , true);
193
214
}
194
215
EXPORT_SYMBOL_GPL (klp_shadow_alloc );
195
216
196
217
/**
197
218
* klp_shadow_get_or_alloc() - get existing or allocate a new shadow variable
198
219
* @obj: pointer to parent object
199
220
* @id: data identifier
200
- * @data: pointer to data to attach to parent
201
221
* @size: size of attached data
202
222
* @gfp_flags: GFP mask for allocation
223
+ * @ctor: custom constructor to initialize the shadow data (optional)
224
+ * @ctor_data: pointer to any data needed by @ctor (optional)
203
225
*
204
226
* Returns a pointer to existing shadow data if an <obj, id> shadow
205
227
* variable is already present. Otherwise, it creates a new shadow
206
228
* variable like klp_shadow_alloc().
207
229
*
208
- * This function guarantees that only one shadow variable exists with
209
- * the given @id for the given @obj. It also guarantees that the shadow
210
- * variable will be initialized by the given @data only when it did not
211
- * exist before .
230
+ * This function guarantees that only one shadow variable exists with the given
231
+ * @id for the given @obj. It also guarantees that the constructor function
232
+ * will be called only when the variable did not exist before. The cost is
233
+ * that @ctor is called in atomic context under a spin lock .
212
234
*
213
235
* Return: the shadow variable data element, NULL on failure.
214
236
*/
215
- void * klp_shadow_get_or_alloc (void * obj , unsigned long id , void * data ,
216
- size_t size , gfp_t gfp_flags )
237
+ void * klp_shadow_get_or_alloc (void * obj , unsigned long id ,
238
+ size_t size , gfp_t gfp_flags ,
239
+ klp_shadow_ctor_t ctor , void * ctor_data )
217
240
{
218
- return __klp_shadow_get_or_alloc (obj , id , data , size , gfp_flags , false);
241
+ return __klp_shadow_get_or_alloc (obj , id , size , gfp_flags ,
242
+ ctor , ctor_data , false);
219
243
}
220
244
EXPORT_SYMBOL_GPL (klp_shadow_get_or_alloc );
221
245
246
+ static void klp_shadow_free_struct (struct klp_shadow * shadow ,
247
+ klp_shadow_dtor_t dtor )
248
+ {
249
+ hash_del_rcu (& shadow -> node );
250
+ if (dtor )
251
+ dtor (shadow -> obj , shadow -> data );
252
+ kfree_rcu (shadow , rcu_head );
253
+ }
254
+
222
255
/**
223
256
* klp_shadow_free() - detach and free a <obj, id> shadow variable
224
257
* @obj: pointer to parent object
225
258
* @id: data identifier
259
+ * @dtor: custom callback that can be used to unregister the variable
260
+ * and/or free data that the shadow variable points to (optional)
226
261
*
227
262
* This function releases the memory for this <obj, id> shadow variable
228
263
* instance, callers should stop referencing it accordingly.
229
264
*/
230
- void klp_shadow_free (void * obj , unsigned long id )
265
+ void klp_shadow_free (void * obj , unsigned long id , klp_shadow_dtor_t dtor )
231
266
{
232
267
struct klp_shadow * shadow ;
233
268
unsigned long flags ;
@@ -239,8 +274,7 @@ void klp_shadow_free(void *obj, unsigned long id)
239
274
(unsigned long )obj ) {
240
275
241
276
if (klp_shadow_match (shadow , obj , id )) {
242
- hash_del_rcu (& shadow -> node );
243
- kfree_rcu (shadow , rcu_head );
277
+ klp_shadow_free_struct (shadow , dtor );
244
278
break ;
245
279
}
246
280
}
@@ -252,11 +286,13 @@ EXPORT_SYMBOL_GPL(klp_shadow_free);
252
286
/**
253
287
* klp_shadow_free_all() - detach and free all <*, id> shadow variables
254
288
* @id: data identifier
289
+ * @dtor: custom callback that can be used to unregister the variable
290
+ * and/or free data that the shadow variable points to (optional)
255
291
*
256
292
* This function releases the memory for all <*, id> shadow variable
257
293
* instances, callers should stop referencing them accordingly.
258
294
*/
259
- void klp_shadow_free_all (unsigned long id )
295
+ void klp_shadow_free_all (unsigned long id , klp_shadow_dtor_t dtor )
260
296
{
261
297
struct klp_shadow * shadow ;
262
298
unsigned long flags ;
@@ -266,10 +302,8 @@ void klp_shadow_free_all(unsigned long id)
266
302
267
303
/* Delete all <*, id> from hash */
268
304
hash_for_each (klp_shadow_hash , i , shadow , node ) {
269
- if (klp_shadow_match (shadow , shadow -> obj , id )) {
270
- hash_del_rcu (& shadow -> node );
271
- kfree_rcu (shadow , rcu_head );
272
- }
305
+ if (klp_shadow_match (shadow , shadow -> obj , id ))
306
+ klp_shadow_free_struct (shadow , dtor );
273
307
}
274
308
275
309
spin_unlock_irqrestore (& klp_shadow_lock , flags );
0 commit comments