xref: /linux/tools/testing/selftests/filesystems/statmount/statmount.h (revision be1ca3ee8f97067fee87fda73ea5959d5ab75bbf)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 
3 #ifndef __STATMOUNT_H
4 #define __STATMOUNT_H
5 
6 #include <errno.h>
7 #include <stdint.h>
8 #include <stdlib.h>
9 #include <linux/mount.h>
10 #include <asm/unistd.h>
11 
12 #define STATMOUNT_BUFSIZE (1 << 15)
13 
14 #ifndef __NR_statmount
15 	#if defined __alpha__
16 		#define __NR_statmount 567
17 	#elif defined _MIPS_SIM
18 		#if _MIPS_SIM == _MIPS_SIM_ABI32	/* o32 */
19 			#define __NR_statmount 4457
20 		#endif
21 		#if _MIPS_SIM == _MIPS_SIM_NABI32	/* n32 */
22 			#define __NR_statmount 6457
23 		#endif
24 		#if _MIPS_SIM == _MIPS_SIM_ABI64	/* n64 */
25 			#define __NR_statmount 5457
26 		#endif
27 	#else
28 		#define __NR_statmount 457
29 	#endif
30 #endif
31 
32 #ifndef __NR_listmount
33 	#if defined __alpha__
34 		#define __NR_listmount 568
35 	#elif defined _MIPS_SIM
36 		#if _MIPS_SIM == _MIPS_SIM_ABI32	/* o32 */
37 			#define __NR_listmount 4458
38 		#endif
39 		#if _MIPS_SIM == _MIPS_SIM_NABI32	/* n32 */
40 			#define __NR_listmount 6458
41 		#endif
42 		#if _MIPS_SIM == _MIPS_SIM_ABI64	/* n64 */
43 			#define __NR_listmount 5458
44 		#endif
45 	#else
46 		#define __NR_listmount 458
47 	#endif
48 #endif
49 
50 static inline int statmount(uint64_t mnt_id, uint64_t mnt_ns_id, uint32_t fd,
51 			    uint64_t mask, struct statmount *buf, size_t bufsize,
52 			    unsigned int flags)
53 {
54 	struct mnt_id_req req = {
55 		.size = MNT_ID_REQ_SIZE_VER0,
56 		.param = mask,
57 	};
58 
59 	if (flags & STATMOUNT_BY_FD) {
60 		req.size = MNT_ID_REQ_SIZE_VER1;
61 		req.mnt_fd = fd;
62 	} else {
63 		req.mnt_id = mnt_id;
64 		if (mnt_ns_id) {
65 			req.size = MNT_ID_REQ_SIZE_VER1;
66 			req.mnt_ns_id = mnt_ns_id;
67 		}
68 	}
69 
70 	return syscall(__NR_statmount, &req, buf, bufsize, flags);
71 }
72 
73 static inline ssize_t listmount(uint64_t mnt_id, uint64_t mnt_ns_id,
74 			 uint64_t last_mnt_id, uint64_t list[], size_t num,
75 			 unsigned int flags)
76 {
77 	struct mnt_id_req req = {
78 		.size = MNT_ID_REQ_SIZE_VER0,
79 		.mnt_id = mnt_id,
80 		.param = last_mnt_id,
81 	};
82 
83 	if (mnt_ns_id) {
84 		req.size = MNT_ID_REQ_SIZE_VER1;
85 		req.mnt_ns_id = mnt_ns_id;
86 	}
87 
88 	return syscall(__NR_listmount, &req, list, num, flags);
89 }
90 
91 static inline struct statmount *statmount_alloc(uint64_t mnt_id, uint64_t mnt_ns_id,
92 						 uint64_t mask, unsigned int flags)
93 {
94 	struct statmount *buf;
95 	size_t bufsize = STATMOUNT_BUFSIZE;
96 	int ret;
97 
98 	for (;;) {
99 		buf = malloc(bufsize);
100 		if (!buf)
101 			return NULL;
102 
103 		ret = statmount(mnt_id, mnt_ns_id, 0, mask, buf, bufsize, flags);
104 		if (ret == 0)
105 			return buf;
106 
107 		free(buf);
108 		if (errno != EOVERFLOW)
109 			return NULL;
110 
111 		bufsize <<= 1;
112 	}
113 }
114 
115 static inline struct statmount *statmount_alloc_by_fd(int fd, uint64_t mask)
116 {
117 	struct statmount *buf;
118 	size_t bufsize = STATMOUNT_BUFSIZE;
119 	int ret;
120 
121 	for (;;) {
122 		buf = malloc(bufsize);
123 		if (!buf)
124 			return NULL;
125 
126 		ret = statmount(0, 0, fd, mask, buf, bufsize, STATMOUNT_BY_FD);
127 		if (ret == 0)
128 			return buf;
129 
130 		free(buf);
131 		if (errno != EOVERFLOW)
132 			return NULL;
133 
134 		bufsize <<= 1;
135 	}
136 }
137 
138 #endif /* __STATMOUNT_H */
139