11
11
#include <linux/printk.h>
12
12
#include <linux/slab.h>
13
13
#include <linux/sysfs.h>
14
+ #include <linux/workqueue.h>
14
15
15
16
#include "dma-buf-sysfs-stats.h"
16
17
@@ -135,10 +136,51 @@ void dma_buf_uninit_sysfs_statistics(void)
135
136
kset_unregister (dma_buf_stats_kset );
136
137
}
137
138
139
+ static void sysfs_add_workfn (struct work_struct * work )
140
+ {
141
+ /* The ABI would have to change for this to be false, but let's be paranoid. */
142
+ _Static_assert (sizeof (struct kobject ) >= sizeof (struct work_struct ),
143
+ "kobject is smaller than work_struct" );
144
+
145
+ struct dma_buf_sysfs_entry * sysfs_entry =
146
+ container_of ((struct kobject * )work , struct dma_buf_sysfs_entry , kobj );
147
+ struct dma_buf * dmabuf = sysfs_entry -> dmabuf ;
148
+
149
+ /*
150
+ * A dmabuf is ref-counted via its file member. If this handler holds the only
151
+ * reference to the dmabuf, there is no need for sysfs kobject creation. This is an
152
+ * optimization and a race; when the reference count drops to 1 immediately after
153
+ * this check it is not harmful as the sysfs entry will still get cleaned up in
154
+ * dma_buf_stats_teardown, which won't get called until the final dmabuf reference
155
+ * is released, and that can't happen until the end of this function.
156
+ */
157
+ if (file_count (dmabuf -> file ) > 1 ) {
158
+ /*
159
+ * kobject_init_and_add expects kobject to be zero-filled, but we have populated it
160
+ * to trigger this work function.
161
+ */
162
+ memset (& dmabuf -> sysfs_entry -> kobj , 0 , sizeof (dmabuf -> sysfs_entry -> kobj ));
163
+ dmabuf -> sysfs_entry -> kobj .kset = dma_buf_per_buffer_stats_kset ;
164
+ if (kobject_init_and_add (& dmabuf -> sysfs_entry -> kobj , & dma_buf_ktype , NULL ,
165
+ "%lu" , file_inode (dmabuf -> file )-> i_ino )) {
166
+ kobject_put (& dmabuf -> sysfs_entry -> kobj );
167
+ dmabuf -> sysfs_entry = NULL ;
168
+ }
169
+ } else {
170
+ /*
171
+ * Free the sysfs_entry and reset the pointer so dma_buf_stats_teardown doesn't
172
+ * attempt to operate on it.
173
+ */
174
+ kfree (dmabuf -> sysfs_entry );
175
+ dmabuf -> sysfs_entry = NULL ;
176
+ }
177
+ dma_buf_put (dmabuf );
178
+ }
179
+
138
180
int dma_buf_stats_setup (struct dma_buf * dmabuf )
139
181
{
140
182
struct dma_buf_sysfs_entry * sysfs_entry ;
141
- int ret ;
183
+ struct work_struct * work ;
142
184
143
185
if (!dmabuf || !dmabuf -> file )
144
186
return - EINVAL ;
@@ -148,25 +190,21 @@ int dma_buf_stats_setup(struct dma_buf *dmabuf)
148
190
return - EINVAL ;
149
191
}
150
192
151
- sysfs_entry = kzalloc (sizeof (struct dma_buf_sysfs_entry ), GFP_KERNEL );
193
+ sysfs_entry = kmalloc (sizeof (struct dma_buf_sysfs_entry ), GFP_KERNEL );
152
194
if (!sysfs_entry )
153
195
return - ENOMEM ;
154
196
155
- sysfs_entry -> kobj .kset = dma_buf_per_buffer_stats_kset ;
156
197
sysfs_entry -> dmabuf = dmabuf ;
157
-
158
198
dmabuf -> sysfs_entry = sysfs_entry ;
159
199
160
- /* create the directory for buffer stats */
161
- ret = kobject_init_and_add (& sysfs_entry -> kobj , & dma_buf_ktype , NULL ,
162
- "%lu" , file_inode (dmabuf -> file )-> i_ino );
163
- if (ret )
164
- goto err_sysfs_dmabuf ;
200
+ /*
201
+ * The use of kobj as a work_struct is an ugly hack
202
+ * to avoid an ABI break in this frozen kernel.
203
+ */
204
+ work = (struct work_struct * )& dmabuf -> sysfs_entry -> kobj ;
205
+ INIT_WORK (work , sysfs_add_workfn );
206
+ get_dma_buf (dmabuf ); /* This reference will be dropped in sysfs_add_workfn. */
207
+ schedule_work (work );
165
208
166
209
return 0 ;
167
-
168
- err_sysfs_dmabuf :
169
- kobject_put (& sysfs_entry -> kobj );
170
- dmabuf -> sysfs_entry = NULL ;
171
- return ret ;
172
210
}
0 commit comments