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