3838
3939static struct class * devfreq_class ;
4040static struct dentry * devfreq_debugfs ;
41+ static const struct attribute_group gov_attr_group ;
4142
4243/*
4344 * devfreq core provides delayed work based load monitoring helper
@@ -784,11 +785,6 @@ static void devfreq_dev_release(struct device *dev)
784785 kfree (devfreq );
785786}
786787
787- static void create_sysfs_files (struct devfreq * devfreq ,
788- const struct devfreq_governor * gov );
789- static void remove_sysfs_files (struct devfreq * devfreq ,
790- const struct devfreq_governor * gov );
791-
792788/**
793789 * devfreq_add_device() - Add devfreq feature to the device
794790 * @dev: the device to add devfreq feature.
@@ -955,7 +951,10 @@ struct devfreq *devfreq_add_device(struct device *dev,
955951 __func__ );
956952 goto err_init ;
957953 }
958- create_sysfs_files (devfreq , devfreq -> governor );
954+
955+ err = sysfs_update_group (& devfreq -> dev .kobj , & gov_attr_group );
956+ if (err )
957+ goto err_init ;
959958
960959 list_add (& devfreq -> node , & devfreq_list );
961960
@@ -994,12 +993,9 @@ int devfreq_remove_device(struct devfreq *devfreq)
994993
995994 devfreq_cooling_unregister (devfreq -> cdev );
996995
997- if (devfreq -> governor ) {
996+ if (devfreq -> governor )
998997 devfreq -> governor -> event_handler (devfreq ,
999998 DEVFREQ_GOV_STOP , NULL );
1000- remove_sysfs_files (devfreq , devfreq -> governor );
1001- }
1002-
1003999 device_unregister (& devfreq -> dev );
10041000
10051001 return 0 ;
@@ -1459,7 +1455,6 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
14591455 __func__ , df -> governor -> name , ret );
14601456 goto out ;
14611457 }
1462- remove_sysfs_files (df , df -> governor );
14631458
14641459 /*
14651460 * Start the new governor and create the specific sysfs files
@@ -1488,7 +1483,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
14881483 * Create the sysfs files for the new governor. But if failed to start
14891484 * the new governor, restore the sysfs files of previous governor.
14901485 */
1491- create_sysfs_files ( df , df -> governor );
1486+ ret = sysfs_update_group ( & df -> dev . kobj , & gov_attr_group );
14921487
14931488out :
14941489 mutex_unlock (& devfreq_list_lock );
@@ -1806,14 +1801,17 @@ static struct attribute *devfreq_attrs[] = {
18061801 & dev_attr_trans_stat .attr ,
18071802 NULL ,
18081803};
1809- ATTRIBUTE_GROUPS (devfreq );
18101804
18111805static ssize_t polling_interval_show (struct device * dev ,
18121806 struct device_attribute * attr , char * buf )
18131807{
18141808 struct devfreq * df = to_devfreq (dev );
18151809
1816- if (!df -> profile )
1810+ /* Protect against race between sysfs attrs update and read/write */
1811+ guard (mutex )(& devfreq_list_lock );
1812+
1813+ if (!df -> profile || !df -> governor ||
1814+ !IS_SUPPORTED_ATTR (df -> governor -> attrs , POLLING_INTERVAL ))
18171815 return - EINVAL ;
18181816
18191817 return sprintf (buf , "%d\n" , df -> profile -> polling_ms );
@@ -1827,7 +1825,10 @@ static ssize_t polling_interval_store(struct device *dev,
18271825 unsigned int value ;
18281826 int ret ;
18291827
1830- if (!df -> governor )
1828+ guard (mutex )(& devfreq_list_lock );
1829+
1830+ if (!df -> governor ||
1831+ !IS_SUPPORTED_ATTR (df -> governor -> attrs , POLLING_INTERVAL ))
18311832 return - EINVAL ;
18321833
18331834 ret = sscanf (buf , "%u" , & value );
@@ -1846,7 +1847,10 @@ static ssize_t timer_show(struct device *dev,
18461847{
18471848 struct devfreq * df = to_devfreq (dev );
18481849
1849- if (!df -> profile )
1850+ guard (mutex )(& devfreq_list_lock );
1851+
1852+ if (!df -> profile || !df -> governor ||
1853+ !IS_SUPPORTED_ATTR (df -> governor -> attrs , TIMER ))
18501854 return - EINVAL ;
18511855
18521856 return sprintf (buf , "%s\n" , timer_name [df -> profile -> timer ]);
@@ -1860,7 +1864,10 @@ static ssize_t timer_store(struct device *dev, struct device_attribute *attr,
18601864 int timer = -1 ;
18611865 int ret = 0 , i ;
18621866
1863- if (!df -> governor || !df -> profile )
1867+ guard (mutex )(& devfreq_list_lock );
1868+
1869+ if (!df -> governor || !df -> profile ||
1870+ !IS_SUPPORTED_ATTR (df -> governor -> attrs , TIMER ))
18641871 return - EINVAL ;
18651872
18661873 ret = sscanf (buf , "%16s" , str_timer );
@@ -1904,37 +1911,47 @@ static ssize_t timer_store(struct device *dev, struct device_attribute *attr,
19041911}
19051912static DEVICE_ATTR_RW (timer );
19061913
1907- #define CREATE_SYSFS_FILE (df , name ) \
1908- { \
1909- int ret; \
1910- ret = sysfs_create_file(&df->dev.kobj, &dev_attr_##name.attr); \
1911- if (ret < 0) { \
1912- dev_warn(&df->dev, \
1913- "Unable to create attr(%s)\n", "##name"); \
1914- } \
1915- } \
1914+ static struct attribute * governor_attrs [] = {
1915+ & dev_attr_polling_interval .attr ,
1916+ & dev_attr_timer .attr ,
1917+ NULL
1918+ };
19161919
1917- /* Create the specific sysfs files which depend on each governor. */
1918- static void create_sysfs_files (struct devfreq * devfreq ,
1919- const struct devfreq_governor * gov )
1920+ static umode_t gov_attr_visible (struct kobject * kobj ,
1921+ struct attribute * attr , int n )
19201922{
1921- if (IS_SUPPORTED_ATTR (gov -> attrs , POLLING_INTERVAL ))
1922- CREATE_SYSFS_FILE (devfreq , polling_interval );
1923- if (IS_SUPPORTED_ATTR (gov -> attrs , TIMER ))
1924- CREATE_SYSFS_FILE (devfreq , timer );
1925- }
1923+ struct device * dev = kobj_to_dev (kobj );
1924+ struct devfreq * df = to_devfreq (dev );
19261925
1927- /* Remove the specific sysfs files which depend on each governor. */
1928- static void remove_sysfs_files (struct devfreq * devfreq ,
1929- const struct devfreq_governor * gov )
1930- {
1931- if (IS_SUPPORTED_ATTR (gov -> attrs , POLLING_INTERVAL ))
1932- sysfs_remove_file (& devfreq -> dev .kobj ,
1933- & dev_attr_polling_interval .attr );
1934- if (IS_SUPPORTED_ATTR (gov -> attrs , TIMER ))
1935- sysfs_remove_file (& devfreq -> dev .kobj , & dev_attr_timer .attr );
1926+ if (!df -> governor || !df -> governor -> attrs )
1927+ return 0 ;
1928+
1929+ if (attr == & dev_attr_polling_interval .attr &&
1930+ IS_SUPPORTED_ATTR (df -> governor -> attrs , POLLING_INTERVAL ))
1931+ return attr -> mode ;
1932+
1933+ if (attr == & dev_attr_timer .attr &&
1934+ IS_SUPPORTED_ATTR (df -> governor -> attrs , TIMER ))
1935+ return attr -> mode ;
1936+
1937+ return 0 ;
19361938}
19371939
1940+ static const struct attribute_group devfreq_group = {
1941+ .attrs = devfreq_attrs ,
1942+ };
1943+
1944+ static const struct attribute_group gov_attr_group = {
1945+ .attrs = governor_attrs ,
1946+ .is_visible = gov_attr_visible ,
1947+ };
1948+
1949+ static const struct attribute_group * devfreq_groups [] = {
1950+ & devfreq_group ,
1951+ & gov_attr_group ,
1952+ NULL
1953+ };
1954+
19381955/**
19391956 * devfreq_summary_show() - Show the summary of the devfreq devices
19401957 * @s: seq_file instance to show the summary of devfreq devices
0 commit comments