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 unsigned long GFP_DIRECT_RECLAIM(void)
29 static unsigned long saved_flags
= -1;
30 struct symbol
*macro_sym
;
32 if (saved_flags
!= -1)
35 macro_sym
= lookup_macro_symbol("___GFP_DIRECT_RECLAIM");
36 if (!macro_sym
|| !macro_sym
->expansion
)
38 if (token_type(macro_sym
->expansion
) != TOKEN_NUMBER
)
41 saved_flags
= strtoul(macro_sym
->expansion
->number
, NULL
, 0);
45 static void do_sleep(void)
49 FOR_EACH_PTR(hooks
, fn
) {
51 } END_FOR_EACH_PTR(fn
);
53 set_state(my_id
, "sleep", NULL
, &sleep
);
57 static void match_sleep(const char *fn
, struct expression
*expr
, void *unused
)
62 static void match_might_sleep_fn(const char *fn
, struct expression
*expr
, void *unused
)
64 struct range_list
*rl
;
67 if (!get_implied_rl_from_call_str(expr
, "$0", &rl
))
69 if (!rl_to_sval(rl
, &sval
) || sval
.value
!= 0)
75 static void match_might_sleep_macro(struct statement
*stmt
)
79 macro
= get_macro_name(stmt
->pos
);
81 strcmp(macro
, "might_sleep") != 0)
87 static void select_sleep(struct expression
*call
, struct expression
*arg
, char *key
, char *unused
)
92 static void match_gfp_t(struct expression
*expr
)
94 struct expression
*arg
;
99 param
= get_gfp_param(expr
);
102 arg
= get_argument_from_call_expr(expr
->args
, param
);
103 if (!get_implied_value(arg
, &sval
))
106 if (!(sval
.value
& GFP_DIRECT_RECLAIM()))
109 name
= expr_to_str(expr
->fn
);
111 (strncmp(name
, "__xa_", 5) == 0 ||
112 strncmp(name
, "xa_", 3) == 0 ||
113 strcmp(name
, "ttm_bo_swapout") == 0)) {
122 static void insert_sleep(void)
124 if (function_decrements_preempt())
126 if (get_state(my_id
, "sleep", NULL
) != &sleep
)
128 sql_insert_return_implies(SLEEP
, -1, "", "");
131 void add_sleep_callback(void_fn
*fn
)
133 add_ptr_list(&hooks
, fn
);
136 void check_sleep_info(int id
)
140 if (option_project
!= PROJ_KERNEL
)
143 add_function_hook("schedule", &match_sleep
, NULL
);
144 add_function_hook("msleep", &match_sleep
, NULL
);
145 add_function_hook("might_resched", &match_sleep
, NULL
);
146 add_function_hook("vfree", &match_sleep
, NULL
);
147 add_function_hook("__might_sleep", &match_might_sleep_fn
, NULL
);
148 add_function_hook("___might_sleep", &match_might_sleep_fn
, NULL
);
149 add_hook(&match_might_sleep_macro
, STMT_HOOK
);
151 add_hook(&match_gfp_t
, FUNCTION_CALL_HOOK
);
153 all_return_states_hook(&insert_sleep
);
154 select_return_implies_hook_early(SLEEP
, &select_sleep
);