Print this page
3910 t_look(3NSL) should never return T_ERROR
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/nfs/nfs_dump.c
+++ new/usr/src/uts/common/fs/nfs/nfs_dump.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 + * Copyright 2014 Gary Mills
22 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 24 * Use is subject to license terms.
24 25 */
25 26
26 27 /*
27 28 * Dump memory to NFS swap file after a panic.
28 29 * We have no timeouts, context switches, etc.
29 30 */
30 31
31 32 #include <rpc/types.h>
32 33 #include <sys/param.h>
33 34 #include <sys/errno.h>
34 35 #include <sys/vnode.h>
35 36 #include <sys/bootconf.h>
36 37 #include <nfs/nfs.h>
37 38 #include <rpc/auth.h>
38 39 #include <rpc/xdr.h>
39 40 #include <rpc/rpc_msg.h>
40 41 #include <rpc/clnt.h>
41 42 #include <netinet/in.h>
42 43 #include <sys/tiuser.h>
43 44 #include <nfs/nfs_clnt.h>
44 45 #include <sys/t_kuser.h>
45 46 #include <sys/file.h>
46 47 #include <sys/netconfig.h>
47 48 #include <sys/utsname.h>
48 49 #include <sys/sysmacros.h>
49 50 #include <sys/thread.h>
50 51 #include <sys/cred.h>
51 52 #include <sys/strsubr.h>
52 53 #include <nfs/rnode.h>
53 54 #include <sys/varargs.h>
54 55 #include <sys/cmn_err.h>
55 56 #include <sys/systm.h>
56 57 #include <sys/dumphdr.h>
57 58 #include <sys/debug.h>
58 59 #include <sys/sunddi.h>
59 60
60 61 #define TIMEOUT (2 * hz)
61 62 #define RETRIES (5)
62 63 #define HDR_SIZE (256)
63 64
64 65 static struct knetconfig nfsdump_cf;
65 66 static struct netbuf nfsdump_addr;
66 67 static fhandle_t nfsdump_fhandle2;
67 68 static nfs_fh3 nfsdump_fhandle3;
68 69 static int nfsdump_maxcount;
69 70 static rpcvers_t nfsdump_version;
70 71
71 72 /*
72 73 * nonzero dumplog enables nd_log messages
73 74 */
74 75 static int dumplog = 0;
75 76
76 77 static int nd_init(vnode_t *, TIUSER **);
77 78 static int nd_poll(TIUSER *, int, int *);
78 79 static int nd_send_data(TIUSER *, caddr_t, int, XDR *, uint32_t *);
79 80 static int nd_get_reply(TIUSER *, XDR *, uint32_t, int *);
80 81 static int nd_auth_marshall(XDR *);
81 82
82 83 static void nd_log(const char *, ...) __KPRINTFLIKE(1);
83 84
84 85 /*PRINTFLIKE1*/
85 86 static void
86 87 nd_log(const char *fmt, ...)
87 88 {
88 89 if (dumplog) {
89 90 va_list adx;
90 91
91 92 va_start(adx, fmt);
92 93 vprintf(fmt, adx);
93 94 va_end(adx);
94 95 }
95 96 }
96 97
97 98 /* ARGSUSED */
98 99 int
99 100 nfs_dump(vnode_t *dumpvp, caddr_t addr, offset_t bn, offset_t count,
100 101 caller_context_t *ct)
101 102 {
102 103 static TIUSER *tiptr;
103 104 XDR xdrs;
104 105 int reply;
105 106 int badmsg;
106 107 uint32_t call_xid;
107 108 int retry = 0;
108 109 int error;
109 110 int i;
110 111
111 112 nd_log("nfs_dump: addr=%p bn=%lld count=%lld\n",
112 113 (void *)addr, bn, count);
113 114
114 115 if (error = nd_init(dumpvp, &tiptr))
115 116 return (error);
116 117
117 118 for (i = 0; i < count; i += ptod(1), addr += ptob(1)) {
118 119 do {
119 120 error = nd_send_data(tiptr, addr, (int)dbtob(bn + i),
120 121 &xdrs, &call_xid);
121 122 if (error)
122 123 return (error);
123 124
124 125 do {
125 126 if (error = nd_poll(tiptr, retry, &reply))
126 127 return (error);
127 128
128 129 if (!reply) {
129 130 retry++;
130 131 break;
131 132 }
132 133 retry = 0;
133 134
134 135 error = nd_get_reply(tiptr, &xdrs, call_xid,
135 136 &badmsg);
136 137 if (error)
137 138 return (error);
138 139 } while (badmsg);
139 140 } while (retry);
140 141 }
141 142
142 143 return (0);
143 144 }
144 145
145 146 static int
146 147 nd_init(vnode_t *dumpvp, TIUSER **tiptr)
147 148 {
148 149 int error;
149 150
150 151 if (*tiptr)
151 152 return (0);
152 153
153 154 /*
154 155 * If dump info hasn't yet been initialized (because dump
155 156 * device was chosen at user-level, rather than at boot time
156 157 * in nfs_swapvp) fill it in now.
157 158 */
158 159 if (nfsdump_maxcount == 0) {
159 160 nfsdump_version = VTOMI(dumpvp)->mi_vers;
160 161 switch (nfsdump_version) {
161 162 case NFS_VERSION:
162 163 nfsdump_fhandle2 = *VTOFH(dumpvp);
163 164 break;
164 165 case NFS_V3:
165 166 nfsdump_fhandle3 = *VTOFH3(dumpvp);
166 167 break;
167 168 default:
168 169 return (EIO);
169 170 }
170 171 nfsdump_maxcount = (int)dumpvp_size;
171 172 nfsdump_addr = VTOMI(dumpvp)->mi_curr_serv->sv_addr;
172 173 nfsdump_cf = *(VTOMI(dumpvp)->mi_curr_serv->sv_knconf);
173 174 if (nfsdump_cf.knc_semantics != NC_TPI_CLTS) {
174 175 int v6 = 1;
175 176 nd_log("nfs_dump: not connectionless!\n");
176 177 if ((strcmp(nfsdump_cf.knc_protofmly, NC_INET) == 0) ||
177 178 ((v6 = strcmp(nfsdump_cf.knc_protofmly, NC_INET6))\
178 179 == 0)) {
179 180 major_t clone_maj;
180 181
181 182 nfsdump_cf.knc_proto = NC_UDP;
182 183 nfsdump_cf.knc_semantics = NC_TPI_CLTS;
183 184 nd_log("nfs_dump: grabbing UDP major number\n");
184 185 clone_maj = ddi_name_to_major("clone");
185 186 nd_log("nfs_dump: making UDP device\n");
186 187 nfsdump_cf.knc_rdev = makedevice(clone_maj,
187 188 ddi_name_to_major(v6?"udp":"udp6"));
188 189 } else {
189 190 error = EIO;
190 191 nfs_perror(error, "\nnfs_dump: cannot dump over"
191 192 " protocol %s: %m\n", nfsdump_cf.knc_proto);
192 193 return (error);
193 194 }
194 195 }
195 196 }
196 197
197 198 nd_log("nfs_dump: calling t_kopen\n");
198 199
199 200 if (error = t_kopen(NULL, nfsdump_cf.knc_rdev,
200 201 FREAD|FWRITE|FNDELAY, tiptr, CRED())) {
201 202 nfs_perror(error, "\nnfs_dump: t_kopen failed: %m\n");
202 203 return (EIO);
203 204 }
204 205
205 206 if ((strcmp(nfsdump_cf.knc_protofmly, NC_INET) == 0) ||
206 207 (strcmp(nfsdump_cf.knc_protofmly, NC_INET6) == 0)) {
207 208 nd_log("nfs_dump: calling bindresvport\n");
208 209 if (error = bindresvport(*tiptr, NULL, NULL, FALSE)) {
209 210 nfs_perror(error,
210 211 "\nnfs_dump: bindresvport failed: %m\n");
211 212 return (EIO);
212 213 }
213 214 } else {
214 215 nd_log("nfs_dump: calling t_kbind\n");
215 216 if ((error = t_kbind(*tiptr, NULL, NULL)) != 0) {
216 217 nfs_perror(error, "\nnfs_dump: t_kbind failed: %m\n");
217 218 return (EIO);
218 219 }
219 220 }
220 221 return (0);
221 222 }
222 223
223 224 static int
224 225 nd_send_data(TIUSER *tiptr, caddr_t addr, int offset, XDR *xdrp, uint32_t *xidp)
225 226 {
226 227 static struct rpc_msg call_msg;
227 228 static uchar_t header[HDR_SIZE];
228 229 static struct t_kunitdata sudata;
229 230 static uchar_t *dumpbuf;
230 231 int procnum;
231 232 stable_how stable = FILE_SYNC;
232 233 mblk_t *mblk_p;
233 234 int error;
234 235 int tsize = ptob(1);
235 236 uint64 offset3;
236 237
237 238 if (!dumpbuf) {
238 239 call_msg.rm_direction = CALL;
239 240 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
240 241 call_msg.rm_call.cb_prog = NFS_PROGRAM;
241 242 call_msg.rm_call.cb_vers = nfsdump_version;
242 243
243 244 if (!(dumpbuf = kmem_alloc(ptob(1), KM_NOSLEEP))) {
244 245 cmn_err(CE_WARN, "\tnfs_dump: cannot allocate dump buffer");
245 246 return (ENOMEM);
246 247 }
247 248 }
248 249
249 250 nd_log("nfs_dump: calling esballoc for header\n");
250 251
251 252 if (!(mblk_p = esballoc(header, HDR_SIZE, BPRI_HI, &frnop))) {
252 253 cmn_err(CE_WARN, "\tnfs_dump: out of mblks");
253 254 return (ENOBUFS);
254 255 }
255 256
256 257 xdrmem_create(xdrp, (caddr_t)header, HDR_SIZE, XDR_ENCODE);
257 258
258 259 call_msg.rm_xid = alloc_xid();
259 260 *xidp = call_msg.rm_xid;
260 261
261 262 if (!xdr_callhdr(xdrp, &call_msg)) {
262 263 cmn_err(CE_WARN, "\tnfs_dump: cannot serialize header");
263 264 return (EIO);
264 265 }
265 266
266 267 if (nfsdump_maxcount) {
267 268 /*
268 269 * Do not extend the dump file if it is also
269 270 * the swap file.
270 271 */
271 272 if (offset >= nfsdump_maxcount) {
272 273 cmn_err(CE_WARN, "\tnfs_dump: end of file");
273 274 return (EIO);
274 275 }
275 276 if (offset + tsize > nfsdump_maxcount)
276 277 tsize = nfsdump_maxcount - offset;
277 278 }
278 279 switch (nfsdump_version) {
279 280 case NFS_VERSION:
280 281 procnum = RFS_WRITE;
281 282 if (!XDR_PUTINT32(xdrp, (int32_t *)&procnum) ||
282 283 !nd_auth_marshall(xdrp) ||
283 284 !xdr_fhandle(xdrp, &nfsdump_fhandle2) ||
284 285 /*
285 286 * Following four values are:
286 287 * beginoffset
287 288 * offset
288 289 * length
289 290 * bytes array length
290 291 */
291 292 !XDR_PUTINT32(xdrp, (int32_t *)&offset) ||
292 293 !XDR_PUTINT32(xdrp, (int32_t *)&offset) ||
293 294 !XDR_PUTINT32(xdrp, (int32_t *)&tsize) ||
294 295 !XDR_PUTINT32(xdrp, (int32_t *)&tsize)) {
295 296 cmn_err(CE_WARN, "\tnfs_dump: serialization failed");
296 297 return (EIO);
297 298 }
298 299 break;
299 300 case NFS_V3:
300 301 procnum = NFSPROC3_WRITE;
301 302 offset3 = offset;
302 303 if (!XDR_PUTINT32(xdrp, (int32_t *)&procnum) ||
303 304 !nd_auth_marshall(xdrp) ||
304 305 !xdr_nfs_fh3(xdrp, &nfsdump_fhandle3) ||
305 306 /*
306 307 * Following four values are:
307 308 * offset
308 309 * count
309 310 * stable
310 311 * bytes array length
311 312 */
312 313 !xdr_u_longlong_t(xdrp, &offset3) ||
313 314 !XDR_PUTINT32(xdrp, (int32_t *)&tsize) ||
314 315 !XDR_PUTINT32(xdrp, (int32_t *)&stable) ||
315 316 !XDR_PUTINT32(xdrp, (int32_t *)&tsize)) {
316 317 cmn_err(CE_WARN, "\tnfs_dump: serialization failed");
317 318 return (EIO);
318 319 }
319 320 break;
320 321 default:
321 322 return (EIO);
322 323 }
323 324
324 325 bcopy(addr, (caddr_t)dumpbuf, tsize);
325 326
326 327 mblk_p->b_wptr += (int)XDR_GETPOS(xdrp);
327 328
328 329 mblk_p->b_cont = esballoc((uchar_t *)dumpbuf, ptob(1), BPRI_HI, &frnop);
329 330
330 331 if (!mblk_p->b_cont) {
331 332 cmn_err(CE_WARN, "\tnfs_dump: out of mblks");
332 333 return (ENOBUFS);
333 334 }
334 335 mblk_p->b_cont->b_wptr += ptob(1);
335 336
336 337 sudata.addr = nfsdump_addr; /* structure copy */
337 338 sudata.udata.buf = (char *)NULL;
338 339 sudata.udata.maxlen = 0;
339 340 sudata.udata.len = 1; /* needed for t_ksndudata */
340 341 sudata.udata.udata_mp = mblk_p;
341 342
342 343 nd_log("nfs_dump: calling t_ksndudata\n");
343 344
344 345 if (error = t_ksndudata(tiptr, &sudata, (frtn_t *)NULL)) {
345 346 nfs_perror(error, "\nnfs_dump: t_ksndudata failed: %m\n");
346 347 return (error);
347 348 }
348 349 return (0);
349 350 }
350 351
351 352 static int
352 353 nd_get_reply(TIUSER *tiptr, XDR *xdrp, uint32_t call_xid, int *badmsg)
353 354 {
354 355 static struct rpc_msg reply_msg;
355 356 static struct rpc_err rpc_err;
356 357 static struct nfsattrstat na;
357 358 static struct WRITE3res wres;
358 359 static struct t_kunitdata rudata;
359 360 int uderr;
360 361 int type;
361 362 int error;
↓ open down ↓ |
330 lines elided |
↑ open up ↑ |
362 363
363 364 *badmsg = 0;
364 365
365 366 rudata.addr.maxlen = 0;
366 367 rudata.opt.maxlen = 0;
367 368 rudata.udata.udata_mp = (mblk_t *)NULL;
368 369
369 370 nd_log("nfs_dump: calling t_krcvudata\n");
370 371
371 372 if (error = t_krcvudata(tiptr, &rudata, &type, &uderr)) {
373 + if (error == EBADMSG) {
374 + cmn_err(CE_WARN, "\tnfs_dump: received EBADMSG");
375 + *badmsg = 1;
376 + return (0);
377 + }
372 378 nfs_perror(error, "\nnfs_dump: t_krcvudata failed: %m\n");
373 379 return (EIO);
374 380 }
375 381 if (type != T_DATA) {
376 382 cmn_err(CE_WARN, "\tnfs_dump: received type %d", type);
377 383 *badmsg = 1;
378 384 return (0);
379 385 }
380 386 if (!rudata.udata.udata_mp) {
381 387 cmn_err(CE_WARN, "\tnfs_dump: null receive");
382 388 *badmsg = 1;
383 389 return (0);
384 390 }
385 391
386 392 /*
387 393 * Decode results.
388 394 */
389 395 xdrmblk_init(xdrp, rudata.udata.udata_mp, XDR_DECODE, 0);
390 396
391 397 reply_msg.acpted_rply.ar_verf = _null_auth;
392 398 switch (nfsdump_version) {
393 399 case NFS_VERSION:
394 400 reply_msg.acpted_rply.ar_results.where = (caddr_t)&na;
395 401 reply_msg.acpted_rply.ar_results.proc = xdr_attrstat;
396 402 break;
397 403 case NFS_V3:
398 404 reply_msg.acpted_rply.ar_results.where = (caddr_t)&wres;
399 405 reply_msg.acpted_rply.ar_results.proc = xdr_WRITE3res;
400 406 break;
401 407 default:
402 408 return (EIO);
403 409 }
404 410
405 411 if (!xdr_replymsg(xdrp, &reply_msg)) {
406 412 cmn_err(CE_WARN, "\tnfs_dump: xdr_replymsg failed");
407 413 return (EIO);
408 414 }
409 415
410 416 if (reply_msg.rm_xid != call_xid) {
411 417 *badmsg = 1;
412 418 return (0);
413 419 }
414 420
415 421 _seterr_reply(&reply_msg, &rpc_err);
416 422
417 423 if (rpc_err.re_status != RPC_SUCCESS) {
418 424 cmn_err(CE_WARN, "\tnfs_dump: RPC error %d (%s)",
419 425 rpc_err.re_status, clnt_sperrno(rpc_err.re_status));
420 426 return (EIO);
421 427 }
422 428
423 429 switch (nfsdump_version) {
424 430 case NFS_VERSION:
425 431 if (na.ns_status) {
426 432 cmn_err(CE_WARN, "\tnfs_dump: status %d", na.ns_status);
427 433 return (EIO);
428 434 }
429 435 break;
430 436 case NFS_V3:
431 437 if (wres.status != NFS3_OK) {
432 438 cmn_err(CE_WARN, "\tnfs_dump: status %d", wres.status);
433 439 return (EIO);
434 440 }
435 441 break;
436 442 default:
437 443 return (EIO);
438 444 }
439 445
440 446 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
441 447 /* free auth handle */
442 448 xdrp->x_op = XDR_FREE;
443 449 (void) xdr_opaque_auth(xdrp, &(reply_msg.acpted_rply.ar_verf));
444 450 }
445 451
446 452 freemsg(rudata.udata.udata_mp);
447 453
448 454 return (0);
449 455 }
450 456
451 457 static int
452 458 nd_poll(TIUSER *tiptr, int retry, int *eventp)
453 459 {
454 460 clock_t start_bolt = ddi_get_lbolt();
455 461 clock_t timout = TIMEOUT * (retry + 1);
456 462 int error;
457 463
458 464 nd_log("nfs_dump: calling t_kspoll\n");
459 465
460 466 *eventp = 0;
461 467
462 468 while (!*eventp && ((ddi_get_lbolt() - start_bolt) < timout)) {
463 469 /*
464 470 * Briefly enable interrupts before checking for a reply;
465 471 * the network transports do not yet support do_polled_io.
466 472 */
467 473 int s = spl0();
468 474 splx(s);
469 475
470 476 if (error = t_kspoll(tiptr, 0, READWAIT, eventp)) {
471 477 nfs_perror(error,
472 478 "\nnfs_dump: t_kspoll failed: %m\n");
473 479 return (EIO);
474 480 }
475 481 runqueues();
476 482 }
477 483
478 484 if (retry == RETRIES && !*eventp) {
479 485 cmn_err(CE_WARN, "\tnfs_dump: server not responding");
480 486 return (EIO);
481 487 }
482 488
483 489 return (0);
484 490 }
485 491
486 492 static int
487 493 nd_auth_marshall(XDR *xdrp)
488 494 {
489 495 int credsize;
490 496 int32_t *ptr;
491 497 int hostnamelen;
492 498
493 499 hostnamelen = (int)strlen(utsname.nodename);
494 500 credsize = 4 + 4 + roundup(hostnamelen, 4) + 4 + 4 + 4;
495 501
496 502 ptr = XDR_INLINE(xdrp, 4 + 4 + credsize + 4 + 4);
497 503 if (!ptr) {
498 504 cmn_err(CE_WARN, "\tnfs_dump: auth_marshall failed");
499 505 return (0);
500 506 }
501 507 /*
502 508 * We can do the fast path.
503 509 */
504 510 IXDR_PUT_INT32(ptr, AUTH_UNIX); /* cred flavor */
505 511 IXDR_PUT_INT32(ptr, credsize); /* cred len */
506 512 IXDR_PUT_INT32(ptr, gethrestime_sec());
507 513 IXDR_PUT_INT32(ptr, hostnamelen);
508 514
509 515 bcopy(utsname.nodename, ptr, hostnamelen);
510 516 ptr += roundup(hostnamelen, 4) / 4;
511 517
512 518 IXDR_PUT_INT32(ptr, 0); /* uid */
513 519 IXDR_PUT_INT32(ptr, 0); /* gid */
514 520 IXDR_PUT_INT32(ptr, 0); /* gid list length (empty) */
515 521 IXDR_PUT_INT32(ptr, AUTH_NULL); /* verf flavor */
516 522 IXDR_PUT_INT32(ptr, 0); /* verf len */
517 523
518 524 return (1);
519 525 }
↓ open down ↓ |
138 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX