1 /*************************************************************************/ /*!
3 @Title Functions for creating debugfs directories and entries.
4 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @License Dual MIT/GPLv2
7 The contents of this file are subject to the MIT license as set out below.
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
19 Alternatively, the contents of this file may be used under the terms of
20 the GNU General Public License Version 2 ("GPL") in which case the provisions
21 of GPL are applicable instead of those above.
23 If you wish to allow use of your version of this file only under the terms of
24 GPL, and not to allow others to use your version of this file under the terms
25 of the MIT license, indicate your decision by deleting the provisions above
26 and replace them with the notice and other provisions required by GPL as set
27 out in the file called "GPL-COPYING" included in this distribution. If you do
28 not delete the provisions above, a recipient may use your version of this file
29 under the terms of either the MIT license or GPL.
31 This License is also included in this distribution in the file called
34 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
35 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
36 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
37 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
38 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
39 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
40 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41 */ /**************************************************************************/
43 #include <linux/module.h>
44 #include <linux/slab.h>
46 #include "pvr_debug.h"
47 #include "pvr_debugfs.h"
49 #define PVR_DEBUGFS_DIR_NAME "pvr"
51 static struct dentry *gpsPVRDebugFSEntryDir = NULL;
53 /* Lock used when adjusting refCounts and deleting entries */
54 static struct mutex gDebugFSLock;
56 /*************************************************************************/ /*!
57 Statistic entry read functions
58 */ /**************************************************************************/
60 typedef struct _PVR_DEBUGFS_DRIVER_STAT_
63 PVRSRV_GET_NEXT_STAT_FUNC *pfnGetNextStat;
64 PVRSRV_INC_STAT_MEM_REFCOUNT_FUNC *pfnIncStatMemRefCount;
65 PVRSRV_DEC_STAT_MEM_REFCOUNT_FUNC *pfnDecStatMemRefCount;
66 IMG_UINT32 ui32RefCount;
67 IMG_INT32 i32StatValue;
68 IMG_CHAR *pszStatFormat;
69 PVR_DEBUGFS_ENTRY_DATA *pvDebugFSEntry;
70 } PVR_DEBUGFS_DRIVER_STAT;
71 typedef struct _PVR_DEBUGFS_DIR_DATA_
74 PVR_DEBUGFS_DIR_DATA *psParentDir;
75 IMG_UINT32 ui32RefCount;
76 } PVR_DEBUGFS_DIR_DATA;
77 typedef struct _PVR_DEBUGFS_ENTRY_DATA_
79 struct dentry *psEntry;
80 PVR_DEBUGFS_DIR_DATA *psParentDir;
81 IMG_UINT32 ui32RefCount;
82 PVR_DEBUGFS_DRIVER_STAT *psStatData;
83 } PVR_DEBUGFS_ENTRY_DATA;
84 typedef struct _PVR_DEBUGFS_PRIV_DATA_
86 struct seq_operations *psReadOps;
87 PVRSRV_ENTRY_WRITE_FUNC *pfnWrite;
90 PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry;
91 } PVR_DEBUGFS_PRIV_DATA;
92 static void _RefDirEntry(PVR_DEBUGFS_DIR_DATA *psDirEntry);
93 static void _UnrefAndMaybeDestroyDirEntry(PVR_DEBUGFS_DIR_DATA *psDirEntry);
94 static void _UnrefAndMaybeDestroyDirEntryWhileLocked(PVR_DEBUGFS_DIR_DATA *psDirEntry);
95 static IMG_BOOL _RefDebugFSEntryNoLock(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry);
96 static void _UnrefAndMaybeDestroyDebugFSEntry(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry);
97 static IMG_BOOL _RefStatEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry);
98 static IMG_BOOL _UnrefAndMaybeDestroyStatEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry);
100 static void *_DebugFSStatisticSeqStart(struct seq_file *psSeqFile, loff_t *puiPosition)
102 PVR_DEBUGFS_DRIVER_STAT *psStatData = (PVR_DEBUGFS_DRIVER_STAT *)psSeqFile->private;
103 IMG_BOOL bResult = IMG_FALSE;
107 if (psStatData->pvData)
109 /* take reference on psStatData (for duration of stat iteration) */
110 if (!_RefStatEntry((void*)psStatData))
117 bResult = psStatData->pfnGetNextStat(psStatData->pvData,
118 (IMG_UINT32)(*puiPosition),
119 &psStatData->i32StatValue,
120 &psStatData->pszStatFormat);
123 return bResult ? psStatData : NULL;
126 static void _DebugFSStatisticSeqStop(struct seq_file *psSeqFile, void *pvData)
128 PVR_DEBUGFS_DRIVER_STAT *psStatData = (PVR_DEBUGFS_DRIVER_STAT *)psSeqFile->private;
132 /* drop ref taken on stat memory, and if it is now zero, be sure we don't try to read it again */
133 if ((psStatData->ui32RefCount > 0) && (psStatData->pvData))
135 /* drop reference on psStatData (held for duration of stat iteration) */
136 _UnrefAndMaybeDestroyStatEntry((void*)psStatData);
141 static void *_DebugFSStatisticSeqNext(struct seq_file *psSeqFile,
145 PVR_DEBUGFS_DRIVER_STAT *psStatData = (PVR_DEBUGFS_DRIVER_STAT *)psSeqFile->private;
146 IMG_BOOL bResult = IMG_FALSE;
148 if (puiPosition && psStatData && psStatData->pvData)
150 bResult = psStatData->pfnGetNextStat(psStatData->pvData,
151 (IMG_UINT32)(*puiPosition) + 1,
152 &psStatData->i32StatValue,
153 &psStatData->pszStatFormat);
155 if (psStatData->pszStatFormat)
157 IMG_CHAR tmp_buff[1];
158 IMG_INT32 i32Size = snprintf(tmp_buff, 0, psStatData->pszStatFormat,
159 psStatData->i32StatValue);
160 if ((i32Size < 0) || (psSeqFile->size - psSeqFile->count < i32Size))
168 return bResult ? psStatData : NULL;
171 static int _DebugFSStatisticSeqShow(struct seq_file *psSeqFile, void *pvData)
173 PVR_DEBUGFS_DRIVER_STAT *psStatData = (PVR_DEBUGFS_DRIVER_STAT *)pvData;
175 if (psStatData != NULL)
179 if (psStatData->pszStatFormat == NULL)
184 if ((ret = seq_printf(psSeqFile, psStatData->pszStatFormat, psStatData->i32StatValue)))
186 PVR_DPF((PVR_DBG_WARNING, "%s: Overflow when writing to seq_file (%d).", __FUNCTION__, ret));
194 static struct seq_operations gsDebugFSStatisticReadOps =
196 .start = _DebugFSStatisticSeqStart,
197 .stop = _DebugFSStatisticSeqStop,
198 .next = _DebugFSStatisticSeqNext,
199 .show = _DebugFSStatisticSeqShow,
203 /*************************************************************************/ /*!
205 */ /**************************************************************************/
207 static int _DebugFSFileOpen(struct inode *psINode, struct file *psFile)
209 PVR_DEBUGFS_PRIV_DATA *psPrivData;
211 IMG_BOOL bRefRet = IMG_FALSE;
212 PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry = NULL;
214 mutex_lock(&gDebugFSLock);
217 psPrivData = (PVR_DEBUGFS_PRIV_DATA *)psINode->i_private;
220 /* Check that psPrivData is still valid to use */
221 if (psPrivData->bValid)
223 psDebugFSEntry = psPrivData->psDebugFSEntry;
225 /* Take ref on stat entry before opening seq file - this ref will be dropped if we
226 * fail to open the seq file or when we close it
230 bRefRet = _RefDebugFSEntryNoLock(psDebugFSEntry);
231 mutex_unlock(&gDebugFSLock);
234 iResult = seq_open(psFile, psPrivData->psReadOps);
237 struct seq_file *psSeqFile = psFile->private_data;
239 psSeqFile->private = psPrivData->pvData;
243 /* Drop ref if we failed to open seq file */
244 _UnrefAndMaybeDestroyDebugFSEntry(psDebugFSEntry);
245 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to seq_open psFile, returning %d", __FUNCTION__, iResult));
251 mutex_unlock(&gDebugFSLock);
256 mutex_unlock(&gDebugFSLock);
261 mutex_unlock(&gDebugFSLock);
267 static int _DebugFSFileClose(struct inode *psINode, struct file *psFile)
270 PVR_DEBUGFS_PRIV_DATA *psPrivData = (PVR_DEBUGFS_PRIV_DATA *)psINode->i_private;
271 PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry = NULL;
275 psDebugFSEntry = psPrivData->psDebugFSEntry;
277 iResult = seq_release(psINode, psFile);
280 _UnrefAndMaybeDestroyDebugFSEntry(psDebugFSEntry);
285 static ssize_t _DebugFSFileWrite(struct file *psFile,
286 const char __user *pszBuffer,
290 struct inode *psINode = psFile->f_path.dentry->d_inode;
291 PVR_DEBUGFS_PRIV_DATA *psPrivData = (PVR_DEBUGFS_PRIV_DATA *)psINode->i_private;
293 if (psPrivData->pfnWrite == NULL)
295 PVR_DPF((PVR_DBG_ERROR, "%s: Called for file '%s', which does not have pfnWrite defined, returning -EIO(%d)", __FUNCTION__, psFile->f_path.dentry->d_iname, -EIO));
299 return psPrivData->pfnWrite(pszBuffer, uiCount, *puiPosition, psPrivData->pvData);
302 static const struct file_operations gsPVRDebugFSFileOps =
304 .owner = THIS_MODULE,
305 .open = _DebugFSFileOpen,
307 .write = _DebugFSFileWrite,
309 .release = _DebugFSFileClose,
313 /*************************************************************************/ /*!
315 */ /**************************************************************************/
317 /*************************************************************************/ /*!
318 @Function PVRDebugFSInit
319 @Description Initialise PVR debugfs support. This should be called before
320 using any PVRDebugFS functions.
321 @Return int On success, returns 0. Otherwise, returns an
323 */ /**************************************************************************/
324 int PVRDebugFSInit(void)
326 PVR_ASSERT(gpsPVRDebugFSEntryDir == NULL);
328 mutex_init(&gDebugFSLock);
330 gpsPVRDebugFSEntryDir = debugfs_create_dir(PVR_DEBUGFS_DIR_NAME, NULL);
331 if (gpsPVRDebugFSEntryDir == NULL)
333 PVR_DPF((PVR_DBG_ERROR,
334 "%s: Cannot create '%s' debugfs root directory",
335 __FUNCTION__, PVR_DEBUGFS_DIR_NAME));
343 /*************************************************************************/ /*!
344 @Function PVRDebugFSDeInit
345 @Description Deinitialise PVR debugfs support. This should be called only
346 if PVRDebugFSInit() has already been called. All debugfs
347 directories and entries should be removed otherwise this
350 */ /**************************************************************************/
351 void PVRDebugFSDeInit(void)
353 PVR_ASSERT(gpsPVRDebugFSEntryDir != NULL);
355 debugfs_remove(gpsPVRDebugFSEntryDir);
356 gpsPVRDebugFSEntryDir = NULL;
357 mutex_destroy(&gDebugFSLock);
360 /*************************************************************************/ /*!
361 @Function PVRDebugFSCreateEntryDir
362 @Description Create a directory for debugfs entries that will be located
363 under the root directory, as created by
364 PVRDebugFSCreateEntries().
365 @Input pszName String containing the name for the directory.
366 @Input psParentDir The parent directory in which to create the new
367 directory. This should either be NULL, meaning it
368 should be created in the root directory, or a
369 pointer to a directory as returned by this
371 @Output ppsDir On success, points to the newly created
373 @Return int On success, returns 0. Otherwise, returns an
375 */ /**************************************************************************/
376 int PVRDebugFSCreateEntryDir(IMG_CHAR *pszName,
377 PVR_DEBUGFS_DIR_DATA *psParentDir,
378 PVR_DEBUGFS_DIR_DATA **ppsNewDir)
380 PVR_DEBUGFS_DIR_DATA *psNewDir;
382 PVR_ASSERT(gpsPVRDebugFSEntryDir != NULL);
384 if (pszName == NULL || ppsNewDir == NULL)
386 PVR_DPF((PVR_DBG_ERROR, "%s: Invalid param", __FUNCTION__));
390 psNewDir = kmalloc(sizeof(*psNewDir), GFP_KERNEL);
392 if (psNewDir == IMG_NULL)
394 PVR_DPF((PVR_DBG_ERROR,
395 "%s: Cannot allocate memory for '%s' pvr_debugfs structure",
396 __FUNCTION__, pszName));
400 psNewDir->psParentDir = psParentDir;
401 psNewDir->psDir = debugfs_create_dir(pszName, (psNewDir->psParentDir) ? psNewDir->psParentDir->psDir : gpsPVRDebugFSEntryDir);
403 if (psNewDir->psDir == NULL)
405 PVR_DPF((PVR_DBG_ERROR,
406 "%s: Cannot create '%s' debugfs directory",
407 __FUNCTION__, pszName));
413 *ppsNewDir = psNewDir;
414 psNewDir->ui32RefCount = 1;
416 /* if parent directory is not gpsPVRDebugFSEntryDir, increment its refCount */
417 if (psNewDir->psParentDir)
419 _RefDirEntry(psNewDir->psParentDir);
424 /*************************************************************************/ /*!
425 @Function PVRDebugFSRemoveEntryDir
426 @Description Remove a directory that was created by
427 PVRDebugFSCreateEntryDir(). Any directories or files created
428 under the directory being removed should be removed first.
429 @Input psDir Pointer representing the directory to be removed.
431 */ /**************************************************************************/
432 void PVRDebugFSRemoveEntryDir(PVR_DEBUGFS_DIR_DATA *psDir)
434 _UnrefAndMaybeDestroyDirEntry(psDir);
437 /*************************************************************************/ /*!
438 @Function PVRDebugFSCreateEntry
439 @Description Create an entry in the specified directory.
440 @Input pszName String containing the name for the entry.
441 @Input psParentDir Pointer from PVRDebugFSCreateEntryDir()
442 representing the directory in which to create
443 the entry or NULL for the root directory.
444 @Input psReadOps Pointer to structure containing the necessary
445 functions to read from the entry.
446 @Input pfnWrite Callback function used to write to the entry.
447 @Input pvData Private data to be passed to the read
448 functions, in the seq_file private member, and
449 the write function callback.
450 @Output ppsNewEntry On success, points to the newly created entry.
451 @Return int On success, returns 0. Otherwise, returns an
453 */ /**************************************************************************/
454 int PVRDebugFSCreateEntry(const char *pszName,
455 PVR_DEBUGFS_DIR_DATA *psParentDir,
456 struct seq_operations *psReadOps,
457 PVRSRV_ENTRY_WRITE_FUNC *pfnWrite,
459 PVR_DEBUGFS_ENTRY_DATA **ppsNewEntry)
461 PVR_DEBUGFS_PRIV_DATA *psPrivData;
462 PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry;
463 struct dentry *psEntry;
466 PVR_ASSERT(gpsPVRDebugFSEntryDir != NULL);
468 psPrivData = kmalloc(sizeof(*psPrivData), GFP_KERNEL);
469 if (psPrivData == NULL)
473 psDebugFSEntry = kmalloc(sizeof(*psDebugFSEntry), GFP_KERNEL);
474 if (psDebugFSEntry == NULL)
480 psPrivData->psReadOps = psReadOps;
481 psPrivData->pfnWrite = pfnWrite;
482 psPrivData->pvData = (void*)pvData;
483 psPrivData->bValid = IMG_TRUE;
484 /* Store ptr to debugFSEntry in psPrivData, so a ref can be taken on it
485 * when the client opens a file */
486 psPrivData->psDebugFSEntry = psDebugFSEntry;
490 if (psReadOps != NULL)
495 if (pfnWrite != NULL)
500 psDebugFSEntry->psParentDir = psParentDir;
501 psDebugFSEntry->ui32RefCount = 1;
502 psDebugFSEntry->psStatData = (PVR_DEBUGFS_DRIVER_STAT*)pvData;
504 if (psDebugFSEntry->psParentDir)
506 /* increment refCount of parent directory */
507 _RefDirEntry(psDebugFSEntry->psParentDir);
510 psEntry = debugfs_create_file(pszName,
512 (psParentDir != NULL) ? psParentDir->psDir : gpsPVRDebugFSEntryDir,
514 &gsPVRDebugFSFileOps);
517 PVR_DPF((PVR_DBG_ERROR,
518 "%s: Cannot create debugfs '%s' file",
519 __FUNCTION__, pszName));
521 return PTR_ERR(psEntry);
524 psDebugFSEntry->psEntry = psEntry;
525 *ppsNewEntry = (void*)psDebugFSEntry;
530 /*************************************************************************/ /*!
531 @Function PVRDebugFSRemoveEntry
532 @Description Removes an entry that was created by PVRDebugFSCreateEntry().
533 @Input psDebugFSEntry Pointer representing the entry to be removed.
535 */ /**************************************************************************/
536 void PVRDebugFSRemoveEntry(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry)
538 _UnrefAndMaybeDestroyDebugFSEntry(psDebugFSEntry);
541 /*************************************************************************/ /*!
542 @Function PVRDebugFSCreateStatisticEntry
543 @Description Create a statistic entry in the specified directory.
544 @Input pszName String containing the name for the entry.
545 @Input psDir Pointer from PVRDebugFSCreateEntryDir()
546 representing the directory in which to create
547 the entry or NULL for the root directory.
548 @Input pfnStatsPrint A callback function used to print all the
549 statistics when reading from the statistic
551 @Input pfnIncStatMemRefCount A callback function used take a
552 reference on the memory backing the
554 @Input pfnDecStatMemRefCount A callback function used drop a
555 reference on the memory backing the
557 @Input pvData Private data to be passed to the provided
560 @Return PVR_DEBUGFS_DRIVER_STAT* On success, a pointer representing
561 the newly created statistic entry.
563 */ /**************************************************************************/
564 PVR_DEBUGFS_DRIVER_STAT *PVRDebugFSCreateStatisticEntry(const char *pszName,
565 PVR_DEBUGFS_DIR_DATA *psDir,
566 PVRSRV_GET_NEXT_STAT_FUNC *pfnGetNextStat,
567 PVRSRV_INC_STAT_MEM_REFCOUNT_FUNC *pfnIncStatMemRefCount,
568 PVRSRV_INC_STAT_MEM_REFCOUNT_FUNC *pfnDecStatMemRefCount,
571 PVR_DEBUGFS_DRIVER_STAT *psStatData;
572 PVR_DEBUGFS_ENTRY_DATA * psDebugFSEntry;
575 if (pszName == NULL || pfnGetNextStat == NULL)
579 if ((pfnIncStatMemRefCount != NULL || pfnDecStatMemRefCount != NULL) && pvData == NULL)
584 psStatData = kzalloc(sizeof(*psStatData), GFP_KERNEL);
585 if (psStatData == NULL)
589 psStatData->pvData = pvData;
590 psStatData->pfnGetNextStat = pfnGetNextStat;
591 psStatData->pfnIncStatMemRefCount = pfnIncStatMemRefCount;
592 psStatData->pfnDecStatMemRefCount = pfnDecStatMemRefCount;
593 psStatData->ui32RefCount = 1;
595 iResult = PVRDebugFSCreateEntry(pszName,
597 &gsDebugFSStatisticReadOps,
606 psStatData->pvDebugFSEntry = (void*)psDebugFSEntry;
608 if (pfnIncStatMemRefCount)
610 /* call function to take reference on the memory holding the stat */
611 psStatData->pfnIncStatMemRefCount((void*)psStatData->pvData);
614 psDebugFSEntry->ui32RefCount = 1;
619 /*************************************************************************/ /*!
620 @Function PVRDebugFSRemoveStatisticEntry
621 @Description Removes a statistic entry that was created by
622 PVRDebugFSCreateStatisticEntry().
623 @Input psStatEntry Pointer representing the statistic entry to be
626 */ /**************************************************************************/
627 void PVRDebugFSRemoveStatisticEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry)
629 /* drop reference on pvStatEntry*/
630 _UnrefAndMaybeDestroyStatEntry(psStatEntry);
633 static void _RefDirEntry(PVR_DEBUGFS_DIR_DATA *psDirEntry)
635 mutex_lock(&gDebugFSLock);
637 if (psDirEntry->ui32RefCount > 0)
639 /* Increment refCount */
640 psDirEntry->ui32RefCount++;
643 mutex_unlock(&gDebugFSLock);
646 static void _UnrefAndMaybeDestroyDirEntryWhileLocked(PVR_DEBUGFS_DIR_DATA *psDirEntry)
648 if (psDirEntry->ui32RefCount > 0)
650 /* Decrement refCount and free if now zero */
651 if (--psDirEntry->ui32RefCount == 0)
653 /* if parent directory is not gpsPVRDebugFSEntryDir, decrement its refCount */
654 debugfs_remove(psDirEntry->psDir);
655 if (psDirEntry->psParentDir)
657 _UnrefAndMaybeDestroyDirEntryWhileLocked(psDirEntry->psParentDir);
664 static void _UnrefAndMaybeDestroyDirEntry(PVR_DEBUGFS_DIR_DATA *psDirEntry)
666 mutex_lock(&gDebugFSLock);
668 if (psDirEntry->ui32RefCount > 0)
670 /* Decrement refCount and free if now zero */
671 if (--psDirEntry->ui32RefCount == 0)
673 /* if parent directory is not gpsPVRDebugFSEntryDir, decrement its refCount */
674 debugfs_remove(psDirEntry->psDir);
675 if (psDirEntry->psParentDir)
677 _UnrefAndMaybeDestroyDirEntryWhileLocked(psDirEntry->psParentDir);
683 mutex_unlock(&gDebugFSLock);
686 static IMG_BOOL _RefDebugFSEntryNoLock(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry)
688 IMG_BOOL bResult = IMG_FALSE;
690 PVR_ASSERT(psDebugFSEntry != NULL);
692 bResult = (psDebugFSEntry->ui32RefCount > 0);
695 /* Increment refCount of psDebugFSEntry */
696 psDebugFSEntry->ui32RefCount++;
702 static void _UnrefAndMaybeDestroyDebugFSEntry(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry)
704 mutex_lock(&gDebugFSLock);
705 /* Decrement refCount of psDebugFSEntry, and free if now zero */
706 PVR_ASSERT(psDebugFSEntry != IMG_NULL);
708 if (psDebugFSEntry->ui32RefCount > 0)
710 if (--psDebugFSEntry->ui32RefCount == 0)
712 struct dentry *psEntry = psDebugFSEntry->psEntry;
716 /* Free any private data that was provided to debugfs_create_file() */
717 if (psEntry->d_inode->i_private != NULL)
719 PVR_DEBUGFS_PRIV_DATA *psPrivData = (PVR_DEBUGFS_PRIV_DATA*)psDebugFSEntry->psEntry->d_inode->i_private;
721 psPrivData->bValid = IMG_FALSE;
722 psPrivData->psDebugFSEntry = NULL;
723 kfree(psEntry->d_inode->i_private);
724 psEntry->d_inode->i_private = IMG_NULL;
726 debugfs_remove(psEntry);
729 /* decrement refcount of parent directory */
730 if (psDebugFSEntry->psParentDir)
732 _UnrefAndMaybeDestroyDirEntryWhileLocked(psDebugFSEntry->psParentDir);
735 /* now free the memory allocated for psDebugFSEntry */
736 kfree(psDebugFSEntry);
740 mutex_unlock(&gDebugFSLock);
744 static IMG_BOOL _RefStatEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry)
746 IMG_BOOL bResult = IMG_FALSE;
748 PVR_ASSERT(psStatEntry != NULL);
750 mutex_lock(&gDebugFSLock);
752 bResult = (psStatEntry->ui32RefCount > 0);
755 /* Increment refCount of psStatEntry */
756 psStatEntry->ui32RefCount++;
759 mutex_unlock(&gDebugFSLock);
764 static IMG_BOOL _UnrefAndMaybeDestroyStatEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry)
768 PVR_ASSERT(psStatEntry != IMG_NULL);
770 mutex_lock(&gDebugFSLock);
772 bResult = (psStatEntry->ui32RefCount > 0);
776 /* Decrement refCount of psStatData, and free if now zero */
777 if (--psStatEntry->ui32RefCount == 0)
779 mutex_unlock(&gDebugFSLock);
781 if (psStatEntry->pvDebugFSEntry)
783 _UnrefAndMaybeDestroyDebugFSEntry((PVR_DEBUGFS_ENTRY_DATA*)psStatEntry->pvDebugFSEntry);
785 if (psStatEntry->pfnDecStatMemRefCount)
787 /* call function to drop reference on the memory holding the stat */
788 psStatEntry->pfnDecStatMemRefCount((void*)psStatEntry->pvData);
793 mutex_unlock(&gDebugFSLock);
798 mutex_unlock(&gDebugFSLock);