@@ -31,6 +31,8 @@ struct eventfs_inode {
3131 * struct eventfs_file - hold the properties of the eventfs files and
3232 * directories.
3333 * @name: the name of the file or directory to create
34+ * @d_parent: holds parent's dentry
35+ * @dentry: once accessed holds dentry
3436 * @list: file or directory to be added to parent directory
3537 * @ei: list of files and directories within directory
3638 * @fop: file_operations for file or directory
@@ -40,22 +42,320 @@ struct eventfs_inode {
4042 */
4143struct eventfs_file {
4244 const char * name ;
45+ struct dentry * d_parent ;
46+ struct dentry * dentry ;
4347 struct list_head list ;
4448 struct eventfs_inode * ei ;
4549 const struct file_operations * fop ;
4650 const struct inode_operations * iop ;
51+ union {
52+ struct list_head del_list ; /* list of eventfs_file to delete */
53+ struct rcu_head rcu ; /* eventfs_file to delete */
54+ unsigned long is_freed ; /* Freed if one of the above is set */
55+ };
4756 void * data ;
4857 umode_t mode ;
4958};
5059
5160static DEFINE_MUTEX (eventfs_mutex );
61+ DEFINE_STATIC_SRCU (eventfs_srcu );
62+
63+ static struct dentry * eventfs_root_lookup (struct inode * dir ,
64+ struct dentry * dentry ,
65+ unsigned int flags );
66+ static int dcache_dir_open_wrapper (struct inode * inode , struct file * file );
67+ static int eventfs_release (struct inode * inode , struct file * file );
5268
5369static const struct inode_operations eventfs_root_dir_inode_operations = {
70+ .lookup = eventfs_root_lookup ,
5471};
5572
5673static const struct file_operations eventfs_file_operations = {
74+ .open = dcache_dir_open_wrapper ,
75+ .read = generic_read_dir ,
76+ .iterate_shared = dcache_readdir ,
77+ .llseek = generic_file_llseek ,
78+ .release = eventfs_release ,
79+ };
80+
81+ /**
82+ * create_file - create a file in the tracefs filesystem
83+ * @name: the name of the file to create.
84+ * @mode: the permission that the file should have.
85+ * @parent: parent dentry for this file.
86+ * @data: something that the caller will want to get to later on.
87+ * @fop: struct file_operations that should be used for this file.
88+ *
89+ * This is the basic "create a file" function for tracefs. It allows for a
90+ * wide range of flexibility in creating a file.
91+ *
92+ * This function will return a pointer to a dentry if it succeeds. This
93+ * pointer must be passed to the tracefs_remove() function when the file is
94+ * to be removed (no automatic cleanup happens if your module is unloaded,
95+ * you are responsible here.) If an error occurs, %NULL will be returned.
96+ *
97+ * If tracefs is not enabled in the kernel, the value -%ENODEV will be
98+ * returned.
99+ */
100+ static struct dentry * create_file (const char * name , umode_t mode ,
101+ struct dentry * parent , void * data ,
102+ const struct file_operations * fop )
103+ {
104+ return NULL ;
57105};
58106
107+ /**
108+ * create_dir - create a dir in the tracefs filesystem
109+ * @name: the name of the file to create.
110+ * @parent: parent dentry for this file.
111+ * @data: something that the caller will want to get to later on.
112+ *
113+ * This is the basic "create a dir" function for eventfs. It allows for a
114+ * wide range of flexibility in creating a dir.
115+ *
116+ * This function will return a pointer to a dentry if it succeeds. This
117+ * pointer must be passed to the tracefs_remove() function when the file is
118+ * to be removed (no automatic cleanup happens if your module is unloaded,
119+ * you are responsible here.) If an error occurs, %NULL will be returned.
120+ *
121+ * If tracefs is not enabled in the kernel, the value -%ENODEV will be
122+ * returned.
123+ */
124+ static struct dentry * create_dir (const char * name , struct dentry * parent , void * data )
125+ {
126+ return NULL ;
127+ }
128+
129+ /**
130+ * eventfs_set_ef_status_free - set the ef->status to free
131+ * @dentry: dentry who's status to be freed
132+ *
133+ * eventfs_set_ef_status_free will be called if no more
134+ * references remain
135+ */
136+ void eventfs_set_ef_status_free (struct dentry * dentry )
137+ {
138+ struct tracefs_inode * ti_parent ;
139+ struct eventfs_file * ef ;
140+
141+ mutex_lock (& eventfs_mutex );
142+ ti_parent = get_tracefs (dentry -> d_parent -> d_inode );
143+ if (!ti_parent || !(ti_parent -> flags & TRACEFS_EVENT_INODE ))
144+ goto out ;
145+
146+ ef = dentry -> d_fsdata ;
147+ if (!ef )
148+ goto out ;
149+
150+ dentry -> d_fsdata = NULL ;
151+ ef -> dentry = NULL ;
152+ out :
153+ mutex_unlock (& eventfs_mutex );
154+ }
155+
156+ /**
157+ * eventfs_post_create_dir - post create dir routine
158+ * @ef: eventfs_file of recently created dir
159+ *
160+ * Map the meta-data of files within an eventfs dir to their parent dentry
161+ */
162+ static void eventfs_post_create_dir (struct eventfs_file * ef )
163+ {
164+ struct eventfs_file * ef_child ;
165+ struct tracefs_inode * ti ;
166+
167+ /* srcu lock already held */
168+ /* fill parent-child relation */
169+ list_for_each_entry_srcu (ef_child , & ef -> ei -> e_top_files , list ,
170+ srcu_read_lock_held (& eventfs_srcu )) {
171+ ef_child -> d_parent = ef -> dentry ;
172+ }
173+
174+ ti = get_tracefs (ef -> dentry -> d_inode );
175+ ti -> private = ef -> ei ;
176+ }
177+
178+ /**
179+ * create_dentry - helper function to create dentry
180+ * @ef: eventfs_file of file or directory to create
181+ * @parent: parent dentry
182+ * @lookup: true if called from lookup routine
183+ *
184+ * Used to create a dentry for file/dir, executes post dentry creation routine
185+ */
186+ static struct dentry *
187+ create_dentry (struct eventfs_file * ef , struct dentry * parent , bool lookup )
188+ {
189+ bool invalidate = false;
190+ struct dentry * dentry ;
191+
192+ mutex_lock (& eventfs_mutex );
193+ if (ef -> is_freed ) {
194+ mutex_unlock (& eventfs_mutex );
195+ return NULL ;
196+ }
197+ if (ef -> dentry ) {
198+ dentry = ef -> dentry ;
199+ /* On dir open, up the ref count */
200+ if (!lookup )
201+ dget (dentry );
202+ mutex_unlock (& eventfs_mutex );
203+ return dentry ;
204+ }
205+ mutex_unlock (& eventfs_mutex );
206+
207+ if (!lookup )
208+ inode_lock (parent -> d_inode );
209+
210+ if (ef -> ei )
211+ dentry = create_dir (ef -> name , parent , ef -> data );
212+ else
213+ dentry = create_file (ef -> name , ef -> mode , parent ,
214+ ef -> data , ef -> fop );
215+
216+ if (!lookup )
217+ inode_unlock (parent -> d_inode );
218+
219+ mutex_lock (& eventfs_mutex );
220+ if (IS_ERR_OR_NULL (dentry )) {
221+ /* If the ef was already updated get it */
222+ dentry = ef -> dentry ;
223+ if (dentry && !lookup )
224+ dget (dentry );
225+ mutex_unlock (& eventfs_mutex );
226+ return dentry ;
227+ }
228+
229+ if (!ef -> dentry && !ef -> is_freed ) {
230+ ef -> dentry = dentry ;
231+ if (ef -> ei )
232+ eventfs_post_create_dir (ef );
233+ dentry -> d_fsdata = ef ;
234+ } else {
235+ /* A race here, should try again (unless freed) */
236+ invalidate = true;
237+ }
238+ mutex_unlock (& eventfs_mutex );
239+ if (invalidate )
240+ d_invalidate (dentry );
241+
242+ if (lookup || invalidate )
243+ dput (dentry );
244+
245+ return invalidate ? NULL : dentry ;
246+ }
247+
248+ static bool match_event_file (struct eventfs_file * ef , const char * name )
249+ {
250+ bool ret ;
251+
252+ mutex_lock (& eventfs_mutex );
253+ ret = !ef -> is_freed && strcmp (ef -> name , name ) == 0 ;
254+ mutex_unlock (& eventfs_mutex );
255+
256+ return ret ;
257+ }
258+
259+ /**
260+ * eventfs_root_lookup - lookup routine to create file/dir
261+ * @dir: in which a lookup is being done
262+ * @dentry: file/dir dentry
263+ * @flags: to pass as flags parameter to simple lookup
264+ *
265+ * Used to create a dynamic file/dir within @dir. Use the eventfs_inode
266+ * list of meta data to find the information needed to create the file/dir.
267+ */
268+ static struct dentry * eventfs_root_lookup (struct inode * dir ,
269+ struct dentry * dentry ,
270+ unsigned int flags )
271+ {
272+ struct tracefs_inode * ti ;
273+ struct eventfs_inode * ei ;
274+ struct eventfs_file * ef ;
275+ struct dentry * ret = NULL ;
276+ int idx ;
277+
278+ ti = get_tracefs (dir );
279+ if (!(ti -> flags & TRACEFS_EVENT_INODE ))
280+ return NULL ;
281+
282+ ei = ti -> private ;
283+ idx = srcu_read_lock (& eventfs_srcu );
284+ list_for_each_entry_srcu (ef , & ei -> e_top_files , list ,
285+ srcu_read_lock_held (& eventfs_srcu )) {
286+ if (!match_event_file (ef , dentry -> d_name .name ))
287+ continue ;
288+ ret = simple_lookup (dir , dentry , flags );
289+ create_dentry (ef , ef -> d_parent , true);
290+ break ;
291+ }
292+ srcu_read_unlock (& eventfs_srcu , idx );
293+ return ret ;
294+ }
295+
296+ /**
297+ * eventfs_release - called to release eventfs file/dir
298+ * @inode: inode to be released
299+ * @file: file to be released (not used)
300+ */
301+ static int eventfs_release (struct inode * inode , struct file * file )
302+ {
303+ struct tracefs_inode * ti ;
304+ struct eventfs_inode * ei ;
305+ struct eventfs_file * ef ;
306+ struct dentry * dentry ;
307+ int idx ;
308+
309+ ti = get_tracefs (inode );
310+ if (!(ti -> flags & TRACEFS_EVENT_INODE ))
311+ return - EINVAL ;
312+
313+ ei = ti -> private ;
314+ idx = srcu_read_lock (& eventfs_srcu );
315+ list_for_each_entry_srcu (ef , & ei -> e_top_files , list ,
316+ srcu_read_lock_held (& eventfs_srcu )) {
317+ mutex_lock (& eventfs_mutex );
318+ dentry = ef -> dentry ;
319+ mutex_unlock (& eventfs_mutex );
320+ if (dentry )
321+ dput (dentry );
322+ }
323+ srcu_read_unlock (& eventfs_srcu , idx );
324+ return dcache_dir_close (inode , file );
325+ }
326+
327+ /**
328+ * dcache_dir_open_wrapper - eventfs open wrapper
329+ * @inode: not used
330+ * @file: dir to be opened (to create its child)
331+ *
332+ * Used to dynamically create the file/dir within @file. @file is really a
333+ * directory and all the files/dirs of the children within @file will be
334+ * created. If any of the files/dirs have already been created, their
335+ * reference count will be incremented.
336+ */
337+ static int dcache_dir_open_wrapper (struct inode * inode , struct file * file )
338+ {
339+ struct tracefs_inode * ti ;
340+ struct eventfs_inode * ei ;
341+ struct eventfs_file * ef ;
342+ struct dentry * dentry = file_dentry (file );
343+ struct inode * f_inode = file_inode (file );
344+ int idx ;
345+
346+ ti = get_tracefs (f_inode );
347+ if (!(ti -> flags & TRACEFS_EVENT_INODE ))
348+ return - EINVAL ;
349+
350+ ei = ti -> private ;
351+ idx = srcu_read_lock (& eventfs_srcu );
352+ list_for_each_entry_rcu (ef , & ei -> e_top_files , list ) {
353+ create_dentry (ef , dentry , false);
354+ }
355+ srcu_read_unlock (& eventfs_srcu , idx );
356+ return dcache_dir_open (inode , file );
357+ }
358+
59359/**
60360 * eventfs_prepare_ef - helper function to prepare eventfs_file
61361 * @name: the name of the file/directory to create.
@@ -179,6 +479,7 @@ struct eventfs_file *eventfs_add_subsystem_dir(const char *name,
179479
180480 mutex_lock (& eventfs_mutex );
181481 list_add_tail (& ef -> list , & ei_parent -> e_top_files );
482+ ef -> d_parent = parent ;
182483 mutex_unlock (& eventfs_mutex );
183484 return ef ;
184485}
@@ -206,6 +507,7 @@ struct eventfs_file *eventfs_add_dir(const char *name,
206507
207508 mutex_lock (& eventfs_mutex );
208509 list_add_tail (& ef -> list , & ef_parent -> ei -> e_top_files );
510+ ef -> d_parent = ef_parent -> dentry ;
209511 mutex_unlock (& eventfs_mutex );
210512 return ef ;
211513}
@@ -254,6 +556,7 @@ int eventfs_add_events_file(const char *name, umode_t mode,
254556
255557 mutex_lock (& eventfs_mutex );
256558 list_add_tail (& ef -> list , & ei -> e_top_files );
559+ ef -> d_parent = parent ;
257560 mutex_unlock (& eventfs_mutex );
258561 return 0 ;
259562}
@@ -292,6 +595,7 @@ int eventfs_add_file(const char *name, umode_t mode,
292595
293596 mutex_lock (& eventfs_mutex );
294597 list_add_tail (& ef -> list , & ef_parent -> ei -> e_top_files );
598+ ef -> d_parent = ef_parent -> dentry ;
295599 mutex_unlock (& eventfs_mutex );
296600 return 0 ;
297601}
0 commit comments