Skip to content

Commit 1b13351

Browse files
shadichykdave
authored andcommitted
btrfs-progs: add Android compatibility code
Previous Android compatibility was removed in 51f15d3 ("btrfs-progs: build: remove incomplete android support"). - add pthread_cancel() API stubs and pthread_setcanceltype() emulation, since Android NDK does not support it, use pthread_kill() instead - add manual thread state tracking to 'rescue chunk-recover' command using atomics; code is from termux/termux-packages - add stub for qsort_r() using tread-local storage The compatibility code is in common/compat.h and should be include unles the internal APIs include that already (like sort-utils.h or task-utils.h). The CI does not yet verify the Android build yet. Pull-request: #982 Signed-off-by: Shadichy <shadichy@blisslabs.org> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 2bd9212 commit 1b13351

File tree

7 files changed

+189
-1
lines changed

7 files changed

+189
-1
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ objects = \
216216
kernel-shared/volumes.o \
217217
kernel-shared/zoned.o \
218218
common/array.o \
219+
common/compat.o \
219220
common/cpu-utils.o \
220221
common/device-scan.o \
221222
common/device-utils.o \

cmds/rescue-chunk-recover.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,17 @@
3737
#include "kernel-shared/transaction.h"
3838
#include "kernel-shared/extent_io.h"
3939
#include "common/internal.h"
40+
#include "common/compat.h"
4041
#include "common/messages.h"
4142
#include "common/extent-cache.h"
4243
#include "common/utils.h"
4344
#include "cmds/rescue.h"
4445
#include "check/common.h"
4546

47+
#ifdef __ANDROID__
48+
#include <stdatomic.h>
49+
#endif
50+
4651
struct recover_control {
4752
int verbose;
4853
int yes;
@@ -82,6 +87,9 @@ struct device_scan {
8287
struct btrfs_device *dev;
8388
int fd;
8489
u64 bytenr;
90+
#ifdef __ANDROID__
91+
atomic_flag thread_running;
92+
#endif
8593
};
8694

8795
static struct extent_record *btrfs_new_extent_record(struct extent_buffer *eb)
@@ -761,8 +769,12 @@ static int scan_one_device(void *dev_scan_struct)
761769
return 1;
762770

763771
buf = malloc(sizeof(*buf) + rc->nodesize);
764-
if (!buf)
772+
if (!buf) {
773+
#ifdef __ANDROID__
774+
atomic_flag_clear(&dev_scan->thread_running);
775+
#endif
765776
return -ENOMEM;
777+
}
766778
buf->len = rc->nodesize;
767779

768780
bytenr = 0;
@@ -823,6 +835,9 @@ static int scan_one_device(void *dev_scan_struct)
823835
out:
824836
close(fd);
825837
free(buf);
838+
#ifdef __ANDROID__
839+
atomic_flag_clear(&dev_scan->thread_running);
840+
#endif
826841
return ret;
827842
}
828843

@@ -869,6 +884,9 @@ static int scan_devices(struct recover_control *rc)
869884
dev_scans[devidx].dev = dev;
870885
dev_scans[devidx].fd = fd;
871886
dev_scans[devidx].bytenr = -1;
887+
#ifdef __ANDROID__
888+
atomic_flag_test_and_set(&dev_scans[devidx].thread_running);
889+
#endif
872890
devidx++;
873891
}
874892

