1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * RCM module providing support for swap areas
28 * during reconfiguration operations.
29 */
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <thread.h>
34 #include <synch.h>
35 #include <strings.h>
36 #include <assert.h>
37 #include <errno.h>
38 #include <libintl.h>
39 #include <sys/types.h>
40 #include <sys/swap.h>
41 #include <sys/stat.h>
42 #include <sys/param.h>
43 #include <sys/dumpadm.h>
44 #include <sys/wait.h>
45 #include "rcm_module.h"
46
47 /* cache flags */
48 #define SWAP_CACHE_NEW 0x01
49 #define SWAP_CACHE_STALE 0x02
50 #define SWAP_CACHE_OFFLINED 0x04
51
52 #define SWAP_CMD "/usr/sbin/swap"
53 #define SWAP_DELETE SWAP_CMD" -d %s %ld"
54 #define SWAP_ADD SWAP_CMD" -a %s %ld %ld"
55
56 /* LP64 hard code */
57 #define MAXOFFSET_STRLEN 20
58
59 typedef struct swap_file {
60 char path[MAXPATHLEN];
61 int cache_flags;
62 struct swap_area *areas;
63 struct swap_file *next;
64 struct swap_file *prev;
65 } swap_file_t;
66
67 /* swap file may have multiple swap areas */
68 typedef struct swap_area {
69 off_t start;
70 off_t len;
71 int cache_flags;
72 struct swap_area *next;
73 struct swap_area *prev;
74 } swap_area_t;
75
76 static swap_file_t *cache;
77 static mutex_t cache_lock;
78
79 static int swap_register(rcm_handle_t *);
80 static int swap_unregister(rcm_handle_t *);
81 static int swap_getinfo(rcm_handle_t *, char *, id_t, uint_t,
82 char **, char **, nvlist_t *, rcm_info_t **);
83 static int swap_suspend(rcm_handle_t *, char *, id_t, timespec_t *,
84 uint_t, char **, rcm_info_t **);
85 static int swap_resume(rcm_handle_t *, char *, id_t, uint_t,
86 char **, rcm_info_t **);
87 static int swap_offline(rcm_handle_t *, char *, id_t, uint_t,
88 char **, rcm_info_t **);
89 static int swap_online(rcm_handle_t *, char *, id_t, uint_t,
90 char **, rcm_info_t **);
91 static int swap_remove(rcm_handle_t *, char *, id_t, uint_t,
92 char **, rcm_info_t **);
93
94 static int alloc_usage(char **);
95 static void cache_insert(swap_file_t *);
96 static swap_file_t *cache_lookup(char *);
97 static void cache_remove(swap_file_t *);
98 static void free_cache(void);
99 static int get_dumpdev(char []);
100 static void log_cmd_status(int);
101 static int swap_add(swap_file_t *, char **);
102 static void swap_area_add(swap_file_t *, swap_area_t *);
103 static swap_area_t *swap_area_alloc(swapent_t *);
104 static swap_area_t *swap_area_lookup(swap_file_t *, swapent_t *);
105 static void swap_area_remove(swap_file_t *, swap_area_t *);
106 static int swap_delete(swap_file_t *, char **);
107 static swap_file_t *swap_file_alloc(char *);
108 static void swap_file_free(swap_file_t *);
109 static swaptbl_t *sys_swaptbl(void);
110 static int update_cache(rcm_handle_t *);
111
112 static struct rcm_mod_ops swap_ops =
113 {
114 RCM_MOD_OPS_VERSION,
115 swap_register,
116 swap_unregister,
117 swap_getinfo,
118 swap_suspend,
119 swap_resume,
120 swap_offline,
121 swap_online,
122 swap_remove,
123 NULL,
124 NULL,
125 NULL
126 };
127
128 struct rcm_mod_ops *
rcm_mod_init()129 rcm_mod_init()
130 {
131 return (&swap_ops);
132 }
133
134 const char *
rcm_mod_info()135 rcm_mod_info()
136 {
137 return ("RCM Swap module 1.5");
138 }
139
140 int
rcm_mod_fini()141 rcm_mod_fini()
142 {
143 free_cache();
144 (void) mutex_destroy(&cache_lock);
145
146 return (RCM_SUCCESS);
147 }
148
149 static int
swap_register(rcm_handle_t * hdl)150 swap_register(rcm_handle_t *hdl)
151 {
152 return (update_cache(hdl));
153 }
154
155 static int
swap_unregister(rcm_handle_t * hdl)156 swap_unregister(rcm_handle_t *hdl)
157 {
158 swap_file_t *sf;
159
160 (void) mutex_lock(&cache_lock);
161 while ((sf = cache) != NULL) {
162 cache = cache->next;
163 (void) rcm_unregister_interest(hdl, sf->path, 0);
164 swap_file_free(sf);
165 }
166 (void) mutex_unlock(&cache_lock);
167
168 return (RCM_SUCCESS);
169 }
170
171 /*ARGSUSED*/
172 static int
swap_getinfo(rcm_handle_t * hdl,char * rsrcname,id_t id,uint_t flags,char ** infostr,char ** errstr,nvlist_t * props,rcm_info_t ** dependent)173 swap_getinfo(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
174 char **infostr, char **errstr, nvlist_t *props, rcm_info_t **dependent)
175 {
176 assert(rsrcname != NULL && infostr != NULL);
177
178 (void) mutex_lock(&cache_lock);
179 if (cache_lookup(rsrcname) == NULL) {
180 rcm_log_message(RCM_ERROR, "unknown resource: %s\n",
181 rsrcname);
182 (void) mutex_unlock(&cache_lock);
183 return (RCM_FAILURE);
184 }
185 (void) mutex_unlock(&cache_lock);
186 (void) alloc_usage(infostr);
187
188 return (RCM_SUCCESS);
189 }
190
191 /*
192 * Remove swap space to maintain availability of anonymous pages
193 * during device suspension. Swap will be reconfigured upon resume.
194 * Fail if operation will unconfigure dump device.
195 */
196 /*ARGSUSED*/
197 static int
swap_suspend(rcm_handle_t * hdl,char * rsrcname,id_t id,timespec_t * interval,uint_t flags,char ** errstr,rcm_info_t ** dependent)198 swap_suspend(rcm_handle_t *hdl, char *rsrcname, id_t id, timespec_t *interval,
199 uint_t flags, char **errstr, rcm_info_t **dependent)
200 {
201 swap_file_t *sf;
202 int rv;
203
204 assert(rsrcname != NULL && errstr != NULL);
205
206 if (flags & RCM_QUERY)
207 return (RCM_SUCCESS);
208
209 (void) mutex_lock(&cache_lock);
210 if ((sf = cache_lookup(rsrcname)) == NULL) {
211 (void) mutex_unlock(&cache_lock);
212 return (RCM_SUCCESS);
213 }
214
215 rv = swap_delete(sf, errstr);
216 (void) mutex_unlock(&cache_lock);
217
218 return (rv);
219 }
220
221 /*ARGSUSED*/
222 static int
swap_resume(rcm_handle_t * hdl,char * rsrcname,id_t id,uint_t flags,char ** errstr,rcm_info_t ** dependent)223 swap_resume(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
224 char **errstr, rcm_info_t **dependent)
225 {
226 swap_file_t *sf;
227 int rv;
228
229 assert(rsrcname != NULL && errstr != NULL);
230
231 (void) mutex_lock(&cache_lock);
232 if ((sf = cache_lookup(rsrcname)) == NULL) {
233 (void) mutex_unlock(&cache_lock);
234 return (RCM_SUCCESS);
235 }
236
237 rv = swap_add(sf, errstr);
238 (void) mutex_unlock(&cache_lock);
239
240 return (rv);
241 }
242
243 /*
244 * By default, reject offline request. If forced, attempt to
245 * delete swap. Fail if operation will unconfigure dump device.
246 */
247 /*ARGSUSED*/
248 static int
swap_offline(rcm_handle_t * hdl,char * rsrcname,id_t id,uint_t flags,char ** errstr,rcm_info_t ** dependent)249 swap_offline(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
250 char **errstr, rcm_info_t **dependent)
251 {
252 swap_file_t *sf;
253 int rv;
254
255 assert(rsrcname != NULL && errstr != NULL);
256
257 if ((flags & RCM_FORCE) && (flags & RCM_QUERY))
258 return (RCM_SUCCESS);
259
260 (void) mutex_lock(&cache_lock);
261 if ((sf = cache_lookup(rsrcname)) == NULL) {
262 (void) mutex_unlock(&cache_lock);
263 return (RCM_SUCCESS);
264 }
265
266 if (flags & RCM_FORCE) {
267 rv = swap_delete(sf, errstr);
268 (void) mutex_unlock(&cache_lock);
269 return (rv);
270 }
271 /* default reject */
272 (void) mutex_unlock(&cache_lock);
273 (void) alloc_usage(errstr);
274
275 return (RCM_FAILURE);
276 }
277
278 /*ARGSUSED*/
279 static int
swap_online(rcm_handle_t * hdl,char * rsrcname,id_t id,uint_t flags,char ** errstr,rcm_info_t ** dependent)280 swap_online(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
281 char **errstr, rcm_info_t **dependent)
282 {
283 swap_file_t *sf;
284 int rv;
285
286 assert(rsrcname != NULL && errstr != NULL);
287
288 (void) mutex_lock(&cache_lock);
289 if ((sf = cache_lookup(rsrcname)) == NULL) {
290 (void) mutex_unlock(&cache_lock);
291 return (RCM_SUCCESS);
292 }
293
294 rv = swap_add(sf, errstr);
295 (void) mutex_unlock(&cache_lock);
296
297 return (rv);
298 }
299
300 /*ARGSUSED*/
301 static int
swap_remove(rcm_handle_t * hdl,char * rsrcname,id_t id,uint_t flags,char ** errstr,rcm_info_t ** dependent)302 swap_remove(rcm_handle_t *hdl, char *rsrcname, id_t id, uint_t flags,
303 char **errstr, rcm_info_t **dependent)
304 {
305 swap_file_t *sf;
306
307 assert(rsrcname != NULL);
308
309 (void) mutex_lock(&cache_lock);
310 if ((sf = cache_lookup(rsrcname)) == NULL) {
311 (void) mutex_unlock(&cache_lock);
312 return (RCM_SUCCESS);
313 }
314 /* RCM framework handles unregistration */
315 cache_remove(sf);
316 swap_file_free(sf);
317 (void) mutex_unlock(&cache_lock);
318
319 return (RCM_SUCCESS);
320 }
321
322 /*
323 * Delete all swap areas for swap file.
324 * Invoke swap(8) instead of swapctl(2) to
325 * handle relocation of dump device.
326 * If dump device is configured, fail if
327 * unable to relocate dump.
328 *
329 * Call with cache_lock held.
330 */
331 static int
swap_delete(swap_file_t * sf,char ** errstr)332 swap_delete(swap_file_t *sf, char **errstr)
333 {
334 swap_area_t *sa;
335 char cmd[sizeof (SWAP_DELETE) + MAXPATHLEN +
336 MAXOFFSET_STRLEN];
337 char dumpdev[MAXPATHLEN];
338 int have_dump = 1;
339 int stat;
340 int rv = RCM_SUCCESS;
341
342 if (get_dumpdev(dumpdev) == 0 && dumpdev[0] == '\0')
343 have_dump = 0;
344
345 for (sa = sf->areas; sa != NULL; sa = sa->next) {
346 /* swap(8) is not idempotent */
347 if (sa->cache_flags & SWAP_CACHE_OFFLINED) {
348 continue;
349 }
350
351 (void) snprintf(cmd, sizeof (cmd), SWAP_DELETE, sf->path,
352 sa->start);
353 rcm_log_message(RCM_TRACE1, "%s\n", cmd);
354 if ((stat = rcm_exec_cmd(cmd)) != 0) {
355 log_cmd_status(stat);
356 *errstr = strdup(gettext("unable to delete swap"));
357 rv = RCM_FAILURE;
358 goto out;
359 }
360 sa->cache_flags |= SWAP_CACHE_OFFLINED;
361
362 /*
363 * Fail on removal of dump device.
364 */
365 if (have_dump == 0)
366 continue;
367
368 if (get_dumpdev(dumpdev) != 0) {
369 rcm_log_message(RCM_WARNING, "unable to "
370 "check for removal of dump device\n");
371 } else if (dumpdev[0] == '\0') {
372 rcm_log_message(RCM_DEBUG, "removed dump: "
373 "attempting recovery\n");
374
375 /*
376 * Restore dump
377 */
378 (void) snprintf(cmd, sizeof (cmd), SWAP_ADD,
379 sf->path, sa->start, sa->len);
380 rcm_log_message(RCM_TRACE1, "%s\n", cmd);
381 if ((stat = rcm_exec_cmd(cmd)) != 0) {
382 log_cmd_status(stat);
383 rcm_log_message(RCM_ERROR,
384 "failed to restore dump\n");
385 } else {
386 sa->cache_flags &= ~SWAP_CACHE_OFFLINED;
387 rcm_log_message(RCM_DEBUG, "dump restored\n");
388 }
389 *errstr = strdup(gettext("unable to relocate dump"));
390 rv = RCM_FAILURE;
391 goto out;
392 }
393 }
394 sf->cache_flags |= SWAP_CACHE_OFFLINED;
395 out:
396 return (rv);
397 }
398
399 /*
400 * Invoke swap(8) to add each registered swap area.
401 *
402 * Call with cache_lock held.
403 */
404 static int
swap_add(swap_file_t * sf,char ** errstr)405 swap_add(swap_file_t *sf, char **errstr)
406 {
407 swap_area_t *sa;
408 char cmd[sizeof (SWAP_ADD) + MAXPATHLEN +
409 (2 * MAXOFFSET_STRLEN)];
410 int stat;
411 int rv = RCM_SUCCESS;
412
413 for (sa = sf->areas; sa != NULL; sa = sa->next) {
414 /* swap(8) is not idempotent */
415 if (!(sa->cache_flags & SWAP_CACHE_OFFLINED)) {
416 continue;
417 }
418
419 (void) snprintf(cmd, sizeof (cmd),
420 SWAP_ADD, sf->path, sa->start, sa->len);
421 rcm_log_message(RCM_TRACE1, "%s\n", cmd);
422 if ((stat = rcm_exec_cmd(cmd)) != 0) {
423 log_cmd_status(stat);
424 *errstr = strdup(gettext("unable to add swap"));
425 rv = RCM_FAILURE;
426 break;
427 } else {
428 sa->cache_flags &= ~SWAP_CACHE_OFFLINED;
429 sf->cache_flags &= ~SWAP_CACHE_OFFLINED;
430 }
431 }
432
433 return (rv);
434 }
435
436 static int
update_cache(rcm_handle_t * hdl)437 update_cache(rcm_handle_t *hdl)
438 {
439 swaptbl_t *swt;
440 swap_file_t *sf, *stale_sf;
441 swap_area_t *sa, *stale_sa;
442 int i;
443 int rv = RCM_SUCCESS;
444
445 if ((swt = sys_swaptbl()) == NULL) {
446 rcm_log_message(RCM_ERROR, "failed to read "
447 "current swap configuration\n");
448 return (RCM_FAILURE);
449 }
450
451 (void) mutex_lock(&cache_lock);
452
453 /*
454 * cache pass 1 - mark everyone stale
455 */
456 for (sf = cache; sf != NULL; sf = sf->next) {
457 sf->cache_flags |= SWAP_CACHE_STALE;
458 for (sa = sf->areas; sa != NULL; sa = sa->next) {
459 sa->cache_flags |= SWAP_CACHE_STALE;
460 }
461 }
462
463 /*
464 * add new entries
465 */
466 for (i = 0; i < swt->swt_n; i++) {
467 if (swt->swt_ent[i].ste_flags & (ST_INDEL|ST_DOINGDEL)) {
468 continue;
469 }
470
471 /*
472 * assure swap_file_t
473 */
474 if ((sf = cache_lookup(swt->swt_ent[i].ste_path)) == NULL) {
475 if ((sf = swap_file_alloc(swt->swt_ent[i].ste_path)) ==
476 NULL) {
477 free(swt);
478 return (RCM_FAILURE);
479 }
480 sf->cache_flags |= SWAP_CACHE_NEW;
481 cache_insert(sf);
482 } else {
483 sf->cache_flags &= ~SWAP_CACHE_STALE;
484 }
485
486 /*
487 * assure swap_area_t
488 */
489 if ((sa = swap_area_lookup(sf, &swt->swt_ent[i])) == NULL) {
490 if ((sa = swap_area_alloc(&swt->swt_ent[i])) == NULL) {
491 free(swt);
492 return (RCM_FAILURE);
493 }
494 swap_area_add(sf, sa);
495 } else {
496 sa->cache_flags &= ~SWAP_CACHE_STALE;
497 }
498 }
499
500 free(swt);
501
502 /*
503 * cache pass 2
504 *
505 * swap_file_t - skip offlined, register new, unregister/remove stale
506 * swap_area_t - skip offlined, remove stale
507 */
508 sf = cache;
509 while (sf != NULL) {
510 sa = sf->areas;
511 while (sa != NULL) {
512 if (sa->cache_flags & SWAP_CACHE_OFFLINED) {
513 sa->cache_flags &= ~SWAP_CACHE_STALE;
514 sa = sa->next;
515 continue;
516 }
517 if (sa->cache_flags & SWAP_CACHE_STALE) {
518 stale_sa = sa;
519 sa = sa->next;
520 swap_area_remove(sf, stale_sa);
521 free(stale_sa);
522 continue;
523 }
524 sa = sa->next;
525 }
526
527 if (sf->cache_flags & SWAP_CACHE_OFFLINED) {
528 sf->cache_flags &= ~SWAP_CACHE_STALE;
529 sf = sf->next;
530 continue;
531 }
532
533 if (sf->cache_flags & SWAP_CACHE_STALE) {
534 if (rcm_unregister_interest(hdl, sf->path, 0) !=
535 RCM_SUCCESS) {
536 rcm_log_message(RCM_ERROR, "failed to register "
537 "%s\n", sf->path);
538 }
539 stale_sf = sf;
540 sf = sf->next;
541 cache_remove(stale_sf);
542 swap_file_free(stale_sf);
543 continue;
544 }
545
546 if (!(sf->cache_flags & SWAP_CACHE_NEW)) {
547 sf = sf->next;
548 continue;
549 }
550
551 if (rcm_register_interest(hdl, sf->path, 0, NULL) !=
552 RCM_SUCCESS) {
553 rcm_log_message(RCM_ERROR, "failed to register %s\n",
554 sf->path);
555 rv = RCM_FAILURE;
556 } else {
557 rcm_log_message(RCM_DEBUG, "registered %s\n",
558 sf->path);
559 sf->cache_flags &= ~SWAP_CACHE_NEW;
560 }
561 sf = sf->next;
562 }
563 (void) mutex_unlock(&cache_lock);
564
565 return (rv);
566 }
567
568 /*
569 * Returns system swap table.
570 */
571 static swaptbl_t *
sys_swaptbl()572 sys_swaptbl()
573 {
574 swaptbl_t *swt;
575 char *cp;
576 int i, n;
577 size_t tbl_size;
578
579 if ((n = swapctl(SC_GETNSWP, NULL)) == -1)
580 return (NULL);
581
582 tbl_size = sizeof (int) + n * sizeof (swapent_t) + n * MAXPATHLEN;
583 if ((swt = (swaptbl_t *)malloc(tbl_size)) == NULL)
584 return (NULL);
585
586 swt->swt_n = n;
587 cp = (char *)swt + (sizeof (int) + n * sizeof (swapent_t));
588 for (i = 0; i < n; i++) {
589 swt->swt_ent[i].ste_path = cp;
590 cp += MAXPATHLEN;
591 }
592
593 if ((n = swapctl(SC_LIST, swt)) == -1) {
594 free(swt);
595 return (NULL);
596 }
597
598 if (n != swt->swt_n) {
599 /* mismatch, try again */
600 free(swt);
601 return (sys_swaptbl());
602 }
603
604 return (swt);
605 }
606
607 static int
get_dumpdev(char dumpdev[])608 get_dumpdev(char dumpdev[])
609 {
610 int fd;
611 int rv = 0;
612 char *err;
613
614 if ((fd = open("/dev/dump", O_RDONLY)) == -1) {
615 rcm_log_message(RCM_ERROR, "failed to open /dev/dump\n");
616 return (-1);
617 }
618
619 if (ioctl(fd, DIOCGETDEV, dumpdev) == -1) {
620 if (errno == ENODEV) {
621 dumpdev[0] = '\0';
622 } else {
623 rcm_log_message(RCM_ERROR, "ioctl: %s\n",
624 ((err = strerror(errno)) == NULL) ? "" : err);
625 rv = -1;
626 }
627 }
628 (void) close(fd);
629
630 return (rv);
631 }
632
633 static void
free_cache(void)634 free_cache(void)
635 {
636 swap_file_t *sf;
637
638 (void) mutex_lock(&cache_lock);
639 while ((sf = cache) != NULL) {
640 cache = cache->next;
641 swap_file_free(sf);
642 }
643 (void) mutex_unlock(&cache_lock);
644
645 }
646
647 /*
648 * Call with cache_lock held.
649 */
650 static void
swap_file_free(swap_file_t * sf)651 swap_file_free(swap_file_t *sf)
652 {
653 swap_area_t *sa;
654
655 assert(sf != NULL);
656
657 while ((sa = sf->areas) != NULL) {
658 sf->areas = sf->areas->next;
659 free(sa);
660 }
661 free(sf);
662 }
663
664 /*
665 * Call with cache_lock held.
666 */
667 static void
cache_insert(swap_file_t * ent)668 cache_insert(swap_file_t *ent)
669 {
670 ent->next = cache;
671 if (ent->next)
672 ent->next->prev = ent;
673 ent->prev = NULL;
674 cache = ent;
675 }
676
677 /*
678 * Call with cache_lock held.
679 */
680 static swap_file_t *
cache_lookup(char * rsrc)681 cache_lookup(char *rsrc)
682 {
683 swap_file_t *sf;
684
685 for (sf = cache; sf != NULL; sf = sf->next) {
686 if (strcmp(rsrc, sf->path) == 0) {
687 return (sf);
688 }
689 }
690 return (NULL);
691 }
692
693 /*
694 * Call with cache_lock held.
695 */
696 static void
cache_remove(swap_file_t * ent)697 cache_remove(swap_file_t *ent)
698 {
699 assert(ent != NULL);
700
701 if (ent->next != NULL) {
702 ent->next->prev = ent->prev;
703 }
704 if (ent->prev != NULL) {
705 ent->prev->next = ent->next;
706 } else {
707 cache = ent->next;
708 }
709 ent->next = NULL;
710 ent->prev = NULL;
711 }
712
713 /*
714 * Call with cache_lock held.
715 */
716 static void
swap_area_add(swap_file_t * sf,swap_area_t * sa)717 swap_area_add(swap_file_t *sf, swap_area_t *sa)
718 {
719 sa->next = sf->areas;
720 if (sa->next)
721 sa->next->prev = sa;
722 sa->prev = NULL;
723 sf->areas = sa;
724 }
725
726 /*
727 * Call with cache_lock held.
728 */
729 static void
swap_area_remove(swap_file_t * sf,swap_area_t * ent)730 swap_area_remove(swap_file_t *sf, swap_area_t *ent)
731 {
732 assert(sf != NULL && ent != NULL);
733
734 if (ent->next != NULL) {
735 ent->next->prev = ent->prev;
736 }
737 if (ent->prev != NULL) {
738 ent->prev->next = ent->next;
739 } else {
740 sf->areas = ent->next;
741 }
742 ent->next = NULL;
743 ent->prev = NULL;
744 }
745
746 static swap_file_t *
swap_file_alloc(char * rsrc)747 swap_file_alloc(char *rsrc)
748 {
749 swap_file_t *sf;
750
751 if ((sf = calloc(1, sizeof (*sf))) == NULL) {
752 rcm_log_message(RCM_ERROR, "calloc failure\n");
753 return (NULL);
754 }
755 (void) strlcpy(sf->path, rsrc, sizeof (sf->path));
756
757 return (sf);
758 }
759
760 static swap_area_t *
swap_area_alloc(swapent_t * swt_ent)761 swap_area_alloc(swapent_t *swt_ent)
762 {
763 swap_area_t *sa;
764
765 if ((sa = calloc(1, sizeof (*sa))) == NULL) {
766 rcm_log_message(RCM_ERROR, "calloc failure\n");
767 return (NULL);
768 }
769 sa->start = swt_ent->ste_start;
770 sa->len = swt_ent->ste_length;
771
772 return (sa);
773 }
774
775 /*
776 * Call with cache_lock held.
777 */
778 static swap_area_t *
swap_area_lookup(swap_file_t * sf,swapent_t * swt_ent)779 swap_area_lookup(swap_file_t *sf, swapent_t *swt_ent)
780 {
781 swap_area_t *sa;
782
783 assert(sf != NULL && swt_ent != NULL);
784 assert(strcmp(sf->path, swt_ent->ste_path) == 0);
785
786 for (sa = sf->areas; sa != NULL; sa = sa->next) {
787 if (sa->start == swt_ent->ste_start &&
788 sa->len == swt_ent->ste_length) {
789 return (sa);
790 }
791 }
792 return (NULL);
793 }
794
795 /*
796 * All-purpose usage string.
797 */
798 static int
alloc_usage(char ** cpp)799 alloc_usage(char **cpp)
800 {
801 if ((*cpp = strdup(gettext("swap area"))) == NULL) {
802 rcm_log_message(RCM_ERROR, "strdup failure\n");
803 return (-1);
804 }
805 return (0);
806 }
807
808 static void
log_cmd_status(int stat)809 log_cmd_status(int stat)
810 {
811 char *err;
812
813 if (stat == -1) {
814 rcm_log_message(RCM_ERROR, "wait: %s\n",
815 ((err = strerror(errno)) == NULL) ? "" : err);
816 } else if (WIFEXITED(stat)) {
817 rcm_log_message(RCM_ERROR, "exit status: %d\n",
818 WEXITSTATUS(stat));
819 } else {
820 rcm_log_message(RCM_ERROR, "wait status: %d\n", stat);
821 }
822 }
823