mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-01 08:04:22 +08:00
perf tools fixes for v5.15: first batch
- Fix ip display in 'perf script' when output type != attr->type. - Ignore deprecation warning when using libbpf'sg btf__get_from_id(), fixing the build with libbpf v0.6+. - Make use of FD() robust in libperf, fixing a segfault with 'perf stat --iostat list'. - Initialize addr_location:srcline pointer to NULL when resolving callchain addresses. - Fix fused instruction logic for assembly functions in 'perf annotate'. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQR2GiIUctdOfX2qHhGyPKLppCJ+JwUCYUZ+YgAKCRCyPKLppCJ+ JwF3AP9q5lcFHsYfFYmQj9U5UPIXm9A94Y7/9r5nHbVGig8Y0wEAgIBWHj3paCaZ P0d0MQX7lQ7/wC5o+wlXJueUb0h8ZgE= =uPbL -----END PGP SIGNATURE----- Merge tag 'perf-tools-fixes-for-v5.15-2021-09-18' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux Pull perf tools fixes from Arnaldo Carvalho de Melo: - Fix ip display in 'perf script' when output type != attr->type. - Ignore deprecation warning when using libbpf'sg btf__get_from_id(), fixing the build with libbpf v0.6+. - Make use of FD() robust in libperf, fixing a segfault with 'perf stat --iostat list'. - Initialize addr_location:srcline pointer to NULL when resolving callchain addresses. - Fix fused instruction logic for assembly functions in 'perf annotate'. * tag 'perf-tools-fixes-for-v5.15-2021-09-18' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux: perf bpf: Ignore deprecation warning when using libbpf's btf__get_from_id() libperf evsel: Make use of FD robust. perf machine: Initialize srcline string member in add_location struct perf script: Fix ip display when type != attr->type perf annotate: Fix fused instr logic for assembly functions
This commit is contained in:
commit
d94f395772
@ -43,7 +43,7 @@ void perf_evsel__delete(struct perf_evsel *evsel)
|
|||||||
free(evsel);
|
free(evsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FD(e, x, y) (*(int *) xyarray__entry(e->fd, x, y))
|
#define FD(e, x, y) ((int *) xyarray__entry(e->fd, x, y))
|
||||||
#define MMAP(e, x, y) (e->mmap ? ((struct perf_mmap *) xyarray__entry(e->mmap, x, y)) : NULL)
|
#define MMAP(e, x, y) (e->mmap ? ((struct perf_mmap *) xyarray__entry(e->mmap, x, y)) : NULL)
|
||||||
|
|
||||||
int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
|
int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
|
||||||
@ -54,7 +54,10 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
|
|||||||
int cpu, thread;
|
int cpu, thread;
|
||||||
for (cpu = 0; cpu < ncpus; cpu++) {
|
for (cpu = 0; cpu < ncpus; cpu++) {
|
||||||
for (thread = 0; thread < nthreads; thread++) {
|
for (thread = 0; thread < nthreads; thread++) {
|
||||||
FD(evsel, cpu, thread) = -1;
|
int *fd = FD(evsel, cpu, thread);
|
||||||
|
|
||||||
|
if (fd)
|
||||||
|
*fd = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,7 +83,7 @@ sys_perf_event_open(struct perf_event_attr *attr,
|
|||||||
static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread, int *group_fd)
|
static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread, int *group_fd)
|
||||||
{
|
{
|
||||||
struct perf_evsel *leader = evsel->leader;
|
struct perf_evsel *leader = evsel->leader;
|
||||||
int fd;
|
int *fd;
|
||||||
|
|
||||||
if (evsel == leader) {
|
if (evsel == leader) {
|
||||||
*group_fd = -1;
|
*group_fd = -1;
|
||||||
@ -95,10 +98,10 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread, int *grou
|
|||||||
return -ENOTCONN;
|
return -ENOTCONN;
|
||||||
|
|
||||||
fd = FD(leader, cpu, thread);
|
fd = FD(leader, cpu, thread);
|
||||||
if (fd == -1)
|
if (fd == NULL || *fd == -1)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
*group_fd = fd;
|
*group_fd = *fd;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -138,7 +141,11 @@ int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
|
|||||||
|
|
||||||
for (cpu = 0; cpu < cpus->nr; cpu++) {
|
for (cpu = 0; cpu < cpus->nr; cpu++) {
|
||||||
for (thread = 0; thread < threads->nr; thread++) {
|
for (thread = 0; thread < threads->nr; thread++) {
|
||||||
int fd, group_fd;
|
int fd, group_fd, *evsel_fd;
|
||||||
|
|
||||||
|
evsel_fd = FD(evsel, cpu, thread);
|
||||||
|
if (evsel_fd == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
err = get_group_fd(evsel, cpu, thread, &group_fd);
|
err = get_group_fd(evsel, cpu, thread, &group_fd);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
@ -151,7 +158,7 @@ int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
|
|||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
FD(evsel, cpu, thread) = fd;
|
*evsel_fd = fd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,9 +170,12 @@ static void perf_evsel__close_fd_cpu(struct perf_evsel *evsel, int cpu)
|
|||||||
int thread;
|
int thread;
|
||||||
|
|
||||||
for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) {
|
for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) {
|
||||||
if (FD(evsel, cpu, thread) >= 0)
|
int *fd = FD(evsel, cpu, thread);
|
||||||
close(FD(evsel, cpu, thread));
|
|
||||||
FD(evsel, cpu, thread) = -1;
|
if (fd && *fd >= 0) {
|
||||||
|
close(*fd);
|
||||||
|
*fd = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,13 +219,12 @@ void perf_evsel__munmap(struct perf_evsel *evsel)
|
|||||||
|
|
||||||
for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) {
|
for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) {
|
||||||
for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
|
for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
|
||||||
int fd = FD(evsel, cpu, thread);
|
int *fd = FD(evsel, cpu, thread);
|
||||||
struct perf_mmap *map = MMAP(evsel, cpu, thread);
|
|
||||||
|
|
||||||
if (fd < 0)
|
if (fd == NULL || *fd < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
perf_mmap__munmap(map);
|
perf_mmap__munmap(MMAP(evsel, cpu, thread));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,15 +248,16 @@ int perf_evsel__mmap(struct perf_evsel *evsel, int pages)
|
|||||||
|
|
||||||
for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) {
|
for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) {
|
||||||
for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
|
for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
|
||||||
int fd = FD(evsel, cpu, thread);
|
int *fd = FD(evsel, cpu, thread);
|
||||||
struct perf_mmap *map = MMAP(evsel, cpu, thread);
|
struct perf_mmap *map;
|
||||||
|
|
||||||
if (fd < 0)
|
if (fd == NULL || *fd < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
map = MMAP(evsel, cpu, thread);
|
||||||
perf_mmap__init(map, NULL, false, NULL);
|
perf_mmap__init(map, NULL, false, NULL);
|
||||||
|
|
||||||
ret = perf_mmap__mmap(map, &mp, fd, cpu);
|
ret = perf_mmap__mmap(map, &mp, *fd, cpu);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
perf_evsel__munmap(evsel);
|
perf_evsel__munmap(evsel);
|
||||||
return ret;
|
return ret;
|
||||||
@ -260,7 +270,9 @@ int perf_evsel__mmap(struct perf_evsel *evsel, int pages)
|
|||||||
|
|
||||||
void *perf_evsel__mmap_base(struct perf_evsel *evsel, int cpu, int thread)
|
void *perf_evsel__mmap_base(struct perf_evsel *evsel, int cpu, int thread)
|
||||||
{
|
{
|
||||||
if (FD(evsel, cpu, thread) < 0 || MMAP(evsel, cpu, thread) == NULL)
|
int *fd = FD(evsel, cpu, thread);
|
||||||
|
|
||||||
|
if (fd == NULL || *fd < 0 || MMAP(evsel, cpu, thread) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return MMAP(evsel, cpu, thread)->base;
|
return MMAP(evsel, cpu, thread)->base;
|
||||||
@ -295,17 +307,18 @@ int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,
|
|||||||
struct perf_counts_values *count)
|
struct perf_counts_values *count)
|
||||||
{
|
{
|
||||||
size_t size = perf_evsel__read_size(evsel);
|
size_t size = perf_evsel__read_size(evsel);
|
||||||
|
int *fd = FD(evsel, cpu, thread);
|
||||||
|
|
||||||
memset(count, 0, sizeof(*count));
|
memset(count, 0, sizeof(*count));
|
||||||
|
|
||||||
if (FD(evsel, cpu, thread) < 0)
|
if (fd == NULL || *fd < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (MMAP(evsel, cpu, thread) &&
|
if (MMAP(evsel, cpu, thread) &&
|
||||||
!perf_mmap__read_self(MMAP(evsel, cpu, thread), count))
|
!perf_mmap__read_self(MMAP(evsel, cpu, thread), count))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (readn(FD(evsel, cpu, thread), count->values, size) <= 0)
|
if (readn(*fd, count->values, size) <= 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -318,8 +331,13 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel,
|
|||||||
int thread;
|
int thread;
|
||||||
|
|
||||||
for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
|
for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
|
||||||
int fd = FD(evsel, cpu, thread),
|
int err;
|
||||||
err = ioctl(fd, ioc, arg);
|
int *fd = FD(evsel, cpu, thread);
|
||||||
|
|
||||||
|
if (fd == NULL || *fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
err = ioctl(*fd, ioc, arg);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -368,16 +368,6 @@ static inline int output_type(unsigned int type)
|
|||||||
return OUTPUT_TYPE_OTHER;
|
return OUTPUT_TYPE_OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned int attr_type(unsigned int type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case OUTPUT_TYPE_SYNTH:
|
|
||||||
return PERF_TYPE_SYNTH;
|
|
||||||
default:
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool output_set_by_user(void)
|
static bool output_set_by_user(void)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
@ -556,6 +546,18 @@ static void set_print_ip_opts(struct perf_event_attr *attr)
|
|||||||
output[type].print_ip_opts |= EVSEL__PRINT_SRCLINE;
|
output[type].print_ip_opts |= EVSEL__PRINT_SRCLINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct evsel *find_first_output_type(struct evlist *evlist,
|
||||||
|
unsigned int type)
|
||||||
|
{
|
||||||
|
struct evsel *evsel;
|
||||||
|
|
||||||
|
evlist__for_each_entry(evlist, evsel) {
|
||||||
|
if (output_type(evsel->core.attr.type) == (int)type)
|
||||||
|
return evsel;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* verify all user requested events exist and the samples
|
* verify all user requested events exist and the samples
|
||||||
* have the expected data
|
* have the expected data
|
||||||
@ -567,7 +569,7 @@ static int perf_session__check_output_opt(struct perf_session *session)
|
|||||||
struct evsel *evsel;
|
struct evsel *evsel;
|
||||||
|
|
||||||
for (j = 0; j < OUTPUT_TYPE_MAX; ++j) {
|
for (j = 0; j < OUTPUT_TYPE_MAX; ++j) {
|
||||||
evsel = perf_session__find_first_evtype(session, attr_type(j));
|
evsel = find_first_output_type(session->evlist, j);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* even if fields is set to 0 (ie., show nothing) event must
|
* even if fields is set to 0 (ie., show nothing) event must
|
||||||
|
@ -757,25 +757,40 @@ void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ui_browser__mark_fused(struct ui_browser *browser, unsigned int column,
|
void ui_browser__mark_fused(struct ui_browser *browser, unsigned int column,
|
||||||
unsigned int row, bool arrow_down)
|
unsigned int row, int diff, bool arrow_down)
|
||||||
{
|
{
|
||||||
unsigned int end_row;
|
int end_row;
|
||||||
|
|
||||||
if (row >= browser->top_idx)
|
if (diff <= 0)
|
||||||
end_row = row - browser->top_idx;
|
|
||||||
else
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SLsmg_set_char_set(1);
|
SLsmg_set_char_set(1);
|
||||||
|
|
||||||
if (arrow_down) {
|
if (arrow_down) {
|
||||||
|
if (row + diff <= browser->top_idx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
end_row = row + diff - browser->top_idx;
|
||||||
ui_browser__gotorc(browser, end_row, column - 1);
|
ui_browser__gotorc(browser, end_row, column - 1);
|
||||||
SLsmg_write_char(SLSMG_ULCORN_CHAR);
|
|
||||||
ui_browser__gotorc(browser, end_row, column);
|
|
||||||
SLsmg_draw_hline(2);
|
|
||||||
ui_browser__gotorc(browser, end_row + 1, column - 1);
|
|
||||||
SLsmg_write_char(SLSMG_LTEE_CHAR);
|
SLsmg_write_char(SLSMG_LTEE_CHAR);
|
||||||
|
|
||||||
|
while (--end_row >= 0 && end_row > (int)(row - browser->top_idx)) {
|
||||||
|
ui_browser__gotorc(browser, end_row, column - 1);
|
||||||
|
SLsmg_draw_vline(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
end_row = (int)(row - browser->top_idx);
|
||||||
|
if (end_row >= 0) {
|
||||||
|
ui_browser__gotorc(browser, end_row, column - 1);
|
||||||
|
SLsmg_write_char(SLSMG_ULCORN_CHAR);
|
||||||
|
ui_browser__gotorc(browser, end_row, column);
|
||||||
|
SLsmg_draw_hline(2);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (row < browser->top_idx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
end_row = row - browser->top_idx;
|
||||||
ui_browser__gotorc(browser, end_row, column - 1);
|
ui_browser__gotorc(browser, end_row, column - 1);
|
||||||
SLsmg_write_char(SLSMG_LTEE_CHAR);
|
SLsmg_write_char(SLSMG_LTEE_CHAR);
|
||||||
ui_browser__gotorc(browser, end_row, column);
|
ui_browser__gotorc(browser, end_row, column);
|
||||||
|
@ -51,7 +51,7 @@ void ui_browser__write_graph(struct ui_browser *browser, int graph);
|
|||||||
void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
|
void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
|
||||||
u64 start, u64 end);
|
u64 start, u64 end);
|
||||||
void ui_browser__mark_fused(struct ui_browser *browser, unsigned int column,
|
void ui_browser__mark_fused(struct ui_browser *browser, unsigned int column,
|
||||||
unsigned int row, bool arrow_down);
|
unsigned int row, int diff, bool arrow_down);
|
||||||
void __ui_browser__show_title(struct ui_browser *browser, const char *title);
|
void __ui_browser__show_title(struct ui_browser *browser, const char *title);
|
||||||
void ui_browser__show_title(struct ui_browser *browser, const char *title);
|
void ui_browser__show_title(struct ui_browser *browser, const char *title);
|
||||||
int ui_browser__show(struct ui_browser *browser, const char *title,
|
int ui_browser__show(struct ui_browser *browser, const char *title,
|
||||||
|
@ -125,13 +125,20 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
|
|||||||
ab->selection = al;
|
ab->selection = al;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
|
static int is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
|
||||||
{
|
{
|
||||||
struct disasm_line *pos = list_prev_entry(cursor, al.node);
|
struct disasm_line *pos = list_prev_entry(cursor, al.node);
|
||||||
const char *name;
|
const char *name;
|
||||||
|
int diff = 1;
|
||||||
|
|
||||||
|
while (pos && pos->al.offset == -1) {
|
||||||
|
pos = list_prev_entry(pos, al.node);
|
||||||
|
if (!ab->opts->hide_src_code)
|
||||||
|
diff++;
|
||||||
|
}
|
||||||
|
|
||||||
if (!pos)
|
if (!pos)
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
if (ins__is_lock(&pos->ins))
|
if (ins__is_lock(&pos->ins))
|
||||||
name = pos->ops.locked.ins.name;
|
name = pos->ops.locked.ins.name;
|
||||||
@ -139,9 +146,11 @@ static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
|
|||||||
name = pos->ins.name;
|
name = pos->ins.name;
|
||||||
|
|
||||||
if (!name || !cursor->ins.name)
|
if (!name || !cursor->ins.name)
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
return ins__is_fused(ab->arch, name, cursor->ins.name);
|
if (ins__is_fused(ab->arch, name, cursor->ins.name))
|
||||||
|
return diff;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void annotate_browser__draw_current_jump(struct ui_browser *browser)
|
static void annotate_browser__draw_current_jump(struct ui_browser *browser)
|
||||||
@ -155,6 +164,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
|
|||||||
struct annotation *notes = symbol__annotation(sym);
|
struct annotation *notes = symbol__annotation(sym);
|
||||||
u8 pcnt_width = annotation__pcnt_width(notes);
|
u8 pcnt_width = annotation__pcnt_width(notes);
|
||||||
int width;
|
int width;
|
||||||
|
int diff = 0;
|
||||||
|
|
||||||
/* PLT symbols contain external offsets */
|
/* PLT symbols contain external offsets */
|
||||||
if (strstr(sym->name, "@plt"))
|
if (strstr(sym->name, "@plt"))
|
||||||
@ -205,11 +215,11 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
|
|||||||
pcnt_width + 2 + notes->widths.addr + width,
|
pcnt_width + 2 + notes->widths.addr + width,
|
||||||
from, to);
|
from, to);
|
||||||
|
|
||||||
if (is_fused(ab, cursor)) {
|
diff = is_fused(ab, cursor);
|
||||||
|
if (diff > 0) {
|
||||||
ui_browser__mark_fused(browser,
|
ui_browser__mark_fused(browser,
|
||||||
pcnt_width + 3 + notes->widths.addr + width,
|
pcnt_width + 3 + notes->widths.addr + width,
|
||||||
from - 1,
|
from - diff, diff, to > from);
|
||||||
to > from);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,10 @@
|
|||||||
struct btf * __weak btf__load_from_kernel_by_id(__u32 id)
|
struct btf * __weak btf__load_from_kernel_by_id(__u32 id)
|
||||||
{
|
{
|
||||||
struct btf *btf;
|
struct btf *btf;
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
int err = btf__get_from_id(id, &btf);
|
int err = btf__get_from_id(id, &btf);
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
return err ? ERR_PTR(err) : btf;
|
return err ? ERR_PTR(err) : btf;
|
||||||
}
|
}
|
||||||
|
@ -2149,6 +2149,7 @@ static int add_callchain_ip(struct thread *thread,
|
|||||||
|
|
||||||
al.filtered = 0;
|
al.filtered = 0;
|
||||||
al.sym = NULL;
|
al.sym = NULL;
|
||||||
|
al.srcline = NULL;
|
||||||
if (!cpumode) {
|
if (!cpumode) {
|
||||||
thread__find_cpumode_addr_location(thread, ip, &al);
|
thread__find_cpumode_addr_location(thread, ip, &al);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user