@@ -887,8 +905,15 @@ static int scan_devices(struct recover_control *rc)
887905
for (i = 0; i < devidx; i++) {
888906
if (dev_scans[i].bytenr == -1)
889907
continue;
908+
#ifdef __ANDROID__
909+
if (atomic_flag_test_and_set(&dev_scans[i].thread_running))
910+
ret = EBUSY;
911+
else
912+
ret = pthread_join(t_scans[i], (void **)&t_rets[i]);
913+
#else
890914
ret = pthread_tryjoin_np(t_scans[i],
891915
(void **)&t_rets[i]);
916+
#endif
892917
if (ret == EBUSY) {
893918
all_done = false;
894919
continue;

cmds/scrub.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "kernel-lib/sizes.h"
4646
#include "kernel-shared/volumes.h"
4747
#include "common/defs.h"
48+
#include "common/compat.h"
4849
#include "common/messages.h"
4950
#include "common/utils.h"
5051
#include "common/open-utils.h"

common/compat.c

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* This program is free software; you can redistribute it and/or
3+
* modify it under the terms of the GNU General Public
4+
* License v2 as published by the Free Software Foundation.
5+
*
6+
* This program is distributed in the hope that it will be useful,
7+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9+
* General Public License for more details.
10+
*
11+
* You should have received a copy of the GNU General Public
12+
* License along with this program; if not, write to the
13+
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14+
* Boston, MA 021110-1307, USA.
15+
*/
16+
17+
#include <string.h>
18+
#include <signal.h>
19+
#include <stdlib.h>
20+
#include "common/compat.h"
21+
22+
#ifdef __ANDROID__
23+
24+
/*
25+
* Workaround for pthread_cancel() in Android, using pthread_kill() instead, as
26+
* Android NDK does not support pthread_cancel().
27+
*/
28+
29+
int pthread_setcanceltype(int type, int *oldtype) { return 0; }
30+
31+
int pthread_setcancelstate(int state, int *oldstate) { return 0; }
32+
33+
int pthread_cancel(pthread_t thread_id) {
34+
int status;
35+
36+
status = btrfs_set_thread_exit_handler();
37+
if (status == 0)
38+
status = pthread_kill(thread_id, SIGUSR1);
39+
40+
return status;
41+
}
42+
43+
void btrfs_thread_exit_handler(int sig) {
44+
pthread_exit(0);
45+
}
46+
47+
int btrfs_set_thread_exit_handler() {
48+
struct sigaction actions;
49+
50+
memset(&actions, 0, sizeof(actions));
51+
sigemptyset(&actions.sa_mask);
52+
actions.sa_flags = 0;
53+
actions.sa_handler = btrfs_thread_exit_handler;
54+
55+
return sigaction(SIGUSR1, &actions, NULL);
56+
}
57+
58+
struct qsort_r_context {
59+
int (*compare)(const void *a, const void *b, void *context);
60+
void *arg;
61+
};
62+
63+
#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
64+
static _Thread_local struct qsort_r_context *qsort_r_ctx = NULL;
65+
#else
66+
static __thread struct qsort_r_context *qsort_r_ctx = NULL;
67+
#endif
68+
69+
static int qsort_r_stub_compare(const void *a, const void *b)
70+
{
71+
return qsort_r_ctx->compare(a, b, qsort_r_ctx->arg);
72+
}
73+
74+
void qsort_r(void *base, size_t nel, size_t width,
75+
int (*compare)(const void *a, const void *b, void *context),
76+
void *arg)
77+
{
78+
struct qsort_r_context ctx;
79+
struct qsort_r_context *old_ctx;
80+
81+
if (nel == 0)
82+
return;
83+
84+
ctx.compare = compare;
85+
ctx.arg = arg;
86+
old_ctx = qsort_r_ctx;
87+
qsort_r_ctx = &ctx;
88+
qsort(base, nel, width, qsort_r_stub_compare);
89+
90+
/* Restore the old context after qsort is finished. */
91+
qsort_r_ctx = old_ctx;
92+
}
93+
94+
#endif

common/compat.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* This program is free software; you can redistribute it and/or
3+
* modify it under the terms of the GNU General Public
4+
* License v2 as published by the Free Software Foundation.
5+
*
6+
* This program is distributed in the hope that it will be useful,
7+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9+
* General Public License for more details.
10+
*
11+
* You should have received a copy of the GNU General Public
12+
* License along with this program; if not, write to the
13+
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14+
* Boston, MA 021110-1307, USA.
15+
*/
16+
17+
#ifndef __BTRFS_COMPAT_H__
18+
#define __BTRFS_COMPAT_H__
19+
20+
#ifdef __ANDROID__
21+
22+
#include <pthread.h>
23+
24+
/*
25+
* Add missing pthread related definitions in Android.
26+
*/
27+
28+
#define PTHREAD_CANCELED ((void *)-1)
29+
30+
#define PTHREAD_CANCEL_DEFERRED 0
31+
#define PTHREAD_CANCEL_ASYNCHRONOUS 0
32+
#define PTHREAD_CANCEL_ENABLE 0
33+
#define PTHREAD_CANCEL_DISABLE 0
34+
35+
int pthread_setcanceltype(int type, int *oldtype);
36+
int pthread_setcancelstate(int state, int *oldstate);
37+
int pthread_cancel(pthread_t thread_id);
38+
39+
int btrfs_set_thread_exit_handler();
40+
void btrfs_thread_exit_handler(int sig);
41+
42+
/**
43+
* @brief A compatible implementation of the GNU C Library (Glibc) qsort_r.
44+
*
45+
* Sorts an array using the quicksort algorithm. This function is thread-safe
46+
* by allowing a custom context pointer (arg) to be passed to the comparison
47+
* function.
48+
*
49+
* @param base A pointer to the first element of the array to be sorted.
50+
* @param nel The number of elements in the array.
51+
* @param width The size in bytes of each element in the array.
52+
* @param compare The comparison function, which takes two elements and a context
53+
* pointer. The function must return:
54+
* - A negative integer if the first element is less than the second.
55+
* - Zero if the elements are equal.
56+
* - A positive integer if the first element is greater than the second.
57+
* @param arg The custom pointer passed to the comparison function.
58+
*/
59+
void qsort_r(void *base, size_t nel, size_t width,
60+
int (*compare)(const void *a, const void *b, void *context),
61+
void *arg);
62+
63+
#endif
64+
65+
#endif

common/sort-utils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define __COMMON_SORT_UTILS_H__
1919

2020
#include <stdbool.h>
21+
#include "common/compat.h"
2122

2223
/*
2324
* Example:

common/task-utils.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <unistd.h>
2121
#include <time.h>
2222
#include "common/task-utils.h"
23+
#include "common/compat.h"
2324

2425
struct task_info *task_init(void *(*threadfn)(void *), int (*postfn)(void *),
2526
void *thread_private)

0 commit comments

Comments
 (0)