diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 170 |
1 files changed, 130 insertions, 40 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 89bd9a6f52ec..2552454609cf 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -170,7 +170,7 @@ static DEFINE_PER_CPU(int, ftrace_shutdown_disable_cpu); | |||
170 | 170 | ||
171 | static DEFINE_SPINLOCK(ftrace_shutdown_lock); | 171 | static DEFINE_SPINLOCK(ftrace_shutdown_lock); |
172 | static DEFINE_MUTEX(ftraced_lock); | 172 | static DEFINE_MUTEX(ftraced_lock); |
173 | static DEFINE_MUTEX(ftrace_filter_lock); | 173 | static DEFINE_MUTEX(ftrace_regex_lock); |
174 | 174 | ||
175 | struct ftrace_page { | 175 | struct ftrace_page { |
176 | struct ftrace_page *next; | 176 | struct ftrace_page *next; |
@@ -337,13 +337,12 @@ static void | |||
337 | __ftrace_replace_code(struct dyn_ftrace *rec, | 337 | __ftrace_replace_code(struct dyn_ftrace *rec, |
338 | unsigned char *old, unsigned char *new, int enable) | 338 | unsigned char *old, unsigned char *new, int enable) |
339 | { | 339 | { |
340 | unsigned long ip; | 340 | unsigned long ip, fl; |
341 | int failed; | 341 | int failed; |
342 | 342 | ||
343 | ip = rec->ip; | 343 | ip = rec->ip; |
344 | 344 | ||
345 | if (ftrace_filtered && enable) { | 345 | if (ftrace_filtered && enable) { |
346 | unsigned long fl; | ||
347 | /* | 346 | /* |
348 | * If filtering is on: | 347 | * If filtering is on: |
349 | * | 348 | * |
@@ -356,13 +355,16 @@ __ftrace_replace_code(struct dyn_ftrace *rec, | |||
356 | * If this record is not set to be filtered | 355 | * If this record is not set to be filtered |
357 | * and it is not enabled do nothing. | 356 | * and it is not enabled do nothing. |
358 | * | 357 | * |
358 | * If this record is set not to trace then | ||
359 | * do nothing. | ||
360 | * | ||
359 | * If this record is not set to be filtered and | 361 | * If this record is not set to be filtered and |
360 | * it is enabled, disable it. | 362 | * it is enabled, disable it. |
361 | */ | 363 | */ |
362 | fl = rec->flags & (FTRACE_FL_FILTER | FTRACE_FL_ENABLED); | 364 | fl = rec->flags & (FTRACE_FL_FILTER | FTRACE_FL_ENABLED); |
363 | 365 | ||
364 | if ((fl == (FTRACE_FL_FILTER | FTRACE_FL_ENABLED)) || | 366 | if ((fl == (FTRACE_FL_FILTER | FTRACE_FL_ENABLED)) || |
365 | (fl == 0)) | 367 | (fl == 0) || (rec->flags & FTRACE_FL_NOTRACE)) |
366 | return; | 368 | return; |
367 | 369 | ||
368 | /* | 370 | /* |
@@ -380,9 +382,17 @@ __ftrace_replace_code(struct dyn_ftrace *rec, | |||
380 | } | 382 | } |
381 | } else { | 383 | } else { |
382 | 384 | ||
383 | if (enable) | 385 | if (enable) { |
386 | /* | ||
387 | * If this record is set not to trace and is | ||
388 | * not enabled, do nothing. | ||
389 | */ | ||
390 | fl = rec->flags & (FTRACE_FL_NOTRACE | FTRACE_FL_ENABLED); | ||
391 | if (fl == FTRACE_FL_NOTRACE) | ||
392 | return; | ||
393 | |||
384 | new = ftrace_call_replace(ip, FTRACE_ADDR); | 394 | new = ftrace_call_replace(ip, FTRACE_ADDR); |
385 | else | 395 | } else |
386 | old = ftrace_call_replace(ip, FTRACE_ADDR); | 396 | old = ftrace_call_replace(ip, FTRACE_ADDR); |
387 | 397 | ||
388 | if (enable) { | 398 | if (enable) { |
@@ -721,6 +731,7 @@ static int __init ftrace_dyn_table_alloc(void) | |||
721 | enum { | 731 | enum { |
722 | FTRACE_ITER_FILTER = (1 << 0), | 732 | FTRACE_ITER_FILTER = (1 << 0), |
723 | FTRACE_ITER_CONT = (1 << 1), | 733 | FTRACE_ITER_CONT = (1 << 1), |
734 | FTRACE_ITER_NOTRACE = (1 << 2), | ||
724 | }; | 735 | }; |
725 | 736 | ||
726 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ | 737 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ |
@@ -754,7 +765,9 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
754 | rec = &iter->pg->records[iter->idx++]; | 765 | rec = &iter->pg->records[iter->idx++]; |
755 | if ((rec->flags & FTRACE_FL_FAILED) || | 766 | if ((rec->flags & FTRACE_FL_FAILED) || |
756 | ((iter->flags & FTRACE_ITER_FILTER) && | 767 | ((iter->flags & FTRACE_ITER_FILTER) && |
757 | !(rec->flags & FTRACE_FL_FILTER))) { | 768 | !(rec->flags & FTRACE_FL_FILTER)) || |
769 | ((iter->flags & FTRACE_ITER_NOTRACE) && | ||
770 | !(rec->flags & FTRACE_FL_NOTRACE))) { | ||
758 | rec = NULL; | 771 | rec = NULL; |
759 | goto retry; | 772 | goto retry; |
760 | } | 773 | } |
@@ -847,22 +860,24 @@ int ftrace_avail_release(struct inode *inode, struct file *file) | |||
847 | return 0; | 860 | return 0; |
848 | } | 861 | } |
849 | 862 | ||
850 | static void ftrace_filter_reset(void) | 863 | static void ftrace_filter_reset(int enable) |
851 | { | 864 | { |
852 | struct ftrace_page *pg; | 865 | struct ftrace_page *pg; |
853 | struct dyn_ftrace *rec; | 866 | struct dyn_ftrace *rec; |
867 | unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; | ||
854 | unsigned i; | 868 | unsigned i; |
855 | 869 | ||
856 | /* keep kstop machine from running */ | 870 | /* keep kstop machine from running */ |
857 | preempt_disable(); | 871 | preempt_disable(); |
858 | ftrace_filtered = 0; | 872 | if (enable) |
873 | ftrace_filtered = 0; | ||
859 | pg = ftrace_pages_start; | 874 | pg = ftrace_pages_start; |
860 | while (pg) { | 875 | while (pg) { |
861 | for (i = 0; i < pg->index; i++) { | 876 | for (i = 0; i < pg->index; i++) { |
862 | rec = &pg->records[i]; | 877 | rec = &pg->records[i]; |
863 | if (rec->flags & FTRACE_FL_FAILED) | 878 | if (rec->flags & FTRACE_FL_FAILED) |
864 | continue; | 879 | continue; |
865 | rec->flags &= ~FTRACE_FL_FILTER; | 880 | rec->flags &= ~type; |
866 | } | 881 | } |
867 | pg = pg->next; | 882 | pg = pg->next; |
868 | } | 883 | } |
@@ -870,7 +885,7 @@ static void ftrace_filter_reset(void) | |||
870 | } | 885 | } |
871 | 886 | ||
872 | static int | 887 | static int |
873 | ftrace_filter_open(struct inode *inode, struct file *file) | 888 | ftrace_regex_open(struct inode *inode, struct file *file, int enable) |
874 | { | 889 | { |
875 | struct ftrace_iterator *iter; | 890 | struct ftrace_iterator *iter; |
876 | int ret = 0; | 891 | int ret = 0; |
@@ -882,15 +897,16 @@ ftrace_filter_open(struct inode *inode, struct file *file) | |||
882 | if (!iter) | 897 | if (!iter) |
883 | return -ENOMEM; | 898 | return -ENOMEM; |
884 | 899 | ||
885 | mutex_lock(&ftrace_filter_lock); | 900 | mutex_lock(&ftrace_regex_lock); |
886 | if ((file->f_mode & FMODE_WRITE) && | 901 | if ((file->f_mode & FMODE_WRITE) && |
887 | !(file->f_flags & O_APPEND)) | 902 | !(file->f_flags & O_APPEND)) |
888 | ftrace_filter_reset(); | 903 | ftrace_filter_reset(enable); |
889 | 904 | ||
890 | if (file->f_mode & FMODE_READ) { | 905 | if (file->f_mode & FMODE_READ) { |
891 | iter->pg = ftrace_pages_start; | 906 | iter->pg = ftrace_pages_start; |
892 | iter->pos = -1; | 907 | iter->pos = -1; |
893 | iter->flags = FTRACE_ITER_FILTER; | 908 | iter->flags = enable ? FTRACE_ITER_FILTER : |
909 | FTRACE_ITER_NOTRACE; | ||
894 | 910 | ||
895 | ret = seq_open(file, &show_ftrace_seq_ops); | 911 | ret = seq_open(file, &show_ftrace_seq_ops); |
896 | if (!ret) { | 912 | if (!ret) { |
@@ -900,13 +916,25 @@ ftrace_filter_open(struct inode *inode, struct file *file) | |||
900 | kfree(iter); | 916 | kfree(iter); |
901 | } else | 917 | } else |
902 | file->private_data = iter; | 918 | file->private_data = iter; |
903 | mutex_unlock(&ftrace_filter_lock); | 919 | mutex_unlock(&ftrace_regex_lock); |
904 | 920 | ||
905 | return ret; | 921 | return ret; |
906 | } | 922 | } |
907 | 923 | ||
924 | static int | ||
925 | ftrace_filter_open(struct inode *inode, struct file *file) | ||
926 | { | ||
927 | return ftrace_regex_open(inode, file, 1); | ||
928 | } | ||
929 | |||
930 | static int | ||
931 | ftrace_notrace_open(struct inode *inode, struct file *file) | ||
932 | { | ||
933 | return ftrace_regex_open(inode, file, 0); | ||
934 | } | ||
935 | |||
908 | static ssize_t | 936 | static ssize_t |
909 | ftrace_filter_read(struct file *file, char __user *ubuf, | 937 | ftrace_regex_read(struct file *file, char __user *ubuf, |
910 | size_t cnt, loff_t *ppos) | 938 | size_t cnt, loff_t *ppos) |
911 | { | 939 | { |
912 | if (file->f_mode & FMODE_READ) | 940 | if (file->f_mode & FMODE_READ) |
@@ -916,7 +944,7 @@ ftrace_filter_read(struct file *file, char __user *ubuf, | |||
916 | } | 944 | } |
917 | 945 | ||
918 | static loff_t | 946 | static loff_t |
919 | ftrace_filter_lseek(struct file *file, loff_t offset, int origin) | 947 | ftrace_regex_lseek(struct file *file, loff_t offset, int origin) |
920 | { | 948 | { |
921 | loff_t ret; | 949 | loff_t ret; |
922 | 950 | ||
@@ -936,13 +964,14 @@ enum { | |||
936 | }; | 964 | }; |
937 | 965 | ||
938 | static void | 966 | static void |
939 | ftrace_match(unsigned char *buff, int len) | 967 | ftrace_match(unsigned char *buff, int len, int enable) |
940 | { | 968 | { |
941 | char str[KSYM_SYMBOL_LEN]; | 969 | char str[KSYM_SYMBOL_LEN]; |
942 | char *search = NULL; | 970 | char *search = NULL; |
943 | struct ftrace_page *pg; | 971 | struct ftrace_page *pg; |
944 | struct dyn_ftrace *rec; | 972 | struct dyn_ftrace *rec; |
945 | int type = MATCH_FULL; | 973 | int type = MATCH_FULL; |
974 | unsigned long flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; | ||
946 | unsigned i, match = 0, search_len = 0; | 975 | unsigned i, match = 0, search_len = 0; |
947 | 976 | ||
948 | for (i = 0; i < len; i++) { | 977 | for (i = 0; i < len; i++) { |
@@ -966,7 +995,8 @@ ftrace_match(unsigned char *buff, int len) | |||
966 | 995 | ||
967 | /* keep kstop machine from running */ | 996 | /* keep kstop machine from running */ |
968 | preempt_disable(); | 997 | preempt_disable(); |
969 | ftrace_filtered = 1; | 998 | if (enable) |
999 | ftrace_filtered = 1; | ||
970 | pg = ftrace_pages_start; | 1000 | pg = ftrace_pages_start; |
971 | while (pg) { | 1001 | while (pg) { |
972 | for (i = 0; i < pg->index; i++) { | 1002 | for (i = 0; i < pg->index; i++) { |
@@ -997,7 +1027,7 @@ ftrace_match(unsigned char *buff, int len) | |||
997 | break; | 1027 | break; |
998 | } | 1028 | } |
999 | if (matched) | 1029 | if (matched) |
1000 | rec->flags |= FTRACE_FL_FILTER; | 1030 | rec->flags |= flag; |
1001 | } | 1031 | } |
1002 | pg = pg->next; | 1032 | pg = pg->next; |
1003 | } | 1033 | } |
@@ -1005,8 +1035,8 @@ ftrace_match(unsigned char *buff, int len) | |||
1005 | } | 1035 | } |
1006 | 1036 | ||
1007 | static ssize_t | 1037 | static ssize_t |
1008 | ftrace_filter_write(struct file *file, const char __user *ubuf, | 1038 | ftrace_regex_write(struct file *file, const char __user *ubuf, |
1009 | size_t cnt, loff_t *ppos) | 1039 | size_t cnt, loff_t *ppos, int enable) |
1010 | { | 1040 | { |
1011 | struct ftrace_iterator *iter; | 1041 | struct ftrace_iterator *iter; |
1012 | char ch; | 1042 | char ch; |
@@ -1016,7 +1046,7 @@ ftrace_filter_write(struct file *file, const char __user *ubuf, | |||
1016 | if (!cnt || cnt < 0) | 1046 | if (!cnt || cnt < 0) |
1017 | return 0; | 1047 | return 0; |
1018 | 1048 | ||
1019 | mutex_lock(&ftrace_filter_lock); | 1049 | mutex_lock(&ftrace_regex_lock); |
1020 | 1050 | ||
1021 | if (file->f_mode & FMODE_READ) { | 1051 | if (file->f_mode & FMODE_READ) { |
1022 | struct seq_file *m = file->private_data; | 1052 | struct seq_file *m = file->private_data; |
@@ -1045,7 +1075,6 @@ ftrace_filter_write(struct file *file, const char __user *ubuf, | |||
1045 | cnt--; | 1075 | cnt--; |
1046 | } | 1076 | } |
1047 | 1077 | ||
1048 | |||
1049 | if (isspace(ch)) { | 1078 | if (isspace(ch)) { |
1050 | file->f_pos += read; | 1079 | file->f_pos += read; |
1051 | ret = read; | 1080 | ret = read; |
@@ -1072,7 +1101,7 @@ ftrace_filter_write(struct file *file, const char __user *ubuf, | |||
1072 | if (isspace(ch)) { | 1101 | if (isspace(ch)) { |
1073 | iter->filtered++; | 1102 | iter->filtered++; |
1074 | iter->buffer[iter->buffer_idx] = 0; | 1103 | iter->buffer[iter->buffer_idx] = 0; |
1075 | ftrace_match(iter->buffer, iter->buffer_idx); | 1104 | ftrace_match(iter->buffer, iter->buffer_idx, enable); |
1076 | iter->buffer_idx = 0; | 1105 | iter->buffer_idx = 0; |
1077 | } else | 1106 | } else |
1078 | iter->flags |= FTRACE_ITER_CONT; | 1107 | iter->flags |= FTRACE_ITER_CONT; |
@@ -1082,11 +1111,39 @@ ftrace_filter_write(struct file *file, const char __user *ubuf, | |||
1082 | 1111 | ||
1083 | ret = read; | 1112 | ret = read; |
1084 | out: | 1113 | out: |
1085 | mutex_unlock(&ftrace_filter_lock); | 1114 | mutex_unlock(&ftrace_regex_lock); |
1086 | 1115 | ||
1087 | return ret; | 1116 | return ret; |
1088 | } | 1117 | } |
1089 | 1118 | ||
1119 | static ssize_t | ||
1120 | ftrace_filter_write(struct file *file, const char __user *ubuf, | ||
1121 | size_t cnt, loff_t *ppos) | ||
1122 | { | ||
1123 | return ftrace_regex_write(file, ubuf, cnt, ppos, 1); | ||
1124 | } | ||
1125 | |||
1126 | static ssize_t | ||
1127 | ftrace_notrace_write(struct file *file, const char __user *ubuf, | ||
1128 | size_t cnt, loff_t *ppos) | ||
1129 | { | ||
1130 | return ftrace_regex_write(file, ubuf, cnt, ppos, 0); | ||
1131 | } | ||
1132 | |||
1133 | static void | ||
1134 | ftrace_set_regex(unsigned char *buf, int len, int reset, int enable) | ||
1135 | { | ||
1136 | if (unlikely(ftrace_disabled)) | ||
1137 | return; | ||
1138 | |||
1139 | mutex_lock(&ftrace_regex_lock); | ||
1140 | if (reset) | ||
1141 | ftrace_filter_reset(enable); | ||
1142 | if (buf) | ||
1143 | ftrace_match(buf, len, enable); | ||
1144 | mutex_unlock(&ftrace_regex_lock); | ||
1145 | } | ||
1146 | |||
1090 | /** | 1147 | /** |
1091 | * ftrace_set_filter - set a function to filter on in ftrace | 1148 | * ftrace_set_filter - set a function to filter on in ftrace |
1092 | * @buf - the string that holds the function filter text. | 1149 | * @buf - the string that holds the function filter text. |
@@ -1098,24 +1155,31 @@ ftrace_filter_write(struct file *file, const char __user *ubuf, | |||
1098 | */ | 1155 | */ |
1099 | void ftrace_set_filter(unsigned char *buf, int len, int reset) | 1156 | void ftrace_set_filter(unsigned char *buf, int len, int reset) |
1100 | { | 1157 | { |
1101 | if (unlikely(ftrace_disabled)) | 1158 | ftrace_set_regex(buf, len, reset, 1); |
1102 | return; | 1159 | } |
1103 | 1160 | ||
1104 | mutex_lock(&ftrace_filter_lock); | 1161 | /** |
1105 | if (reset) | 1162 | * ftrace_set_notrace - set a function to not trace in ftrace |
1106 | ftrace_filter_reset(); | 1163 | * @buf - the string that holds the function notrace text. |
1107 | if (buf) | 1164 | * @len - the length of the string. |
1108 | ftrace_match(buf, len); | 1165 | * @reset - non zero to reset all filters before applying this filter. |
1109 | mutex_unlock(&ftrace_filter_lock); | 1166 | * |
1167 | * Notrace Filters denote which functions should not be enabled when tracing | ||
1168 | * is enabled. If @buf is NULL and reset is set, all functions will be enabled | ||
1169 | * for tracing. | ||
1170 | */ | ||
1171 | void ftrace_set_notrace(unsigned char *buf, int len, int reset) | ||
1172 | { | ||
1173 | ftrace_set_regex(buf, len, reset, 0); | ||
1110 | } | 1174 | } |
1111 | 1175 | ||
1112 | static int | 1176 | static int |
1113 | ftrace_filter_release(struct inode *inode, struct file *file) | 1177 | ftrace_regex_release(struct inode *inode, struct file *file, int enable) |
1114 | { | 1178 | { |
1115 | struct seq_file *m = (struct seq_file *)file->private_data; | 1179 | struct seq_file *m = (struct seq_file *)file->private_data; |
1116 | struct ftrace_iterator *iter; | 1180 | struct ftrace_iterator *iter; |
1117 | 1181 | ||
1118 | mutex_lock(&ftrace_filter_lock); | 1182 | mutex_lock(&ftrace_regex_lock); |
1119 | if (file->f_mode & FMODE_READ) { | 1183 | if (file->f_mode & FMODE_READ) { |
1120 | iter = m->private; | 1184 | iter = m->private; |
1121 | 1185 | ||
@@ -1126,7 +1190,7 @@ ftrace_filter_release(struct inode *inode, struct file *file) | |||
1126 | if (iter->buffer_idx) { | 1190 | if (iter->buffer_idx) { |
1127 | iter->filtered++; | 1191 | iter->filtered++; |
1128 | iter->buffer[iter->buffer_idx] = 0; | 1192 | iter->buffer[iter->buffer_idx] = 0; |
1129 | ftrace_match(iter->buffer, iter->buffer_idx); | 1193 | ftrace_match(iter->buffer, iter->buffer_idx, enable); |
1130 | } | 1194 | } |
1131 | 1195 | ||
1132 | mutex_lock(&ftrace_sysctl_lock); | 1196 | mutex_lock(&ftrace_sysctl_lock); |
@@ -1137,10 +1201,22 @@ ftrace_filter_release(struct inode *inode, struct file *file) | |||
1137 | mutex_unlock(&ftrace_sysctl_lock); | 1201 | mutex_unlock(&ftrace_sysctl_lock); |
1138 | 1202 | ||
1139 | kfree(iter); | 1203 | kfree(iter); |
1140 | mutex_unlock(&ftrace_filter_lock); | 1204 | mutex_unlock(&ftrace_regex_lock); |
1141 | return 0; | 1205 | return 0; |
1142 | } | 1206 | } |
1143 | 1207 | ||
1208 | static int | ||
1209 | ftrace_filter_release(struct inode *inode, struct file *file) | ||
1210 | { | ||
1211 | return ftrace_regex_release(inode, file, 1); | ||
1212 | } | ||
1213 | |||
1214 | static int | ||
1215 | ftrace_notrace_release(struct inode *inode, struct file *file) | ||
1216 | { | ||
1217 | return ftrace_regex_release(inode, file, 0); | ||
1218 | } | ||
1219 | |||
1144 | static struct file_operations ftrace_avail_fops = { | 1220 | static struct file_operations ftrace_avail_fops = { |
1145 | .open = ftrace_avail_open, | 1221 | .open = ftrace_avail_open, |
1146 | .read = seq_read, | 1222 | .read = seq_read, |
@@ -1150,12 +1226,20 @@ static struct file_operations ftrace_avail_fops = { | |||
1150 | 1226 | ||
1151 | static struct file_operations ftrace_filter_fops = { | 1227 | static struct file_operations ftrace_filter_fops = { |
1152 | .open = ftrace_filter_open, | 1228 | .open = ftrace_filter_open, |
1153 | .read = ftrace_filter_read, | 1229 | .read = ftrace_regex_read, |
1154 | .write = ftrace_filter_write, | 1230 | .write = ftrace_filter_write, |
1155 | .llseek = ftrace_filter_lseek, | 1231 | .llseek = ftrace_regex_lseek, |
1156 | .release = ftrace_filter_release, | 1232 | .release = ftrace_filter_release, |
1157 | }; | 1233 | }; |
1158 | 1234 | ||
1235 | static struct file_operations ftrace_notrace_fops = { | ||
1236 | .open = ftrace_notrace_open, | ||
1237 | .read = ftrace_regex_read, | ||
1238 | .write = ftrace_notrace_write, | ||
1239 | .llseek = ftrace_regex_lseek, | ||
1240 | .release = ftrace_notrace_release, | ||
1241 | }; | ||
1242 | |||
1159 | /** | 1243 | /** |
1160 | * ftrace_force_update - force an update to all recording ftrace functions | 1244 | * ftrace_force_update - force an update to all recording ftrace functions |
1161 | * | 1245 | * |
@@ -1239,6 +1323,12 @@ static __init int ftrace_init_debugfs(void) | |||
1239 | if (!entry) | 1323 | if (!entry) |
1240 | pr_warning("Could not create debugfs " | 1324 | pr_warning("Could not create debugfs " |
1241 | "'set_ftrace_filter' entry\n"); | 1325 | "'set_ftrace_filter' entry\n"); |
1326 | |||
1327 | entry = debugfs_create_file("set_ftrace_notrace", 0644, d_tracer, | ||
1328 | NULL, &ftrace_notrace_fops); | ||
1329 | if (!entry) | ||
1330 | pr_warning("Could not create debugfs " | ||
1331 | "'set_ftrace_notrace' entry\n"); | ||
1242 | return 0; | 1332 | return 0; |
1243 | } | 1333 | } |
1244 | 1334 | ||