]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/compat.cc
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / common / compat.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 * Copyright (C) 2018 Red Hat, Inc.
8 *
9 * This is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License version 2.1, as published by the Free Software
12 * Foundation. See file COPYING.
13 *
14 */
15
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <stdint.h>
19 #include <string.h>
20 #include <sys/mount.h>
21 #include <sys/param.h>
22 #include <sys/socket.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #if defined(__linux__)
27 #include <sys/vfs.h>
28 #endif
29
30 #include "include/compat.h"
31 #include "include/sock_compat.h"
32 #include "common/safe_io.h"
33
34 // The type-value for a ZFS FS in fstatfs.
35 #define FS_ZFS_TYPE 0xde
36
37 // On FreeBSD, ZFS fallocate always fails since it is considered impossible to
38 // reserve space on a COW filesystem. posix_fallocate() returns EINVAL
39 // Linux in this case already emulates the reservation in glibc
40 // In which case it is allocated manually, and still that is not a real guarantee
41 // that a full buffer is allocated on disk, since it could be compressed.
42 // To prevent this the written buffer needs to be loaded with random data.
43 int manual_fallocate(int fd, off_t offset, off_t len) {
44 int r = lseek(fd, offset, SEEK_SET);
45 if (r == -1)
46 return errno;
47 char data[1024*128];
48 // TODO: compressing filesystems would require random data
49 // FIPS zeroization audit 20191115: this memset is not security related.
50 memset(data, 0x42, sizeof(data));
51 for (off_t off = 0; off < len; off += sizeof(data)) {
52 if (off + static_cast<off_t>(sizeof(data)) > len)
53 r = safe_write(fd, data, len - off);
54 else
55 r = safe_write(fd, data, sizeof(data));
56 if (r == -1) {
57 return errno;
58 }
59 }
60 return 0;
61 }
62
63 int on_zfs(int basedir_fd) {
64 struct statfs basefs;
65 (void)fstatfs(basedir_fd, &basefs);
66 return (basefs.f_type == FS_ZFS_TYPE);
67 }
68
69 int ceph_posix_fallocate(int fd, off_t offset, off_t len) {
70 // Return 0 if oke, otherwise errno > 0
71
72 #ifdef HAVE_POSIX_FALLOCATE
73 if (on_zfs(fd)) {
74 return manual_fallocate(fd, offset, len);
75 } else {
76 return posix_fallocate(fd, offset, len);
77 }
78 #elif defined(__APPLE__)
79 fstore_t store;
80 store.fst_flags = F_ALLOCATECONTIG;
81 store.fst_posmode = F_PEOFPOSMODE;
82 store.fst_offset = offset;
83 store.fst_length = len;
84
85 int ret = fcntl(fd, F_PREALLOCATE, &store);
86 if (ret == -1) {
87 ret = errno;
88 }
89 return ret;
90 #else
91 return manual_fallocate(fd, offset, len);
92 #endif
93 }
94
95 int pipe_cloexec(int pipefd[2])
96 {
97 #if defined(HAVE_PIPE2)
98 return pipe2(pipefd, O_CLOEXEC);
99 #else
100 if (pipe(pipefd) == -1)
101 return -1;
102
103 /*
104 * The old-fashioned, race-condition prone way that we have to fall
105 * back on if pipe2 does not exist.
106 */
107 if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) < 0) {
108 goto fail;
109 }
110
111 if (fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) < 0) {
112 goto fail;
113 }
114
115 return 0;
116 fail:
117 int save_errno = errno;
118 VOID_TEMP_FAILURE_RETRY(close(pipefd[0]));
119 VOID_TEMP_FAILURE_RETRY(close(pipefd[1]));
120 return (errno = save_errno, -1);
121 #endif
122 }
123
124
125 int socket_cloexec(int domain, int type, int protocol)
126 {
127 #ifdef SOCK_CLOEXEC
128 return socket(domain, type|SOCK_CLOEXEC, protocol);
129 #else
130 int fd = socket(domain, type, protocol);
131 if (fd == -1)
132 return -1;
133
134 if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
135 goto fail;
136
137 return fd;
138 fail:
139 int save_errno = errno;
140 VOID_TEMP_FAILURE_RETRY(close(fd));
141 return (errno = save_errno, -1);
142 #endif
143 }
144
145 int socketpair_cloexec(int domain, int type, int protocol, int sv[2])
146 {
147 #ifdef SOCK_CLOEXEC
148 return socketpair(domain, type|SOCK_CLOEXEC, protocol, sv);
149 #else
150 int rc = socketpair(domain, type, protocol, sv);
151 if (rc == -1)
152 return -1;
153
154 if (fcntl(sv[0], F_SETFD, FD_CLOEXEC) < 0)
155 goto fail;
156
157 if (fcntl(sv[1], F_SETFD, FD_CLOEXEC) < 0)
158 goto fail;
159
160 return 0;
161 fail:
162 int save_errno = errno;
163 VOID_TEMP_FAILURE_RETRY(close(sv[0]));
164 VOID_TEMP_FAILURE_RETRY(close(sv[1]));
165 return (errno = save_errno, -1);
166 #endif
167 }
168
169 int accept_cloexec(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
170 {
171 #ifdef HAVE_ACCEPT4
172 return accept4(sockfd, addr, addrlen, SOCK_CLOEXEC);
173 #else
174 int fd = accept(sockfd, addr, addrlen);
175 if (fd == -1)
176 return -1;
177
178 if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
179 goto fail;
180
181 return fd;
182 fail:
183 int save_errno = errno;
184 VOID_TEMP_FAILURE_RETRY(close(fd));
185 return (errno = save_errno, -1);
186 #endif
187 }
188
189 #if defined(__FreeBSD__)
190 int sched_setaffinity(pid_t pid, size_t cpusetsize,
191 cpu_set_t *mask)
192 {
193 return 0;
194 }
195 #endif
196