2 * Copyright (C) 2021 Oracle.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 #include "smatch_extra.h"
20 #include "smatch_slist.h"
22 static struct void_fn_list
*hooks
;
27 #define __GFP_ATOMIC 0x200u
28 #define ___GFP_DIRECT_RECLAIM 0x400u
30 unsigned long GFP_DIRECT_RECLAIM(void)
32 static unsigned long saved_flags
= -1;
33 struct symbol
*macro_sym
;
35 if (saved_flags
!= -1)
38 macro_sym
= lookup_macro_symbol("___GFP_DIRECT_RECLAIM");
39 if (!macro_sym
|| !macro_sym
->expansion
)
40 return ___GFP_DIRECT_RECLAIM
;
41 if (token_type(macro_sym
->expansion
) != TOKEN_NUMBER
)
42 return ___GFP_DIRECT_RECLAIM
;
44 saved_flags
= strtoul(macro_sym
->expansion
->number
, NULL
, 0);
48 unsigned long GFP_ATOMIC(void)
50 static unsigned long saved_flags
= -1;
51 struct symbol
*macro_sym
;
53 if (saved_flags
!= -1)
56 macro_sym
= lookup_macro_symbol("___GFP_ATOMIC");
57 if (!macro_sym
|| !macro_sym
->expansion
)
59 if (token_type(macro_sym
->expansion
) != TOKEN_NUMBER
)
62 saved_flags
= strtoul(macro_sym
->expansion
->number
, NULL
, 0);
66 static void do_sleep(void)
70 FOR_EACH_PTR(hooks
, fn
) {
72 } END_FOR_EACH_PTR(fn
);
74 set_state(my_id
, "sleep", NULL
, &sleep
);
78 static void match_sleep(const char *fn
, struct expression
*expr
, void *unused
)
83 static void match_might_sleep_fn(const char *fn
, struct expression
*expr
, void *unused
)
85 struct range_list
*rl
;
88 if (!get_implied_rl_from_call_str(expr
, "$0", &rl
))
90 if (!rl_to_sval(rl
, &sval
) || sval
.value
!= 0)
96 static void match_might_sleep_macro(struct statement
*stmt
)
100 macro
= get_macro_name(stmt
->pos
);
102 strcmp(macro
, "might_sleep") != 0)
108 static void select_sleep(struct expression
*call
, struct expression
*arg
, char *key
, char *unused
)
113 static void match_gfp_t(struct expression
*expr
)
115 struct expression
*arg
;
120 param
= get_gfp_param(expr
);
123 arg
= get_argument_from_call_expr(expr
->args
, param
);
124 if (!get_implied_value(arg
, &sval
))
127 if (!(sval
.value
& GFP_DIRECT_RECLAIM()))
129 if (sval
.uvalue
& GFP_ATOMIC())
132 name
= expr_to_str(expr
->fn
);
134 (strncmp(name
, "__xa_", 5) == 0 ||
135 strncmp(name
, "xa_", 3) == 0 ||
136 strcmp(name
, "ttm_bo_swapout") == 0)) {
145 static void insert_sleep(void)
147 if (function_decrements_preempt())
149 if (get_state(my_id
, "sleep", NULL
) != &sleep
)
151 sql_insert_return_implies(SLEEP
, -1, "", "");
154 void add_sleep_callback(void_fn
*fn
)
156 add_ptr_list(&hooks
, fn
);
159 void check_sleep_info(int id
)
163 if (option_project
!= PROJ_KERNEL
)
166 add_function_hook("schedule", &match_sleep
, NULL
);
167 add_function_hook("might_resched", &match_sleep
, NULL
);
168 add_function_hook("__might_sleep", &match_might_sleep_fn
, NULL
);
169 add_function_hook("___might_sleep", &match_might_sleep_fn
, NULL
);
170 add_hook(&match_might_sleep_macro
, STMT_HOOK
);
172 add_hook(&match_gfp_t
, FUNCTION_CALL_HOOK
);
174 all_return_states_hook(&insert_sleep
);
175 select_return_implies_hook(SLEEP
, &select_sleep
);