]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/pnfsdsfile/pnfsdsfile.c
Optionally bind ktls threads to NUMA domains
[FreeBSD/FreeBSD.git] / usr.sbin / pnfsdsfile / pnfsdsfile.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2017 Rick Macklem
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <err.h>
33 #include <getopt.h>
34 #include <netdb.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <sys/param.h>
40 #include <sys/extattr.h>
41 #include <sys/mount.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <fs/nfs/nfskpiport.h>
45 #include <fs/nfs/nfsproto.h>
46 #include <fs/nfs/nfs.h>
47 #include <fs/nfs/nfsrvstate.h>
48
49 static void usage(void);
50
51 static struct option longopts[] = {
52         { "changeds",   required_argument,      NULL,   'c'     },
53         { "mirror",     required_argument,      NULL,   'm'     },
54         { "quiet",      no_argument,            NULL,   'q'     },
55         { "zerods",     required_argument,      NULL,   'r'     },
56         { "ds",         required_argument,      NULL,   's'     },
57         { "zerofh",     no_argument,            NULL,   'z'     },
58         { NULL,         0,                      NULL,   0       }
59 };
60
61 /*
62  * This program displays the location information of a data storage file
63  * for a given file on a MetaData Server (MDS) in a pNFS service.  This program
64  * must be run on the MDS and the file argument must be a file in a local
65  * file system that has been exported for the pNFS service.
66  */
67 int
68 main(int argc, char *argv[])
69 {
70         struct addrinfo *res, *ad, *newres;
71         struct sockaddr_in *sin, adsin;
72         struct sockaddr_in6 *sin6, adsin6;
73         char hostn[2 * NI_MAXHOST + 2], *cp;
74         struct pnfsdsfile dsfile[NFSDEV_MAXMIRRORS];
75         int ch, dosetxattr, i, mirrorcnt, mirrorit, quiet, zerods, zerofh;
76         in_port_t tport;
77         ssize_t xattrsize, xattrsize2;
78
79         zerods = 0;
80         zerofh = 0;
81         mirrorit = 0;
82         quiet = 0;
83         dosetxattr = 0;
84         res = NULL;
85         newres = NULL;
86         cp = NULL;
87         while ((ch = getopt_long(argc, argv, "c:m:qr:s:z", longopts, NULL)) !=
88             -1) {
89                 switch (ch) {
90                 case 'c':
91                         /* Replace the first DS server with the second one. */
92                         if (zerofh != 0 || zerods != 0 || mirrorit != 0 ||
93                             newres != NULL || res != NULL)
94                                 errx(1, "-c, -m, -r, -s and -z are mutually "
95                                     "exclusive and only can be used once");
96                         strlcpy(hostn, optarg, 2 * NI_MAXHOST + 2);
97                         cp = strchr(hostn, ',');
98                         if (cp == NULL)
99                                 errx(1, "Bad -c argument %s", hostn);
100                         *cp = '\0';
101                         if (getaddrinfo(hostn, NULL, NULL, &res) != 0)
102                                 errx(1, "Can't get IP# for %s", hostn);
103                         *cp++ = ',';
104                         if (getaddrinfo(cp, NULL, NULL, &newres) != 0)
105                                 errx(1, "Can't get IP# for %s", cp);
106                         break;
107                 case 'm':
108                         /* Add 0.0.0.0 entries up to mirror level. */
109                         if (zerofh != 0 || zerods != 0 || mirrorit != 0 ||
110                             newres != NULL || res != NULL)
111                                 errx(1, "-c, -m, -r, -s and -z are mutually "
112                                     "exclusive and only can be used once");
113                         mirrorit = atoi(optarg);
114                         if (mirrorit < 2 || mirrorit > NFSDEV_MAXMIRRORS)
115                                 errx(1, "-m %d out of range", mirrorit);
116                         break;
117                 case 'q':
118                         quiet = 1;
119                         break;
120                 case 'r':
121                         /* Reset the DS server in a mirror with 0.0.0.0. */
122                         if (zerofh != 0 || zerods != 0 || mirrorit != 0 ||
123                             newres != NULL || res != NULL)
124                                 errx(1, "-c, -m, -r, -s and -z are mutually "
125                                     "exclusive and only can be used once");
126                         zerods = 1;
127                         /* Translate the server name to an IP address. */
128                         if (getaddrinfo(optarg, NULL, NULL, &res) != 0)
129                                 errx(1, "Can't get IP# for %s", optarg);
130                         break;
131                 case 's':
132                         /* Translate the server name to an IP address. */
133                         if (zerods != 0 || mirrorit != 0 || newres != NULL ||
134                             res != NULL)
135                                 errx(1, "-c, -m and -r are mutually exclusive "
136                                     "from use with -s and -z");
137                         if (getaddrinfo(optarg, NULL, NULL, &res) != 0)
138                                 errx(1, "Can't get IP# for %s", optarg);
139                         break;
140                 case 'z':
141                         if (zerofh != 0 || zerods != 0 || mirrorit != 0 ||
142                             newres != NULL)
143                                 errx(1, "-c, -m and -r are mutually exclusive "
144                                     "from use with -s and -z");
145                         zerofh = 1;
146                         break;
147                 default:
148                         usage();
149                 }
150         }
151         argc -= optind;
152         if (argc != 1)
153                 usage();
154         argv += optind;
155
156         /*
157          * The host address and directory where the data storage file is
158          * located is in the extended attribute "pnfsd.dsfile".
159          */
160         xattrsize = extattr_get_file(*argv, EXTATTR_NAMESPACE_SYSTEM,
161             "pnfsd.dsfile", dsfile, sizeof(dsfile));
162         mirrorcnt = xattrsize / sizeof(struct pnfsdsfile);
163         xattrsize2 = mirrorcnt * sizeof(struct pnfsdsfile);
164         if (mirrorcnt < 1 || xattrsize != xattrsize2)
165                 err(1, "Can't get extattr pnfsd.dsfile for %s", *argv);
166
167         if (quiet == 0)
168                 printf("%s:\t", *argv);
169         for (i = 0; i < mirrorcnt; i++) {
170                 if (i > 0 && quiet == 0)
171                         printf("\t");
172                 /* Do the zerofh option. You must be root. */
173                 if (zerofh != 0) {
174                         if (geteuid() != 0)
175                                 errx(1, "Must be root/su to zerofh");
176         
177                         /*
178                          * Do it for the server specified by -s/--ds or all
179                          * servers, if -s/--ds was not specified.
180                          */
181                         sin = &dsfile[i].dsf_sin;
182                         sin6 = &dsfile[i].dsf_sin6;
183                         ad = res;
184                         while (ad != NULL) {
185                                 if (ad->ai_addr->sa_family == AF_INET &&
186                                     sin->sin_family == AF_INET &&
187                                     ad->ai_addrlen >= sizeof(adsin)) {
188                                         memcpy(&adsin, ad->ai_addr,
189                                             sizeof(adsin));
190                                         if (sin->sin_addr.s_addr ==
191                                             adsin.sin_addr.s_addr)
192                                                 break;
193                                 }
194                                 if (ad->ai_addr->sa_family == AF_INET6 &&
195                                     sin6->sin6_family == AF_INET6 &&
196                                     ad->ai_addrlen >= sizeof(adsin6)) {
197                                         memcpy(&adsin6, ad->ai_addr,
198                                             sizeof(adsin6));
199                                         if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
200                                             &adsin6.sin6_addr))
201                                                 break;
202                                 }
203                                 ad = ad->ai_next;
204                         }
205                         if (res == NULL || ad != NULL) {
206                                 memset(&dsfile[i].dsf_fh, 0, sizeof(fhandle_t));
207                                 dosetxattr = 1;
208                         }
209                 }
210         
211                 /* Do the zerods option. You must be root. */
212                 if (zerods != 0 && mirrorcnt > 1) {
213                         if (geteuid() != 0)
214                                 errx(1, "Must be root/su to zerods");
215         
216                         /*
217                          * Do it for the server specified.
218                          */
219                         sin = &dsfile[i].dsf_sin;
220                         sin6 = &dsfile[i].dsf_sin6;
221                         ad = res;
222                         while (ad != NULL) {
223                                 if (ad->ai_addr->sa_family == AF_INET &&
224                                     sin->sin_family == AF_INET &&
225                                     ad->ai_addrlen >= sizeof(adsin)) {
226                                         memcpy(&adsin, ad->ai_addr,
227                                             sizeof(adsin));
228                                         if (sin->sin_addr.s_addr ==
229                                             adsin.sin_addr.s_addr)
230                                                 break;
231                                 }
232                                 if (ad->ai_addr->sa_family == AF_INET6 &&
233                                     sin6->sin6_family == AF_INET6 &&
234                                     ad->ai_addrlen >= sizeof(adsin6)) {
235                                         memcpy(&adsin6, ad->ai_addr,
236                                             sizeof(adsin6));
237                                         if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
238                                             &adsin6.sin6_addr))
239                                                 break;
240                                 }
241                                 ad = ad->ai_next;
242                         }
243                         if (ad != NULL) {
244                                 sin->sin_family = AF_INET;
245                                 sin->sin_len = sizeof(*sin);
246                                 sin->sin_port = 0;
247                                 sin->sin_addr.s_addr = 0;
248                                 dosetxattr = 1;
249                         }
250                 }
251         
252                 /* Do the -c option to replace the DS host address. */
253                 if (newres != NULL) {
254                         if (geteuid() != 0)
255                                 errx(1, "Must be root/su to replace the host"
256                                     " addr");
257         
258                         /*
259                          * Check that the old host address matches.
260                          */
261                         sin = &dsfile[i].dsf_sin;
262                         sin6 = &dsfile[i].dsf_sin6;
263                         ad = res;
264                         while (ad != NULL) {
265                                 if (ad->ai_addr->sa_family == AF_INET &&
266                                     sin->sin_family == AF_INET &&
267                                     ad->ai_addrlen >= sizeof(adsin)) {
268                                         memcpy(&adsin, ad->ai_addr,
269                                             sizeof(adsin));
270                                         if (sin->sin_addr.s_addr ==
271                                             adsin.sin_addr.s_addr)
272                                                 break;
273                                 }
274                                 if (ad->ai_addr->sa_family == AF_INET6 &&
275                                     sin6->sin6_family == AF_INET6 &&
276                                     ad->ai_addrlen >= sizeof(adsin6)) {
277                                         memcpy(&adsin6, ad->ai_addr,
278                                             sizeof(adsin6));
279                                         if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
280                                             &adsin6.sin6_addr))
281                                                 break;
282                                 }
283                                 ad = ad->ai_next;
284                         }
285                         if (ad != NULL) {
286                                 if (sin->sin_family == AF_INET)
287                                         tport = sin->sin_port;
288                                 else
289                                         tport = sin6->sin6_port;
290                                 /*
291                                  * We have a match, so replace it with the first
292                                  * AF_INET or AF_INET6 address in the newres
293                                  * list.
294                                  */
295                                 while (newres->ai_addr->sa_family != AF_INET &&
296                                     newres->ai_addr->sa_family != AF_INET6) {
297                                         newres = newres->ai_next;
298                                         if (newres == NULL)
299                                                 errx(1, "Hostname %s has no"
300                                                     " IP#", cp);
301                                 }
302                                 if (newres->ai_addr->sa_family == AF_INET) {
303                                         memcpy(sin, newres->ai_addr,
304                                             sizeof(*sin));
305                                         sin->sin_port = tport;
306                                 } else if (newres->ai_addr->sa_family ==
307                                     AF_INET6) {
308                                         memcpy(sin6, newres->ai_addr,
309                                             sizeof(*sin6));
310                                         sin6->sin6_port = tport;
311                                 }
312                                 dosetxattr = 1;
313                         }
314                 }
315         
316                 if (quiet == 0) {
317                         /* Translate the IP address to a hostname. */
318                         if (getnameinfo((struct sockaddr *)&dsfile[i].dsf_sin,
319                             dsfile[i].dsf_sin.sin_len, hostn, sizeof(hostn),
320                             NULL, 0, 0) < 0)
321                                 err(1, "Can't get hostname");
322                         printf("%s\tds%d/%s", hostn, dsfile[i].dsf_dir,
323                             dsfile[i].dsf_filename);
324                 }
325         }
326         /* Add entrie(s) with IP address set to 0.0.0.0, as required. */
327         for (i = mirrorcnt; i < mirrorit; i++) {
328                 dsfile[i] = dsfile[0];
329                 dsfile[i].dsf_sin.sin_family = AF_INET;
330                 dsfile[i].dsf_sin.sin_len = sizeof(struct sockaddr_in);
331                 dsfile[i].dsf_sin.sin_addr.s_addr = 0;
332                 dsfile[i].dsf_sin.sin_port = 0;
333                 if (quiet == 0) {
334                         /* Print out the 0.0.0.0 entry. */
335                         printf("\t0.0.0.0\tds%d/%s", dsfile[i].dsf_dir,
336                             dsfile[i].dsf_filename);
337                 }
338         }
339         if (mirrorit > mirrorcnt) {
340                 xattrsize = mirrorit * sizeof(struct pnfsdsfile);
341                 dosetxattr = 1;
342         }
343         if (quiet == 0)
344                 printf("\n");
345
346         if (dosetxattr != 0 && extattr_set_file(*argv, EXTATTR_NAMESPACE_SYSTEM,
347             "pnfsd.dsfile", dsfile, xattrsize) != xattrsize)
348                 err(1, "Can't set pnfsd.dsfile");
349 }
350
351 static void
352 usage(void)
353 {
354
355         fprintf(stderr, "pnfsdsfile [-q/--quiet] [-z/--zerofh] "
356             "[-c/--changeds <old dshostname> <new dshostname>] "
357             "[-r/--zerods <dshostname>] "
358             "[-s/--ds <dshostname>] "
359             "<filename>\n");
360         exit(1);
361 }
362