13
13
#include <linux/delayacct.h>
14
14
#include <linux/pid_namespace.h>
15
15
#include <linux/cgroupstats.h>
16
+ #include <linux/fs_parser.h>
16
17
17
18
#include <trace/events/cgroup.h>
18
19
20
+ #define cg_invalf (fc , fmt , ...) ({ pr_err(fmt, ## __VA_ARGS__); -EINVAL; })
21
+
19
22
/*
20
23
* pidlists linger the following amount before being destroyed. The goal
21
24
* is avoiding frequent destruction in the middle of consecutive read calls
@@ -906,94 +909,117 @@ static int cgroup1_show_options(struct seq_file *seq, struct kernfs_root *kf_roo
906
909
return 0 ;
907
910
}
908
911
909
- int parse_cgroup1_options (char * data , struct cgroup_fs_context * ctx )
910
- {
911
- char * token , * o = data ;
912
- struct cgroup_subsys * ss ;
913
- int i ;
912
+ enum cgroup1_param {
913
+ Opt_all ,
914
+ Opt_clone_children ,
915
+ Opt_cpuset_v2_mode ,
916
+ Opt_name ,
917
+ Opt_none ,
918
+ Opt_noprefix ,
919
+ Opt_release_agent ,
920
+ Opt_xattr ,
921
+ };
914
922
915
- while ((token = strsep (& o , "," )) != NULL ) {
916
- if (!* token )
917
- return - EINVAL ;
918
- if (!strcmp (token , "none" )) {
919
- /* Explicitly have no subsystems */
920
- ctx -> none = true;
921
- continue ;
922
- }
923
- if (!strcmp (token , "all" )) {
924
- ctx -> all_ss = true;
925
- continue ;
926
- }
927
- if (!strcmp (token , "noprefix" )) {
928
- ctx -> flags |= CGRP_ROOT_NOPREFIX ;
929
- continue ;
930
- }
931
- if (!strcmp (token , "clone_children" )) {
932
- ctx -> cpuset_clone_children = true;
933
- continue ;
934
- }
935
- if (!strcmp (token , "cpuset_v2_mode" )) {
936
- ctx -> flags |= CGRP_ROOT_CPUSET_V2_MODE ;
937
- continue ;
938
- }
939
- if (!strcmp (token , "xattr" )) {
940
- ctx -> flags |= CGRP_ROOT_XATTR ;
941
- continue ;
942
- }
943
- if (!strncmp (token , "release_agent=" , 14 )) {
944
- /* Specifying two release agents is forbidden */
945
- if (ctx -> release_agent )
946
- return - EINVAL ;
947
- ctx -> release_agent =
948
- kstrndup (token + 14 , PATH_MAX - 1 , GFP_KERNEL );
949
- if (!ctx -> release_agent )
950
- return - ENOMEM ;
951
- continue ;
952
- }
953
- if (!strncmp (token , "name=" , 5 )) {
954
- const char * name = token + 5 ;
955
-
956
- /* blocked by boot param? */
957
- if (cgroup_no_v1_named )
958
- return - ENOENT ;
959
- /* Can't specify an empty name */
960
- if (!strlen (name ))
961
- return - EINVAL ;
962
- /* Must match [\w.-]+ */
963
- for (i = 0 ; i < strlen (name ); i ++ ) {
964
- char c = name [i ];
965
- if (isalnum (c ))
966
- continue ;
967
- if ((c == '.' ) || (c == '-' ) || (c == '_' ))
968
- continue ;
969
- return - EINVAL ;
970
- }
971
- /* Specifying two names is forbidden */
972
- if (ctx -> name )
973
- return - EINVAL ;
974
- ctx -> name = kstrndup (name ,
975
- MAX_CGROUP_ROOT_NAMELEN - 1 ,
976
- GFP_KERNEL );
977
- if (!ctx -> name )
978
- return - ENOMEM ;
923
+ static const struct fs_parameter_spec cgroup1_param_specs [] = {
924
+ fsparam_flag ("all" , Opt_all ),
925
+ fsparam_flag ("clone_children" , Opt_clone_children ),
926
+ fsparam_flag ("cpuset_v2_mode" , Opt_cpuset_v2_mode ),
927
+ fsparam_string ("name" , Opt_name ),
928
+ fsparam_flag ("none" , Opt_none ),
929
+ fsparam_flag ("noprefix" , Opt_noprefix ),
930
+ fsparam_string ("release_agent" , Opt_release_agent ),
931
+ fsparam_flag ("xattr" , Opt_xattr ),
932
+ {}
933
+ };
979
934
980
- continue ;
981
- }
935
+ const struct fs_parameter_description cgroup1_fs_parameters = {
936
+ .name = "cgroup1" ,
937
+ .specs = cgroup1_param_specs ,
938
+ };
982
939
940
+ int cgroup1_parse_param (struct fs_context * fc , struct fs_parameter * param )
941
+ {
942
+ struct cgroup_fs_context * ctx = cgroup_fc2context (fc );
943
+ struct cgroup_subsys * ss ;
944
+ struct fs_parse_result result ;
945
+ int opt , i ;
946
+
947
+ opt = fs_parse (fc , & cgroup1_fs_parameters , param , & result );
948
+ if (opt == - ENOPARAM ) {
949
+ if (strcmp (param -> key , "source" ) == 0 ) {
950
+ fc -> source = param -> string ;
951
+ param -> string = NULL ;
952
+ return 0 ;
953
+ }
983
954
for_each_subsys (ss , i ) {
984
- if (strcmp (token , ss -> legacy_name ))
955
+ if (strcmp (param -> key , ss -> legacy_name ))
985
956
continue ;
986
957
ctx -> subsys_mask |= (1 << i );
987
- break ;
958
+ return 0 ;
988
959
}
989
- if (i == CGROUP_SUBSYS_COUNT )
960
+ return cg_invalf (fc , "cgroup1: Unknown subsys name '%s'" , param -> key );
961
+ }
962
+ if (opt < 0 )
963
+ return opt ;
964
+
965
+ switch (opt ) {
966
+ case Opt_none :
967
+ /* Explicitly have no subsystems */
968
+ ctx -> none = true;
969
+ break ;
970
+ case Opt_all :
971
+ ctx -> all_ss = true;
972
+ break ;
973
+ case Opt_noprefix :
974
+ ctx -> flags |= CGRP_ROOT_NOPREFIX ;
975
+ break ;
976
+ case Opt_clone_children :
977
+ ctx -> cpuset_clone_children = true;
978
+ break ;
979
+ case Opt_cpuset_v2_mode :
980
+ ctx -> flags |= CGRP_ROOT_CPUSET_V2_MODE ;
981
+ break ;
982
+ case Opt_xattr :
983
+ ctx -> flags |= CGRP_ROOT_XATTR ;
984
+ break ;
985
+ case Opt_release_agent :
986
+ /* Specifying two release agents is forbidden */
987
+ if (ctx -> release_agent )
988
+ return cg_invalf (fc , "cgroup1: release_agent respecified" );
989
+ ctx -> release_agent = param -> string ;
990
+ param -> string = NULL ;
991
+ break ;
992
+ case Opt_name :
993
+ /* blocked by boot param? */
994
+ if (cgroup_no_v1_named )
990
995
return - ENOENT ;
996
+ /* Can't specify an empty name */
997
+ if (!param -> size )
998
+ return cg_invalf (fc , "cgroup1: Empty name" );
999
+ if (param -> size > MAX_CGROUP_ROOT_NAMELEN - 1 )
1000
+ return cg_invalf (fc , "cgroup1: Name too long" );
1001
+ /* Must match [\w.-]+ */
1002
+ for (i = 0 ; i < param -> size ; i ++ ) {
1003
+ char c = param -> string [i ];
1004
+ if (isalnum (c ))
1005
+ continue ;
1006
+ if ((c == '.' ) || (c == '-' ) || (c == '_' ))
1007
+ continue ;
1008
+ return cg_invalf (fc , "cgroup1: Invalid name" );
1009
+ }
1010
+ /* Specifying two names is forbidden */
1011
+ if (ctx -> name )
1012
+ return cg_invalf (fc , "cgroup1: name respecified" );
1013
+ ctx -> name = param -> string ;
1014
+ param -> string = NULL ;
1015
+ break ;
991
1016
}
992
1017
return 0 ;
993
1018
}
994
1019
995
- static int check_cgroupfs_options (struct cgroup_fs_context * ctx )
1020
+ static int check_cgroupfs_options (struct fs_context * fc )
996
1021
{
1022
+ struct cgroup_fs_context * ctx = cgroup_fc2context (fc );
997
1023
u16 mask = U16_MAX ;
998
1024
u16 enabled = 0 ;
999
1025
struct cgroup_subsys * ss ;
@@ -1018,7 +1044,7 @@ static int check_cgroupfs_options(struct cgroup_fs_context *ctx)
1018
1044
if (ctx -> all_ss ) {
1019
1045
/* Mutually exclusive option 'all' + subsystem name */
1020
1046
if (ctx -> subsys_mask )
1021
- return - EINVAL ;
1047
+ return cg_invalf ( fc , "cgroup1: subsys name conflicts with all" ) ;
1022
1048
/* 'all' => select all the subsystems */
1023
1049
ctx -> subsys_mask = enabled ;
1024
1050
}
@@ -1028,19 +1054,19 @@ static int check_cgroupfs_options(struct cgroup_fs_context *ctx)
1028
1054
* empty hierarchies must have a name).
1029
1055
*/
1030
1056
if (!ctx -> subsys_mask && !ctx -> name )
1031
- return - EINVAL ;
1057
+ return cg_invalf ( fc , "cgroup1: Need name or subsystem set" ) ;
1032
1058
1033
1059
/*
1034
1060
* Option noprefix was introduced just for backward compatibility
1035
1061
* with the old cpuset, so we allow noprefix only if mounting just
1036
1062
* the cpuset subsystem.
1037
1063
*/
1038
1064
if ((ctx -> flags & CGRP_ROOT_NOPREFIX ) && (ctx -> subsys_mask & mask ))
1039
- return - EINVAL ;
1065
+ return cg_invalf ( fc , "cgroup1: noprefix used incorrectly" ) ;
1040
1066
1041
1067
/* Can't specify "none" and some subsystems */
1042
1068
if (ctx -> subsys_mask && ctx -> none )
1043
- return - EINVAL ;
1069
+ return cg_invalf ( fc , "cgroup1: none used incorrectly" ) ;
1044
1070
1045
1071
return 0 ;
1046
1072
}
@@ -1056,7 +1082,7 @@ int cgroup1_reconfigure(struct fs_context *fc)
1056
1082
cgroup_lock_and_drain_offline (& cgrp_dfl_root .cgrp );
1057
1083
1058
1084
/* See what subsystems are wanted */
1059
- ret = check_cgroupfs_options (ctx );
1085
+ ret = check_cgroupfs_options (fc );
1060
1086
if (ret )
1061
1087
goto out_unlock ;
1062
1088
@@ -1070,7 +1096,7 @@ int cgroup1_reconfigure(struct fs_context *fc)
1070
1096
/* Don't allow flags or name to change at remount */
1071
1097
if ((ctx -> flags ^ root -> flags ) ||
1072
1098
(ctx -> name && strcmp (ctx -> name , root -> name ))) {
1073
- pr_err ( "option or name mismatch, new: 0x%x \"%s\", old: 0x%x \"%s\"\n " ,
1099
+ cg_invalf ( fc , "option or name mismatch, new: 0x%x \"%s\", old: 0x%x \"%s\"" ,
1074
1100
ctx -> flags , ctx -> name ?: "" , root -> flags , root -> name );
1075
1101
ret = - EINVAL ;
1076
1102
goto out_unlock ;
@@ -1125,7 +1151,7 @@ int cgroup1_get_tree(struct fs_context *fc)
1125
1151
cgroup_lock_and_drain_offline (& cgrp_dfl_root .cgrp );
1126
1152
1127
1153
/* First find the desired set of subsystems */
1128
- ret = check_cgroupfs_options (ctx );
1154
+ ret = check_cgroupfs_options (fc );
1129
1155
if (ret )
1130
1156
goto out_unlock ;
1131
1157
@@ -1192,7 +1218,7 @@ int cgroup1_get_tree(struct fs_context *fc)
1192
1218
* can't create new one without subsys specification.
1193
1219
*/
1194
1220
if (!ctx -> subsys_mask && !ctx -> none ) {
1195
- ret = - EINVAL ;
1221
+ ret = cg_invalf ( fc , "cgroup1: No subsys list or none specified" ) ;
1196
1222
goto out_unlock ;
1197
1223
}
1198
1224
0 commit comments