2010-08-14 21:59:25 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2010-05-09 20:44:11 +04:00
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
2012-04-12 02:20:58 +04:00
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
2010-05-09 20:44:11 +04:00
( at your option ) any later version .
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
2012-04-12 02:20:58 +04:00
Lesser General Public License for more details .
2010-05-09 20:44:11 +04:00
2012-04-12 02:20:58 +04:00
You should have received a copy of the GNU Lesser General Public License
2010-05-09 20:44:11 +04:00
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <errno.h>
# include <limits.h>
# include <unistd.h>
# include <fcntl.h>
# include <sys/epoll.h>
# include <sys/stat.h>
# include <sys/swap.h>
2010-10-12 06:07:43 +04:00
# include <libudev.h>
2010-05-09 20:44:11 +04:00
# include "unit.h"
# include "swap.h"
# include "load-fragment.h"
# include "load-dropin.h"
# include "unit-name.h"
# include "dbus-swap.h"
2010-06-18 06:22:59 +04:00
# include "special.h"
2010-10-22 18:11:50 +04:00
# include "bus-errors.h"
2011-01-20 20:22:03 +03:00
# include "exit-status.h"
2011-03-17 06:02:35 +03:00
# include "def.h"
2012-05-07 23:36:12 +04:00
# include "path-util.h"
2012-08-25 01:00:13 +04:00
# include "virt.h"
2013-11-25 18:26:30 +04:00
# include "udev-util.h"
2010-05-09 20:44:11 +04:00
static const UnitActiveState state_translation_table [ _SWAP_STATE_MAX ] = {
[ SWAP_DEAD ] = UNIT_INACTIVE ,
2010-10-12 06:07:43 +04:00
[ SWAP_ACTIVATING ] = UNIT_ACTIVATING ,
2013-11-25 18:26:30 +04:00
[ SWAP_ACTIVATING_DONE ] = UNIT_ACTIVE ,
2010-05-09 20:44:11 +04:00
[ SWAP_ACTIVE ] = UNIT_ACTIVE ,
2010-10-12 06:07:43 +04:00
[ SWAP_DEACTIVATING ] = UNIT_DEACTIVATING ,
[ SWAP_ACTIVATING_SIGTERM ] = UNIT_DEACTIVATING ,
[ SWAP_ACTIVATING_SIGKILL ] = UNIT_DEACTIVATING ,
[ SWAP_DEACTIVATING_SIGTERM ] = UNIT_DEACTIVATING ,
[ SWAP_DEACTIVATING_SIGKILL ] = UNIT_DEACTIVATING ,
2010-08-31 02:23:34 +04:00
[ SWAP_FAILED ] = UNIT_FAILED
2010-05-09 20:44:11 +04:00
} ;
2013-11-20 00:12:59 +04:00
static int swap_dispatch_timer ( sd_event_source * source , usec_t usec , void * userdata ) ;
static int swap_dispatch_io ( sd_event_source * source , int fd , uint32_t revents , void * userdata ) ;
2010-10-12 06:07:43 +04:00
static void swap_unset_proc_swaps ( Swap * s ) {
2013-11-26 00:08:39 +04:00
assert ( s ) ;
if ( ! s - > from_proc_swaps )
return ;
free ( s - > parameters_proc_swaps . what ) ;
s - > parameters_proc_swaps . what = NULL ;
s - > from_proc_swaps = false ;
}
static int swap_set_devnode ( Swap * s , const char * devnode ) {
2012-09-19 12:52:11 +04:00
Hashmap * swaps ;
2013-11-25 18:26:30 +04:00
Swap * first ;
2013-11-26 00:08:39 +04:00
int r ;
2010-10-12 06:07:43 +04:00
assert ( s ) ;
2014-08-13 03:00:18 +04:00
r = hashmap_ensure_allocated ( & UNIT ( s ) - > manager - > swaps_by_devnode , & string_hash_ops ) ;
2013-11-26 00:08:39 +04:00
if ( r < 0 )
return r ;
2010-10-12 06:07:43 +04:00
2013-11-26 00:08:39 +04:00
swaps = UNIT ( s ) - > manager - > swaps_by_devnode ;
2010-10-12 06:07:43 +04:00
2013-11-26 00:08:39 +04:00
if ( s - > devnode ) {
first = hashmap_get ( swaps , s - > devnode ) ;
2010-10-12 06:07:43 +04:00
2013-11-26 00:08:39 +04:00
LIST_REMOVE ( same_devnode , first , s ) ;
if ( first )
hashmap_replace ( swaps , first - > devnode , first ) ;
else
hashmap_remove ( swaps , s - > devnode ) ;
2013-11-25 18:26:30 +04:00
2013-11-26 00:08:39 +04:00
free ( s - > devnode ) ;
s - > devnode = NULL ;
}
if ( devnode ) {
s - > devnode = strdup ( devnode ) ;
if ( ! s - > devnode )
return - ENOMEM ;
first = hashmap_get ( swaps , s - > devnode ) ;
LIST_PREPEND ( same_devnode , first , s ) ;
return hashmap_replace ( swaps , first - > devnode , first ) ;
}
return 0 ;
2010-10-12 06:07:43 +04:00
}
2011-11-19 05:47:09 +04:00
static void swap_init ( Unit * u ) {
2010-05-10 01:41:03 +04:00
Swap * s = SWAP ( u ) ;
assert ( s ) ;
2012-01-15 15:25:20 +04:00
assert ( UNIT ( s ) - > load_state = = UNIT_STUB ) ;
2010-05-10 01:41:03 +04:00
2013-11-04 20:47:43 +04:00
s - > timeout_usec = u - > manager - > default_timeout_start_usec ;
2010-10-12 06:07:43 +04:00
2012-01-15 15:04:08 +04:00
s - > exec_context . std_output = u - > manager - > default_std_output ;
s - > exec_context . std_error = u - > manager - > default_std_error ;
2014-02-25 02:50:10 +04:00
2012-05-22 21:23:33 +04:00
s - > parameters_proc_swaps . priority = s - > parameters_fragment . priority = - 1 ;
2010-10-12 06:07:43 +04:00
2012-02-03 07:47:32 +04:00
s - > control_command_id = _SWAP_EXEC_COMMAND_INVALID ;
2011-04-14 05:55:03 +04:00
2013-11-25 18:26:30 +04:00
u - > ignore_on_isolate = true ;
2010-10-12 06:07:43 +04:00
}
static void swap_unwatch_control_pid ( Swap * s ) {
assert ( s ) ;
if ( s - > control_pid < = 0 )
return ;
unit_unwatch_pid ( UNIT ( s ) , s - > control_pid ) ;
s - > control_pid = 0 ;
2010-05-10 01:41:03 +04:00
}
2010-05-14 04:29:45 +04:00
static void swap_done ( Unit * u ) {
Swap * s = SWAP ( u ) ;
2010-05-09 20:44:11 +04:00
2010-05-14 04:29:45 +04:00
assert ( s ) ;
2010-05-09 20:44:11 +04:00
2010-10-12 06:07:43 +04:00
swap_unset_proc_swaps ( s ) ;
2013-11-26 00:08:39 +04:00
swap_set_devnode ( s , NULL ) ;
2010-10-12 06:07:43 +04:00
2010-05-14 04:29:45 +04:00
free ( s - > what ) ;
2010-10-12 06:07:43 +04:00
s - > what = NULL ;
2010-05-14 04:29:45 +04:00
free ( s - > parameters_fragment . what ) ;
2012-05-22 21:23:33 +04:00
s - > parameters_fragment . what = NULL ;
2010-10-12 06:07:43 +04:00
2014-09-24 16:29:05 +04:00
free ( s - > parameters_fragment . discard ) ;
s - > parameters_fragment . discard = NULL ;
2013-11-27 23:23:18 +04:00
s - > exec_runtime = exec_runtime_unref ( s - > exec_runtime ) ;
2010-10-12 06:07:43 +04:00
exec_command_done_array ( s - > exec_command , _SWAP_EXEC_COMMAND_MAX ) ;
s - > control_command = NULL ;
swap_unwatch_control_pid ( s ) ;
2013-11-20 00:12:59 +04:00
s - > timer_event_source = sd_event_source_unref ( s - > timer_event_source ) ;
}
static int swap_arm_timer ( Swap * s ) {
int r ;
assert ( s ) ;
if ( s - > timeout_usec < = 0 ) {
s - > timer_event_source = sd_event_source_unref ( s - > timer_event_source ) ;
return 0 ;
}
if ( s - > timer_event_source ) {
r = sd_event_source_set_time ( s - > timer_event_source , now ( CLOCK_MONOTONIC ) + s - > timeout_usec ) ;
if ( r < 0 )
return r ;
return sd_event_source_set_enabled ( s - > timer_event_source , SD_EVENT_ONESHOT ) ;
}
2014-03-24 05:49:09 +04:00
return sd_event_add_time (
UNIT ( s ) - > manager - > event ,
& s - > timer_event_source ,
CLOCK_MONOTONIC ,
now ( CLOCK_MONOTONIC ) + s - > timeout_usec , 0 ,
swap_dispatch_timer , s ) ;
2010-05-09 20:44:11 +04:00
}
2010-08-25 22:37:04 +04:00
static int swap_add_device_links ( Swap * s ) {
SwapParameters * p ;
assert ( s ) ;
if ( ! s - > what )
return 0 ;
if ( s - > from_fragment )
p = & s - > parameters_fragment ;
else
return 0 ;
2010-11-22 23:06:38 +03:00
if ( is_device_path ( s - > what ) )
2013-11-25 18:26:30 +04:00
return unit_add_node_link ( UNIT ( s ) , s - > what , ! p - > noauto & & UNIT ( s ) - > manager - > running_as = = SYSTEMD_SYSTEM ) ;
2010-11-22 23:06:38 +03:00
else
/* File based swap devices need to be ordered after
2012-04-24 18:42:42 +04:00
* systemd - remount - fs . service , since they might need a
2010-11-22 23:06:38 +03:00
* writable file system . */
2012-04-24 18:42:42 +04:00
return unit_add_dependency_by_name ( UNIT ( s ) , UNIT_AFTER , SPECIAL_REMOUNT_FS_SERVICE , NULL , true ) ;
2010-08-25 22:37:04 +04:00
}
2010-07-13 00:55:27 +04:00
static int swap_add_default_dependencies ( Swap * s ) {
2013-08-21 18:48:56 +04:00
bool nofail = false , noauto = false ;
2010-07-13 00:55:27 +04:00
int r ;
assert ( s ) ;
2012-09-18 19:11:12 +04:00
if ( UNIT ( s ) - > manager - > running_as ! = SYSTEMD_SYSTEM )
2012-05-22 21:23:33 +04:00
return 0 ;
2010-07-13 00:55:27 +04:00
2012-08-25 01:07:03 +04:00
if ( detect_container ( NULL ) > 0 )
return 0 ;
2012-05-22 21:23:33 +04:00
r = unit_add_two_dependencies_by_name ( UNIT ( s ) , UNIT_BEFORE , UNIT_CONFLICTS , SPECIAL_UMOUNT_TARGET , NULL , true ) ;
if ( r < 0 )
return r ;
2010-07-13 00:55:27 +04:00
2013-08-21 18:48:56 +04:00
if ( s - > from_fragment ) {
SwapParameters * p = & s - > parameters_fragment ;
nofail = p - > nofail ;
noauto = p - > noauto ;
}
if ( ! noauto ) {
2013-09-16 03:08:32 +04:00
if ( nofail )
2013-11-25 18:26:30 +04:00
r = unit_add_dependency_by_name_inverse ( UNIT ( s ) , UNIT_WANTS , SPECIAL_SWAP_TARGET , NULL , true ) ;
2013-09-16 03:08:32 +04:00
else
2013-11-25 18:26:30 +04:00
r = unit_add_two_dependencies_by_name_inverse ( UNIT ( s ) , UNIT_AFTER , UNIT_REQUIRES , SPECIAL_SWAP_TARGET , NULL , true ) ;
2013-08-21 18:48:56 +04:00
if ( r < 0 )
return r ;
}
2010-07-13 00:55:27 +04:00
return 0 ;
}
2010-05-14 04:29:45 +04:00
static int swap_verify ( Swap * s ) {
bool b ;
2013-04-18 11:11:22 +04:00
_cleanup_free_ char * e = NULL ;
2010-05-14 04:29:45 +04:00
2012-01-15 15:25:20 +04:00
if ( UNIT ( s ) - > load_state ! = UNIT_LOADED )
2013-11-25 18:26:30 +04:00
return 0 ;
2010-05-14 04:29:45 +04:00
2012-09-19 19:06:28 +04:00
e = unit_name_from_path ( s - > what , " .swap " ) ;
2013-11-25 18:26:30 +04:00
if ( ! e )
2012-09-19 19:06:28 +04:00
return log_oom ( ) ;
2010-05-14 04:29:45 +04:00
b = unit_has_name ( UNIT ( s ) , e ) ;
if ( ! b ) {
2013-11-25 18:26:30 +04:00
log_error_unit ( UNIT ( s ) - > id , " %s: Value of \" What \" and unit name do not match, not loading. " , UNIT ( s ) - > id ) ;
2010-05-14 04:29:45 +04:00
return - EINVAL ;
}
2012-07-20 01:47:10 +04:00
if ( s - > exec_context . pam_name & & s - > kill_context . kill_mode ! = KILL_CONTROL_GROUP ) {
2013-11-25 18:26:30 +04:00
log_error_unit ( UNIT ( s ) - > id , " %s has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load. " , UNIT ( s ) - > id ) ;
2010-10-12 06:07:43 +04:00
return - EINVAL ;
}
2010-05-14 04:29:45 +04:00
return 0 ;
}
2013-11-26 00:08:39 +04:00
static int swap_load_devnode ( Swap * s ) {
_cleanup_udev_device_unref_ struct udev_device * d = NULL ;
struct stat st ;
const char * p ;
assert ( s ) ;
if ( stat ( s - > what , & st ) < 0 | | ! S_ISBLK ( st . st_mode ) )
return 0 ;
d = udev_device_new_from_devnum ( UNIT ( s ) - > manager - > udev , ' b ' , st . st_rdev ) ;
if ( ! d )
return 0 ;
p = udev_device_get_devnode ( d ) ;
if ( ! p )
return 0 ;
return swap_set_devnode ( s , p ) ;
}
2010-05-09 20:44:11 +04:00
static int swap_load ( Unit * u ) {
int r ;
Swap * s = SWAP ( u ) ;
assert ( s ) ;
2012-01-15 15:04:08 +04:00
assert ( u - > load_state = = UNIT_STUB ) ;
2010-05-09 20:44:11 +04:00
/* Load a .swap file */
2012-09-19 19:38:00 +04:00
r = unit_load_fragment_and_dropin_optional ( u ) ;
if ( r < 0 )
2010-05-09 20:44:11 +04:00
return r ;
2012-01-15 15:04:08 +04:00
if ( u - > load_state = = UNIT_LOADED ) {
2010-05-14 04:29:45 +04:00
2012-01-15 15:25:20 +04:00
if ( UNIT ( s ) - > fragment_path )
2010-05-14 04:29:45 +04:00
s - > from_fragment = true ;
if ( ! s - > what ) {
if ( s - > parameters_fragment . what )
s - > what = strdup ( s - > parameters_fragment . what ) ;
else if ( s - > parameters_proc_swaps . what )
s - > what = strdup ( s - > parameters_proc_swaps . what ) ;
else
2012-01-15 15:04:08 +04:00
s - > what = unit_name_to_path ( u - > id ) ;
2010-05-14 04:29:45 +04:00
if ( ! s - > what )
2010-05-09 20:44:11 +04:00
return - ENOMEM ;
2010-05-14 04:29:45 +04:00
}
2010-05-09 20:44:11 +04:00
path_kill_slashes ( s - > what ) ;
2013-11-25 18:26:30 +04:00
if ( ! UNIT ( s ) - > description ) {
r = unit_set_description ( u , s - > what ) ;
if ( r < 0 )
2010-05-14 04:29:45 +04:00
return r ;
2013-11-25 18:26:30 +04:00
}
2010-05-14 04:29:45 +04:00
2013-09-26 22:14:24 +04:00
r = unit_require_mounts_for ( UNIT ( s ) , s - > what ) ;
2012-09-19 19:38:00 +04:00
if ( r < 0 )
2010-05-09 20:44:11 +04:00
return r ;
2013-09-26 22:14:24 +04:00
r = swap_add_device_links ( s ) ;
2012-09-19 19:38:00 +04:00
if ( r < 0 )
2010-05-13 05:07:16 +04:00
return r ;
2010-05-09 20:44:11 +04:00
2013-11-26 00:08:39 +04:00
r = swap_load_devnode ( s ) ;
if ( r < 0 )
return r ;
2014-03-19 23:40:05 +04:00
r = unit_patch_contexts ( u ) ;
if ( r < 0 )
return r ;
r = unit_add_exec_dependencies ( u , & s - > exec_context ) ;
if ( r < 0 )
return r ;
r = unit_add_default_slice ( u , & s - > cgroup_context ) ;
2013-06-17 23:33:26 +04:00
if ( r < 0 )
return r ;
2012-09-19 19:38:00 +04:00
if ( UNIT ( s ) - > default_dependencies ) {
r = swap_add_default_dependencies ( s ) ;
if ( r < 0 )
2010-07-13 00:55:27 +04:00
return r ;
2012-09-19 19:38:00 +04:00
}
2010-05-09 20:44:11 +04:00
}
return swap_verify ( s ) ;
}
2012-05-22 21:23:33 +04:00
static int swap_add_one (
2010-05-14 04:29:45 +04:00
Manager * m ,
const char * what ,
2010-10-12 06:07:43 +04:00
const char * what_proc_swaps ,
2010-05-14 04:29:45 +04:00
int priority ,
bool noauto ,
2010-08-25 22:37:04 +04:00
bool nofail ,
2010-10-12 06:07:43 +04:00
bool set_flags ) {
2013-04-18 11:11:22 +04:00
_cleanup_free_ char * e = NULL ;
2010-06-02 20:54:50 +04:00
bool delete = false ;
2013-11-25 18:26:30 +04:00
Unit * u = NULL ;
2010-05-09 20:44:11 +04:00
int r ;
2010-05-14 04:29:45 +04:00
SwapParameters * p ;
assert ( m ) ;
assert ( what ) ;
2012-05-22 21:23:33 +04:00
assert ( what_proc_swaps ) ;
2010-05-09 20:44:11 +04:00
2012-01-15 13:53:49 +04:00
e = unit_name_from_path ( what , " .swap " ) ;
if ( ! e )
2012-09-19 19:06:28 +04:00
return log_oom ( ) ;
2010-05-09 20:44:11 +04:00
2010-10-12 06:07:43 +04:00
u = manager_get_unit ( m , e ) ;
2012-05-22 21:23:33 +04:00
if ( u & &
2010-10-12 06:07:43 +04:00
SWAP ( u ) - > from_proc_swaps & &
! path_equal ( SWAP ( u ) - > parameters_proc_swaps . what , what_proc_swaps ) )
return - EEXIST ;
2010-05-14 04:29:45 +04:00
if ( ! u ) {
2010-05-09 20:44:11 +04:00
delete = true ;
2012-01-15 13:53:49 +04:00
u = unit_new ( m , sizeof ( Swap ) ) ;
2012-09-19 19:06:28 +04:00
if ( ! u )
return log_oom ( ) ;
2010-10-12 06:07:43 +04:00
2012-01-15 13:53:49 +04:00
r = unit_add_name ( u , e ) ;
if ( r < 0 )
2010-10-12 06:07:43 +04:00
goto fail ;
2012-01-15 13:53:49 +04:00
SWAP ( u ) - > what = strdup ( what ) ;
if ( ! SWAP ( u ) - > what ) {
2012-09-19 19:38:00 +04:00
r = log_oom ( ) ;
2010-10-12 06:07:43 +04:00
goto fail ;
}
unit_add_to_load_queue ( u ) ;
2010-05-14 04:29:45 +04:00
} else
delete = false ;
2010-05-09 20:44:11 +04:00
2012-05-22 21:23:33 +04:00
p = & SWAP ( u ) - > parameters_proc_swaps ;
2010-05-09 20:44:11 +04:00
2012-05-22 21:23:33 +04:00
if ( ! p - > what ) {
2013-11-25 18:26:30 +04:00
p - > what = strdup ( what_proc_swaps ) ;
if ( ! p - > what ) {
r = - ENOMEM ;
2012-05-22 21:23:33 +04:00
goto fail ;
}
}
2010-10-12 06:07:43 +04:00
2012-05-22 21:23:33 +04:00
if ( set_flags ) {
SWAP ( u ) - > is_active = true ;
SWAP ( u ) - > just_activated = ! SWAP ( u ) - > from_proc_swaps ;
2010-05-14 04:29:45 +04:00
}
2010-05-09 20:44:11 +04:00
2012-05-22 21:23:33 +04:00
SWAP ( u ) - > from_proc_swaps = true ;
2010-05-14 04:29:45 +04:00
p - > priority = priority ;
p - > noauto = noauto ;
2010-08-25 22:37:04 +04:00
p - > nofail = nofail ;
2010-05-09 20:44:11 +04:00
2010-05-14 04:29:45 +04:00
unit_add_to_dbus_queue ( u ) ;
2010-05-09 20:44:11 +04:00
return 0 ;
fail :
2013-01-05 21:00:35 +04:00
log_warning_unit ( e , " Failed to load swap unit: %s " , strerror ( - r ) ) ;
2010-10-12 06:07:43 +04:00
2010-05-14 04:29:45 +04:00
if ( delete & & u )
2010-05-09 20:44:11 +04:00
unit_free ( u ) ;
2010-05-14 04:29:45 +04:00
return r ;
2010-05-09 20:44:11 +04:00
}
2010-10-12 06:07:43 +04:00
static int swap_process_new_swap ( Manager * m , const char * device , int prio , bool set_flags ) {
2013-11-25 18:26:30 +04:00
_cleanup_udev_device_unref_ struct udev_device * d = NULL ;
struct udev_list_entry * item = NULL , * first = NULL ;
const char * dn ;
2010-10-12 06:07:43 +04:00
struct stat st ;
2013-11-25 18:26:30 +04:00
int r ;
2010-10-12 06:07:43 +04:00
assert ( m ) ;
2013-11-25 18:26:30 +04:00
r = swap_add_one ( m , device , device , prio , false , false , set_flags ) ;
if ( r < 0 )
return r ;
2010-10-12 06:07:43 +04:00
2013-11-25 18:26:30 +04:00
/* If this is a block device, then let's add duplicates for
* all other names of this block device */
if ( stat ( device , & st ) < 0 | | ! S_ISBLK ( st . st_mode ) )
return 0 ;
2010-10-12 06:07:43 +04:00
2013-11-25 18:26:30 +04:00
d = udev_device_new_from_devnum ( m - > udev , ' b ' , st . st_rdev ) ;
if ( ! d )
return 0 ;
2010-10-12 06:07:43 +04:00
2013-11-25 18:26:30 +04:00
/* Add the main device node */
dn = udev_device_get_devnode ( d ) ;
if ( dn & & ! streq ( dn , device ) )
swap_add_one ( m , dn , device , prio , false , false , set_flags ) ;
2010-10-12 06:07:43 +04:00
2013-11-25 18:26:30 +04:00
/* Add additional units for all symlinks */
first = udev_device_get_devlinks_list_entry ( d ) ;
udev_list_entry_foreach ( item , first ) {
const char * p ;
2010-10-12 06:07:43 +04:00
2013-11-25 18:26:30 +04:00
/* Don't bother with the /dev/block links */
p = udev_list_entry_get_name ( item ) ;
2010-10-12 06:07:43 +04:00
2013-11-25 18:26:30 +04:00
if ( streq ( p , device ) )
continue ;
2010-10-12 06:07:43 +04:00
2013-11-25 18:26:30 +04:00
if ( path_startswith ( p , " /dev/block/ " ) )
continue ;
2010-10-12 06:07:43 +04:00
2013-11-25 18:26:30 +04:00
if ( stat ( p , & st ) > = 0 )
if ( ! S_ISBLK ( st . st_mode ) | |
st . st_rdev ! = udev_device_get_devnum ( d ) )
continue ;
2010-10-12 06:07:43 +04:00
2013-11-25 18:26:30 +04:00
swap_add_one ( m , p , device , prio , false , false , set_flags ) ;
2010-10-12 06:07:43 +04:00
}
return r ;
}
2010-05-09 20:44:11 +04:00
static void swap_set_state ( Swap * s , SwapState state ) {
SwapState old_state ;
2010-10-12 06:07:43 +04:00
2010-05-09 20:44:11 +04:00
assert ( s ) ;
old_state = s - > state ;
s - > state = state ;
2010-10-12 06:07:43 +04:00
if ( state ! = SWAP_ACTIVATING & &
state ! = SWAP_ACTIVATING_SIGTERM & &
state ! = SWAP_ACTIVATING_SIGKILL & &
2013-11-25 18:26:30 +04:00
state ! = SWAP_ACTIVATING_DONE & &
2010-10-12 06:07:43 +04:00
state ! = SWAP_DEACTIVATING & &
state ! = SWAP_DEACTIVATING_SIGTERM & &
state ! = SWAP_DEACTIVATING_SIGKILL ) {
2013-11-20 00:12:59 +04:00
s - > timer_event_source = sd_event_source_unref ( s - > timer_event_source ) ;
2010-10-12 06:07:43 +04:00
swap_unwatch_control_pid ( s ) ;
s - > control_command = NULL ;
s - > control_command_id = _SWAP_EXEC_COMMAND_INVALID ;
}
2010-05-09 20:44:11 +04:00
if ( state ! = old_state )
2013-01-05 21:00:35 +04:00
log_debug_unit ( UNIT ( s ) - > id ,
" %s changed %s -> %s " ,
UNIT ( s ) - > id ,
swap_state_to_string ( old_state ) ,
swap_state_to_string ( state ) ) ;
2010-05-09 20:44:11 +04:00
2013-11-25 18:26:30 +04:00
unit_notify ( UNIT ( s ) , state_translation_table [ old_state ] , state_translation_table [ state ] , true ) ;
2010-05-09 20:44:11 +04:00
}
static int swap_coldplug ( Unit * u ) {
Swap * s = SWAP ( u ) ;
SwapState new_state = SWAP_DEAD ;
2010-10-12 06:07:43 +04:00
int r ;
2010-05-09 20:44:11 +04:00
assert ( s ) ;
assert ( s - > state = = SWAP_DEAD ) ;
if ( s - > deserialized_state ! = s - > state )
new_state = s - > deserialized_state ;
2010-05-14 04:29:45 +04:00
else if ( s - > from_proc_swaps )
2010-05-09 20:44:11 +04:00
new_state = SWAP_ACTIVE ;
2013-11-25 18:26:30 +04:00
if ( new_state = = s - > state )
return 0 ;
2010-10-12 06:07:43 +04:00
2013-11-25 18:26:30 +04:00
if ( new_state = = SWAP_ACTIVATING | |
new_state = = SWAP_ACTIVATING_SIGTERM | |
new_state = = SWAP_ACTIVATING_SIGKILL | |
new_state = = SWAP_ACTIVATING_DONE | |
new_state = = SWAP_DEACTIVATING | |
new_state = = SWAP_DEACTIVATING_SIGTERM | |
new_state = = SWAP_DEACTIVATING_SIGKILL ) {
2010-10-12 06:07:43 +04:00
2013-11-25 18:26:30 +04:00
if ( s - > control_pid < = 0 )
return - EBADMSG ;
2010-10-12 06:07:43 +04:00
2013-11-25 18:26:30 +04:00
r = unit_watch_pid ( UNIT ( s ) , s - > control_pid ) ;
if ( r < 0 )
return r ;
2010-10-12 06:07:43 +04:00
2013-11-25 18:26:30 +04:00
r = swap_arm_timer ( s ) ;
if ( r < 0 )
return r ;
2010-10-12 06:07:43 +04:00
}
2010-05-09 20:44:11 +04:00
2013-11-25 18:26:30 +04:00
swap_set_state ( s , new_state ) ;
2010-05-09 20:44:11 +04:00
return 0 ;
}
static void swap_dump ( Unit * u , FILE * f , const char * prefix ) {
Swap * s = SWAP ( u ) ;
2010-05-14 04:29:45 +04:00
SwapParameters * p ;
2010-05-09 20:44:11 +04:00
assert ( s ) ;
2010-05-14 04:29:45 +04:00
assert ( f ) ;
if ( s - > from_proc_swaps )
p = & s - > parameters_proc_swaps ;
else if ( s - > from_fragment )
p = & s - > parameters_fragment ;
2012-05-24 19:33:50 +04:00
else
p = NULL ;
2010-05-09 20:44:11 +04:00
fprintf ( f ,
2010-05-14 04:29:45 +04:00
" %sSwap State: %s \n "
2012-02-03 07:47:32 +04:00
" %sResult: %s \n "
2010-05-09 20:44:11 +04:00
" %sWhat: %s \n "
2010-05-14 04:29:45 +04:00
" %sFrom /proc/swaps: %s \n "
" %sFrom fragment: %s \n " ,
2010-05-09 20:44:11 +04:00
prefix , swap_state_to_string ( s - > state ) ,
2012-02-03 07:47:32 +04:00
prefix , swap_result_to_string ( s - > result ) ,
2010-05-09 20:44:11 +04:00
prefix , s - > what ,
2010-05-14 04:29:45 +04:00
prefix , yes_no ( s - > from_proc_swaps ) ,
prefix , yes_no ( s - > from_fragment ) ) ;
2010-10-12 06:07:43 +04:00
2013-11-26 00:08:39 +04:00
if ( s - > devnode )
fprintf ( f , " %sDevice Node: %s \n " , prefix , s - > devnode ) ;
2012-05-24 19:33:50 +04:00
if ( p )
fprintf ( f ,
" %sPriority: %i \n "
" %sNoAuto: %s \n "
2014-09-24 16:29:05 +04:00
" %sNoFail: %s \n "
" %sDiscard: %s \n " ,
2012-05-24 19:33:50 +04:00
prefix , p - > priority ,
prefix , yes_no ( p - > noauto ) ,
2014-09-24 16:29:05 +04:00
prefix , yes_no ( p - > nofail ) ,
2014-09-28 06:02:04 +04:00
prefix , p - > discard ? : " none " ) ;
2012-05-24 19:33:50 +04:00
2010-10-12 06:07:43 +04:00
if ( s - > control_pid > 0 )
fprintf ( f ,
2014-04-25 15:45:15 +04:00
" %sControl PID: " PID_FMT " \n " ,
prefix , s - > control_pid ) ;
2010-10-12 06:07:43 +04:00
exec_context_dump ( & s - > exec_context , f , prefix ) ;
2012-07-20 01:47:10 +04:00
kill_context_dump ( & s - > kill_context , f , prefix ) ;
2010-10-12 06:07:43 +04:00
}
static int swap_spawn ( Swap * s , ExecCommand * c , pid_t * _pid ) {
pid_t pid ;
int r ;
2014-08-23 17:28:37 +04:00
ExecParameters exec_params = {
. apply_permissions = true ,
. apply_chroot = true ,
. apply_tty_stdin = true ,
} ;
2010-10-12 06:07:43 +04:00
assert ( s ) ;
assert ( c ) ;
assert ( _pid ) ;
2013-06-27 06:14:27 +04:00
unit_realize_cgroup ( UNIT ( s ) ) ;
2013-11-27 23:23:18 +04:00
r = unit_setup_exec_runtime ( UNIT ( s ) ) ;
if ( r < 0 )
goto fail ;
2013-11-20 00:12:59 +04:00
r = swap_arm_timer ( s ) ;
2012-09-19 19:38:00 +04:00
if ( r < 0 )
2010-10-12 06:07:43 +04:00
goto fail ;
2014-08-23 17:28:37 +04:00
exec_params . environment = UNIT ( s ) - > manager - > environment ;
exec_params . confirm_spawn = UNIT ( s ) - > manager - > confirm_spawn ;
exec_params . cgroup_supported = UNIT ( s ) - > manager - > cgroup_supported ;
exec_params . cgroup_path = UNIT ( s ) - > cgroup_path ;
exec_params . runtime_prefix = manager_get_runtime_prefix ( UNIT ( s ) - > manager ) ;
exec_params . unit_id = UNIT ( s ) - > id ;
2012-09-19 19:38:00 +04:00
r = exec_spawn ( c ,
& s - > exec_context ,
2014-08-23 17:28:37 +04:00
& exec_params ,
2013-11-27 23:23:18 +04:00
s - > exec_runtime ,
2012-09-19 19:38:00 +04:00
& pid ) ;
if ( r < 0 )
2010-10-12 06:07:43 +04:00
goto fail ;
2012-09-19 19:38:00 +04:00
r = unit_watch_pid ( UNIT ( s ) , pid ) ;
if ( r < 0 )
2010-10-12 06:07:43 +04:00
/* FIXME: we need to do something here */
goto fail ;
* _pid = pid ;
return 0 ;
fail :
2013-11-20 00:12:59 +04:00
s - > timer_event_source = sd_event_source_unref ( s - > timer_event_source ) ;
2010-10-12 06:07:43 +04:00
return r ;
2010-05-09 20:44:11 +04:00
}
2012-02-03 07:47:32 +04:00
static void swap_enter_dead ( Swap * s , SwapResult f ) {
2010-05-09 20:44:11 +04:00
assert ( s ) ;
2012-02-03 07:47:32 +04:00
if ( f ! = SWAP_SUCCESS )
s - > result = f ;
2010-10-12 06:07:43 +04:00
2013-11-27 23:23:18 +04:00
exec_runtime_destroy ( s - > exec_runtime ) ;
s - > exec_runtime = exec_runtime_unref ( s - > exec_runtime ) ;
2014-03-03 20:14:07 +04:00
exec_context_destroy_runtime_directory ( & s - > exec_context , manager_get_runtime_prefix ( UNIT ( s ) - > manager ) ) ;
2012-02-03 07:47:32 +04:00
swap_set_state ( s , s - > result ! = SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD ) ;
2010-05-09 20:44:11 +04:00
}
2012-02-03 07:47:32 +04:00
static void swap_enter_active ( Swap * s , SwapResult f ) {
2010-10-12 06:07:43 +04:00
assert ( s ) ;
2012-02-03 07:47:32 +04:00
if ( f ! = SWAP_SUCCESS )
s - > result = f ;
2010-10-12 06:07:43 +04:00
swap_set_state ( s , SWAP_ACTIVE ) ;
}
2012-02-03 07:47:32 +04:00
static void swap_enter_signal ( Swap * s , SwapState state , SwapResult f ) {
2010-05-09 20:44:11 +04:00
int r ;
assert ( s ) ;
2010-10-12 06:07:43 +04:00
2012-02-03 07:47:32 +04:00
if ( f ! = SWAP_SUCCESS )
s - > result = f ;
2010-10-12 06:07:43 +04:00
2013-01-26 08:53:30 +04:00
r = unit_kill_context (
UNIT ( s ) ,
& s - > kill_context ,
state ! = SWAP_ACTIVATING_SIGTERM & & state ! = SWAP_DEACTIVATING_SIGTERM ,
- 1 ,
s - > control_pid ,
false ) ;
if ( r < 0 )
goto fail ;
2010-10-12 06:07:43 +04:00
2013-01-26 08:53:30 +04:00
if ( r > 0 ) {
2013-11-20 00:12:59 +04:00
r = swap_arm_timer ( s ) ;
2012-09-19 19:38:00 +04:00
if ( r < 0 )
2010-10-12 06:07:43 +04:00
goto fail ;
swap_set_state ( s , state ) ;
2014-01-29 17:58:04 +04:00
} else if ( state = = SWAP_ACTIVATING_SIGTERM )
swap_enter_signal ( s , SWAP_ACTIVATING_SIGKILL , SWAP_SUCCESS ) ;
else if ( state = = SWAP_DEACTIVATING_SIGTERM )
swap_enter_signal ( s , SWAP_DEACTIVATING_SIGKILL , SWAP_SUCCESS ) ;
else
2012-02-03 07:47:32 +04:00
swap_enter_dead ( s , SWAP_SUCCESS ) ;
2010-10-12 06:07:43 +04:00
return ;
fail :
2013-01-05 21:00:35 +04:00
log_warning_unit ( UNIT ( s ) - > id ,
" %s failed to kill processes: %s " , UNIT ( s ) - > id , strerror ( - r ) ) ;
2010-10-12 06:07:43 +04:00
2012-02-03 07:47:32 +04:00
swap_enter_dead ( s , SWAP_FAILURE_RESOURCES ) ;
2010-10-12 06:07:43 +04:00
}
static void swap_enter_activating ( Swap * s ) {
int r , priority ;
2014-09-24 16:29:05 +04:00
char * discard ;
2010-10-12 06:07:43 +04:00
assert ( s ) ;
s - > control_command_id = SWAP_EXEC_ACTIVATE ;
s - > control_command = s - > exec_command + SWAP_EXEC_ACTIVATE ;
2010-05-09 20:44:11 +04:00
2014-09-24 16:29:05 +04:00
if ( s - > from_fragment ) {
2010-05-14 04:29:45 +04:00
priority = s - > parameters_fragment . priority ;
2014-09-24 16:29:05 +04:00
discard = s - > parameters_fragment . discard ;
} else {
2010-10-12 06:07:43 +04:00
priority = - 1 ;
2014-09-24 16:29:05 +04:00
discard = NULL ;
}
r = exec_command_set ( s - > control_command , " /sbin/swapon " , NULL ) ;
if ( r < 0 )
goto fail ;
2010-05-14 04:29:45 +04:00
2010-10-12 06:07:43 +04:00
if ( priority > = 0 ) {
2013-11-25 18:26:30 +04:00
char p [ DECIMAL_STR_MAX ( int ) ] ;
2010-05-09 20:44:11 +04:00
2013-11-25 18:26:30 +04:00
sprintf ( p , " %i " , priority ) ;
2014-09-24 16:29:05 +04:00
r = exec_command_append ( s - > control_command , " -p " , p , NULL ) ;
if ( r < 0 )
goto fail ;
}
2010-05-09 20:44:11 +04:00
2014-09-24 16:29:05 +04:00
if ( discard & & ! streq ( discard , " none " ) ) {
const char * discard_arg = " --discard " ;
if ( ! streq ( discard , " all " ) )
discard_arg = strappenda ( " --discard= " , discard ) ;
r = exec_command_append ( s - > control_command , discard_arg , NULL ) ;
if ( r < 0 )
goto fail ;
}
2010-10-12 06:07:43 +04:00
2014-09-24 16:29:05 +04:00
r = exec_command_append ( s - > control_command , s - > what , NULL ) ;
2010-10-12 06:07:43 +04:00
if ( r < 0 )
goto fail ;
swap_unwatch_control_pid ( s ) ;
2012-09-19 19:38:00 +04:00
r = swap_spawn ( s , s - > control_command , & s - > control_pid ) ;
if ( r < 0 )
2010-10-12 06:07:43 +04:00
goto fail ;
swap_set_state ( s , SWAP_ACTIVATING ) ;
return ;
fail :
2013-01-05 21:00:35 +04:00
log_warning_unit ( UNIT ( s ) - > id ,
" %s failed to run 'swapon' task: %s " ,
UNIT ( s ) - > id , strerror ( - r ) ) ;
2012-02-03 07:47:32 +04:00
swap_enter_dead ( s , SWAP_FAILURE_RESOURCES ) ;
2010-10-12 06:07:43 +04:00
}
2012-02-03 07:47:32 +04:00
static void swap_enter_deactivating ( Swap * s ) {
2010-10-12 06:07:43 +04:00
int r ;
assert ( s ) ;
s - > control_command_id = SWAP_EXEC_DEACTIVATE ;
s - > control_command = s - > exec_command + SWAP_EXEC_DEACTIVATE ;
2012-09-19 19:38:00 +04:00
r = exec_command_set ( s - > control_command ,
2010-10-12 06:07:43 +04:00
" /sbin/swapoff " ,
s - > what ,
2012-09-19 19:38:00 +04:00
NULL ) ;
if ( r < 0 )
2010-10-12 06:07:43 +04:00
goto fail ;
swap_unwatch_control_pid ( s ) ;
2012-09-19 19:38:00 +04:00
r = swap_spawn ( s , s - > control_command , & s - > control_pid ) ;
if ( r < 0 )
2010-10-12 06:07:43 +04:00
goto fail ;
swap_set_state ( s , SWAP_DEACTIVATING ) ;
return ;
fail :
2013-01-05 21:00:35 +04:00
log_warning_unit ( UNIT ( s ) - > id ,
" %s failed to run 'swapoff' task: %s " ,
UNIT ( s ) - > id , strerror ( - r ) ) ;
2012-02-03 07:47:32 +04:00
swap_enter_active ( s , SWAP_FAILURE_RESOURCES ) ;
2010-10-12 06:07:43 +04:00
}
static int swap_start ( Unit * u ) {
Swap * s = SWAP ( u ) ;
assert ( s ) ;
/* We cannot fulfill this request right now, try again later
* please ! */
if ( s - > state = = SWAP_DEACTIVATING | |
s - > state = = SWAP_DEACTIVATING_SIGTERM | |
s - > state = = SWAP_DEACTIVATING_SIGKILL | |
s - > state = = SWAP_ACTIVATING_SIGTERM | |
s - > state = = SWAP_ACTIVATING_SIGKILL )
return - EAGAIN ;
if ( s - > state = = SWAP_ACTIVATING )
return 0 ;
assert ( s - > state = = SWAP_DEAD | | s - > state = = SWAP_FAILED ) ;
2012-08-25 01:00:13 +04:00
if ( detect_container ( NULL ) > 0 )
return - EPERM ;
2012-02-03 07:47:32 +04:00
s - > result = SWAP_SUCCESS ;
2010-10-12 06:07:43 +04:00
swap_enter_activating ( s ) ;
2010-05-09 20:44:11 +04:00
return 0 ;
}
static int swap_stop ( Unit * u ) {
Swap * s = SWAP ( u ) ;
assert ( s ) ;
2010-10-12 06:07:43 +04:00
if ( s - > state = = SWAP_DEACTIVATING | |
s - > state = = SWAP_DEACTIVATING_SIGTERM | |
s - > state = = SWAP_DEACTIVATING_SIGKILL | |
s - > state = = SWAP_ACTIVATING_SIGTERM | |
s - > state = = SWAP_ACTIVATING_SIGKILL )
return 0 ;
2010-05-09 20:44:11 +04:00
2010-10-12 06:07:43 +04:00
assert ( s - > state = = SWAP_ACTIVATING | |
2013-11-25 18:26:30 +04:00
s - > state = = SWAP_ACTIVATING_DONE | |
2010-10-12 06:07:43 +04:00
s - > state = = SWAP_ACTIVE ) ;
2010-05-09 20:44:11 +04:00
2012-08-25 01:00:13 +04:00
if ( detect_container ( NULL ) > 0 )
return - EPERM ;
2012-02-03 07:47:32 +04:00
swap_enter_deactivating ( s ) ;
2010-05-09 20:44:11 +04:00
return 0 ;
}
static int swap_serialize ( Unit * u , FILE * f , FDSet * fds ) {
Swap * s = SWAP ( u ) ;
assert ( s ) ;
assert ( f ) ;
assert ( fds ) ;
unit_serialize_item ( u , f , " state " , swap_state_to_string ( s - > state ) ) ;
2012-02-03 07:47:32 +04:00
unit_serialize_item ( u , f , " result " , swap_result_to_string ( s - > result ) ) ;
2010-10-12 06:07:43 +04:00
if ( s - > control_pid > 0 )
2014-04-25 15:45:15 +04:00
unit_serialize_item_format ( u , f , " control-pid " , PID_FMT , s - > control_pid ) ;
2010-10-12 06:07:43 +04:00
if ( s - > control_command_id > = 0 )
unit_serialize_item ( u , f , " control-command " , swap_exec_command_to_string ( s - > control_command_id ) ) ;
2010-05-09 20:44:11 +04:00
return 0 ;
}
static int swap_deserialize_item ( Unit * u , const char * key , const char * value , FDSet * fds ) {
Swap * s = SWAP ( u ) ;
assert ( s ) ;
assert ( fds ) ;
if ( streq ( key , " state " ) ) {
SwapState state ;
2012-09-19 19:38:00 +04:00
state = swap_state_from_string ( value ) ;
if ( state < 0 )
2013-01-05 21:00:35 +04:00
log_debug_unit ( u - > id , " Failed to parse state value %s " , value ) ;
2010-05-09 20:44:11 +04:00
else
s - > deserialized_state = state ;
2012-02-03 07:47:32 +04:00
} else if ( streq ( key , " result " ) ) {
SwapResult f ;
f = swap_result_from_string ( value ) ;
if ( f < 0 )
2013-01-05 21:00:35 +04:00
log_debug_unit ( u - > id , " Failed to parse result value %s " , value ) ;
2012-02-03 07:47:32 +04:00
else if ( f ! = SWAP_SUCCESS )
s - > result = f ;
2010-10-12 06:07:43 +04:00
} else if ( streq ( key , " control-pid " ) ) {
pid_t pid ;
if ( parse_pid ( value , & pid ) < 0 )
2013-01-05 21:00:35 +04:00
log_debug_unit ( u - > id , " Failed to parse control-pid value %s " , value ) ;
2010-10-12 06:07:43 +04:00
else
s - > control_pid = pid ;
} else if ( streq ( key , " control-command " ) ) {
SwapExecCommand id ;
2012-09-19 19:38:00 +04:00
id = swap_exec_command_from_string ( value ) ;
if ( id < 0 )
2013-01-05 21:00:35 +04:00
log_debug_unit ( u - > id , " Failed to parse exec-command value %s " , value ) ;
2010-10-12 06:07:43 +04:00
else {
s - > control_command_id = id ;
s - > control_command = s - > exec_command + id ;
}
2010-05-09 20:44:11 +04:00
} else
2013-01-05 21:00:35 +04:00
log_debug_unit ( u - > id , " Unknown serialization key '%s' " , key ) ;
2010-05-09 20:44:11 +04:00
return 0 ;
}
2013-05-03 06:51:50 +04:00
_pure_ static UnitActiveState swap_active_state ( Unit * u ) {
2010-05-09 20:44:11 +04:00
assert ( u ) ;
return state_translation_table [ SWAP ( u ) - > state ] ;
}
2013-05-03 06:51:50 +04:00
_pure_ static const char * swap_sub_state_to_string ( Unit * u ) {
2010-05-09 20:44:11 +04:00
assert ( u ) ;
return swap_state_to_string ( SWAP ( u ) - > state ) ;
}
2013-05-03 06:51:50 +04:00
_pure_ static bool swap_check_gc ( Unit * u ) {
2010-05-09 20:44:11 +04:00
Swap * s = SWAP ( u ) ;
assert ( s ) ;
2012-05-22 21:23:33 +04:00
return s - > from_proc_swaps ;
2010-05-09 20:44:11 +04:00
}
2010-10-12 06:07:43 +04:00
static void swap_sigchld_event ( Unit * u , pid_t pid , int code , int status ) {
Swap * s = SWAP ( u ) ;
2012-02-03 07:47:32 +04:00
SwapResult f ;
2010-10-12 06:07:43 +04:00
assert ( s ) ;
assert ( pid > = 0 ) ;
if ( pid ! = s - > control_pid )
return ;
s - > control_pid = 0 ;
2012-08-13 15:58:01 +04:00
if ( is_clean_exit ( code , status , NULL ) )
2012-02-03 07:47:32 +04:00
f = SWAP_SUCCESS ;
else if ( code = = CLD_EXITED )
f = SWAP_FAILURE_EXIT_CODE ;
else if ( code = = CLD_KILLED )
f = SWAP_FAILURE_SIGNAL ;
else if ( code = = CLD_DUMPED )
f = SWAP_FAILURE_CORE_DUMP ;
else
assert_not_reached ( " Unknown code " ) ;
if ( f ! = SWAP_SUCCESS )
s - > result = f ;
2010-10-12 06:07:43 +04:00
if ( s - > control_command ) {
2011-05-18 03:07:31 +04:00
exec_status_exit ( & s - > control_command - > exec_status , & s - > exec_context , pid , code , status ) ;
2012-02-03 07:47:32 +04:00
2010-10-12 06:07:43 +04:00
s - > control_command = NULL ;
s - > control_command_id = _SWAP_EXEC_COMMAND_INVALID ;
}
2013-01-05 21:00:35 +04:00
log_full_unit ( f = = SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE ,
u - > id ,
" %s swap process exited, code=%s status=%i " ,
u - > id , sigchld_code_to_string ( code ) , status ) ;
2010-10-12 06:07:43 +04:00
switch ( s - > state ) {
case SWAP_ACTIVATING :
2013-11-25 18:26:30 +04:00
case SWAP_ACTIVATING_DONE :
2010-10-12 06:07:43 +04:00
case SWAP_ACTIVATING_SIGTERM :
case SWAP_ACTIVATING_SIGKILL :
2012-02-03 07:47:32 +04:00
if ( f = = SWAP_SUCCESS )
swap_enter_active ( s , f ) ;
2010-10-12 06:07:43 +04:00
else
2012-02-03 07:47:32 +04:00
swap_enter_dead ( s , f ) ;
2010-10-12 06:07:43 +04:00
break ;
case SWAP_DEACTIVATING :
case SWAP_DEACTIVATING_SIGKILL :
case SWAP_DEACTIVATING_SIGTERM :
2014-01-03 23:33:20 +04:00
swap_enter_dead ( s , f ) ;
2010-10-12 06:07:43 +04:00
break ;
default :
assert_not_reached ( " Uh, control process died at wrong time. " ) ;
}
/* Notify clients about changed exit status */
unit_add_to_dbus_queue ( u ) ;
}
2013-11-20 00:12:59 +04:00
static int swap_dispatch_timer ( sd_event_source * source , usec_t usec , void * userdata ) {
Swap * s = SWAP ( userdata ) ;
2010-10-12 06:07:43 +04:00
assert ( s ) ;
2013-11-20 00:12:59 +04:00
assert ( s - > timer_event_source = = source ) ;
2010-10-12 06:07:43 +04:00
switch ( s - > state ) {
case SWAP_ACTIVATING :
2013-11-25 18:26:30 +04:00
case SWAP_ACTIVATING_DONE :
2013-11-20 00:12:59 +04:00
log_warning_unit ( UNIT ( s ) - > id , " %s activation timed out. Stopping. " , UNIT ( s ) - > id ) ;
2012-02-03 07:47:32 +04:00
swap_enter_signal ( s , SWAP_ACTIVATING_SIGTERM , SWAP_FAILURE_TIMEOUT ) ;
2010-10-12 06:07:43 +04:00
break ;
case SWAP_DEACTIVATING :
2013-11-20 00:12:59 +04:00
log_warning_unit ( UNIT ( s ) - > id , " %s deactivation timed out. Stopping. " , UNIT ( s ) - > id ) ;
2012-02-03 07:47:32 +04:00
swap_enter_signal ( s , SWAP_DEACTIVATING_SIGTERM , SWAP_FAILURE_TIMEOUT ) ;
2010-10-12 06:07:43 +04:00
break ;
case SWAP_ACTIVATING_SIGTERM :
2012-07-20 01:47:10 +04:00
if ( s - > kill_context . send_sigkill ) {
2013-11-20 00:12:59 +04:00
log_warning_unit ( UNIT ( s ) - > id , " %s activation timed out. Killing. " , UNIT ( s ) - > id ) ;
2012-02-03 07:47:32 +04:00
swap_enter_signal ( s , SWAP_ACTIVATING_SIGKILL , SWAP_FAILURE_TIMEOUT ) ;
2011-01-19 00:55:54 +03:00
} else {
2013-11-20 00:12:59 +04:00
log_warning_unit ( UNIT ( s ) - > id , " %s activation timed out. Skipping SIGKILL. Ignoring. " , UNIT ( s ) - > id ) ;
2012-02-03 07:47:32 +04:00
swap_enter_dead ( s , SWAP_FAILURE_TIMEOUT ) ;
2011-01-19 00:55:54 +03:00
}
2010-10-12 06:07:43 +04:00
break ;
case SWAP_DEACTIVATING_SIGTERM :
2012-07-20 01:47:10 +04:00
if ( s - > kill_context . send_sigkill ) {
2013-11-20 00:12:59 +04:00
log_warning_unit ( UNIT ( s ) - > id , " %s deactivation timed out. Killing. " , UNIT ( s ) - > id ) ;
2012-02-03 07:47:32 +04:00
swap_enter_signal ( s , SWAP_DEACTIVATING_SIGKILL , SWAP_FAILURE_TIMEOUT ) ;
2011-01-19 00:55:54 +03:00
} else {
2013-11-20 00:12:59 +04:00
log_warning_unit ( UNIT ( s ) - > id , " %s deactivation timed out. Skipping SIGKILL. Ignoring. " , UNIT ( s ) - > id ) ;
2012-02-03 07:47:32 +04:00
swap_enter_dead ( s , SWAP_FAILURE_TIMEOUT ) ;
2011-01-19 00:55:54 +03:00
}
2010-10-12 06:07:43 +04:00
break ;
case SWAP_ACTIVATING_SIGKILL :
case SWAP_DEACTIVATING_SIGKILL :
2013-11-20 00:12:59 +04:00
log_warning_unit ( UNIT ( s ) - > id , " %s swap process still around after SIGKILL. Ignoring. " , UNIT ( s ) - > id ) ;
2012-02-03 07:47:32 +04:00
swap_enter_dead ( s , SWAP_FAILURE_TIMEOUT ) ;
2010-10-12 06:07:43 +04:00
break ;
default :
assert_not_reached ( " Timeout at wrong time. " ) ;
}
2013-11-20 00:12:59 +04:00
return 0 ;
2010-10-12 06:07:43 +04:00
}
static int swap_load_proc_swaps ( Manager * m , bool set_flags ) {
unsigned i ;
int r = 0 ;
assert ( m ) ;
2010-05-09 20:44:11 +04:00
rewind ( m - > proc_swaps ) ;
2010-05-10 05:34:31 +04:00
2010-05-14 04:29:45 +04:00
( void ) fscanf ( m - > proc_swaps , " %*s %*s %*s %*s %*s \n " ) ;
2010-05-09 20:44:11 +04:00
2010-10-12 06:07:43 +04:00
for ( i = 1 ; ; i + + ) {
2013-09-18 00:12:16 +04:00
_cleanup_free_ char * dev = NULL , * d = NULL ;
2010-05-09 20:44:11 +04:00
int prio = 0 , k ;
2012-09-19 19:38:00 +04:00
k = fscanf ( m - > proc_swaps ,
" %ms " /* device/file */
" %*s " /* type of swap */
" %*s " /* swap size */
" %*s " /* used */
" %i \n " , /* priority */
& dev , & prio ) ;
if ( k ! = 2 ) {
2010-05-09 20:44:11 +04:00
if ( k = = EOF )
2010-05-14 04:29:45 +04:00
break ;
2010-05-09 20:44:11 +04:00
2012-09-19 19:38:00 +04:00
log_warning ( " Failed to parse /proc/swaps:%u " , i ) ;
2010-10-12 06:07:43 +04:00
continue ;
2010-05-09 20:44:11 +04:00
}
2010-05-14 04:29:45 +04:00
d = cunescape ( dev ) ;
if ( ! d )
return - ENOMEM ;
2010-10-12 06:07:43 +04:00
k = swap_process_new_swap ( m , d , prio , set_flags ) ;
2010-05-09 20:44:11 +04:00
if ( k < 0 )
2010-10-12 06:07:43 +04:00
r = k ;
2010-05-09 20:44:11 +04:00
}
2010-10-12 06:07:43 +04:00
return r ;
}
2013-11-20 00:12:59 +04:00
static int swap_dispatch_io ( sd_event_source * source , int fd , uint32_t revents , void * userdata ) {
Manager * m = userdata ;
2012-01-15 15:37:16 +04:00
Unit * u ;
2010-10-19 01:09:09 +04:00
int r ;
assert ( m ) ;
2013-11-20 00:12:59 +04:00
assert ( revents & EPOLLPRI ) ;
2010-10-19 01:09:09 +04:00
2012-09-19 19:38:00 +04:00
r = swap_load_proc_swaps ( m , true ) ;
if ( r < 0 ) {
2010-10-12 06:07:43 +04:00
log_error ( " Failed to reread /proc/swaps: %s " , strerror ( - r ) ) ;
/* Reset flags, just in case, for late calls */
2012-01-15 15:37:16 +04:00
LIST_FOREACH ( units_by_type , u , m - > units_by_type [ UNIT_SWAP ] ) {
Swap * swap = SWAP ( u ) ;
2010-10-12 06:07:43 +04:00
swap - > is_active = swap - > just_activated = false ;
}
return 0 ;
}
manager_dispatch_load_queue ( m ) ;
2012-01-15 15:37:16 +04:00
LIST_FOREACH ( units_by_type , u , m - > units_by_type [ UNIT_SWAP ] ) {
Swap * swap = SWAP ( u ) ;
2010-10-12 06:07:43 +04:00
if ( ! swap - > is_active ) {
/* This has just been deactivated */
swap_unset_proc_swaps ( swap ) ;
switch ( swap - > state ) {
case SWAP_ACTIVE :
2012-02-03 07:47:32 +04:00
swap_enter_dead ( swap , SWAP_SUCCESS ) ;
2010-10-12 06:07:43 +04:00
break ;
default :
2013-11-25 18:26:30 +04:00
/* Fire again */
2010-10-12 06:07:43 +04:00
swap_set_state ( swap , swap - > state ) ;
break ;
}
} else if ( swap - > just_activated ) {
/* New swap entry */
switch ( swap - > state ) {
case SWAP_DEAD :
case SWAP_FAILED :
2012-02-03 07:47:32 +04:00
swap_enter_active ( swap , SWAP_SUCCESS ) ;
2010-10-12 06:07:43 +04:00
break ;
2013-11-25 18:26:30 +04:00
case SWAP_ACTIVATING :
swap_set_state ( swap , SWAP_ACTIVATING_DONE ) ;
break ;
2010-10-12 06:07:43 +04:00
default :
/* Nothing really changed, but let's
* issue an notification call
* nonetheless , in case somebody is
* waiting for this . */
swap_set_state ( swap , swap - > state ) ;
break ;
}
}
/* Reset the flags for later calls */
swap - > is_active = swap - > just_activated = false ;
}
return 1 ;
}
static Unit * swap_following ( Unit * u ) {
Swap * s = SWAP ( u ) ;
Swap * other , * first = NULL ;
assert ( s ) ;
2013-11-26 00:08:39 +04:00
if ( streq_ptr ( s - > what , s - > devnode ) )
2010-10-12 06:07:43 +04:00
return NULL ;
/* Make everybody follow the unit that's named after the swap
* device in the kernel */
2013-11-26 00:08:39 +04:00
LIST_FOREACH_AFTER ( same_devnode , other , s )
if ( streq_ptr ( other - > what , other - > devnode ) )
2010-10-12 06:07:43 +04:00
return UNIT ( other ) ;
2013-11-26 00:08:39 +04:00
LIST_FOREACH_BEFORE ( same_devnode , other , s ) {
if ( streq_ptr ( other - > what , other - > devnode ) )
2010-10-12 06:07:43 +04:00
return UNIT ( other ) ;
first = other ;
}
return UNIT ( first ) ;
2010-05-09 20:44:11 +04:00
}
2010-11-15 01:47:53 +03:00
static int swap_following_set ( Unit * u , Set * * _set ) {
2013-11-25 18:26:30 +04:00
Swap * s = SWAP ( u ) , * other ;
2010-11-15 01:47:53 +03:00
Set * set ;
int r ;
assert ( s ) ;
assert ( _set ) ;
2013-11-26 00:08:39 +04:00
if ( LIST_JUST_US ( same_devnode , s ) ) {
2010-11-15 01:47:53 +03:00
* _set = NULL ;
return 0 ;
}
2014-08-13 03:00:18 +04:00
set = set_new ( NULL ) ;
2013-11-25 18:26:30 +04:00
if ( ! set )
2010-11-15 01:47:53 +03:00
return - ENOMEM ;
2013-11-26 00:08:39 +04:00
LIST_FOREACH_AFTER ( same_devnode , other , s ) {
2013-11-25 18:26:30 +04:00
r = set_put ( set , other ) ;
if ( r < 0 )
2010-11-15 01:47:53 +03:00
goto fail ;
2013-11-25 18:26:30 +04:00
}
2010-11-15 01:47:53 +03:00
2013-11-26 00:08:39 +04:00
LIST_FOREACH_BEFORE ( same_devnode , other , s ) {
2013-11-25 18:26:30 +04:00
r = set_put ( set , other ) ;
if ( r < 0 )
2010-11-15 01:47:53 +03:00
goto fail ;
2013-11-25 18:26:30 +04:00
}
2010-11-15 01:47:53 +03:00
* _set = set ;
return 1 ;
fail :
set_free ( set ) ;
return r ;
}
2010-05-09 20:44:11 +04:00
static void swap_shutdown ( Manager * m ) {
assert ( m ) ;
2013-11-20 00:12:59 +04:00
m - > swap_event_source = sd_event_source_unref ( m - > swap_event_source ) ;
2010-05-09 20:44:11 +04:00
if ( m - > proc_swaps ) {
fclose ( m - > proc_swaps ) ;
m - > proc_swaps = NULL ;
}
2010-10-12 06:07:43 +04:00
2013-11-26 00:08:39 +04:00
hashmap_free ( m - > swaps_by_devnode ) ;
m - > swaps_by_devnode = NULL ;
2010-05-09 20:44:11 +04:00
}
static int swap_enumerate ( Manager * m ) {
int r ;
2013-11-26 00:08:39 +04:00
2010-05-09 20:44:11 +04:00
assert ( m ) ;
2010-10-19 01:09:09 +04:00
if ( ! m - > proc_swaps ) {
2012-09-19 19:38:00 +04:00
m - > proc_swaps = fopen ( " /proc/swaps " , " re " ) ;
if ( ! m - > proc_swaps )
2013-11-20 00:12:59 +04:00
return errno = = ENOENT ? 0 : - errno ;
2010-10-19 01:09:09 +04:00
2014-02-20 02:54:58 +04:00
r = sd_event_add_io ( m - > event , & m - > swap_event_source , fileno ( m - > proc_swaps ) , EPOLLPRI , swap_dispatch_io , m ) ;
2013-11-20 00:12:59 +04:00
if ( r < 0 )
2013-11-25 18:35:10 +04:00
goto fail ;
/* Dispatch this before we dispatch SIGCHLD, so that
* we always get the events from / proc / swaps before
* the SIGCHLD of / sbin / swapon . */
r = sd_event_source_set_priority ( m - > swap_event_source , - 10 ) ;
if ( r < 0 )
2013-11-20 00:12:59 +04:00
goto fail ;
2010-10-19 01:09:09 +04:00
}
2012-09-19 19:38:00 +04:00
r = swap_load_proc_swaps ( m , false ) ;
if ( r < 0 )
2013-11-20 00:12:59 +04:00
goto fail ;
return 0 ;
2010-05-09 20:44:11 +04:00
2013-11-20 00:12:59 +04:00
fail :
swap_shutdown ( m ) ;
2010-05-09 20:44:11 +04:00
return r ;
}
2013-11-26 00:08:39 +04:00
int swap_process_new_device ( Manager * m , struct udev_device * dev ) {
struct udev_list_entry * item = NULL , * first = NULL ;
_cleanup_free_ char * e = NULL ;
const char * dn ;
Swap * s ;
int r = 0 ;
assert ( m ) ;
assert ( dev ) ;
dn = udev_device_get_devnode ( dev ) ;
if ( ! dn )
return 0 ;
e = unit_name_from_path ( dn , " .swap " ) ;
if ( ! e )
return - ENOMEM ;
s = hashmap_get ( m - > units , e ) ;
if ( s )
r = swap_set_devnode ( s , dn ) ;
first = udev_device_get_devlinks_list_entry ( dev ) ;
udev_list_entry_foreach ( item , first ) {
_cleanup_free_ char * n = NULL ;
n = unit_name_from_path ( udev_list_entry_get_name ( item ) , " .swap " ) ;
if ( ! n )
return - ENOMEM ;
s = hashmap_get ( m - > units , n ) ;
if ( s ) {
int q ;
q = swap_set_devnode ( s , dn ) ;
if ( q < 0 )
r = q ;
}
}
return r ;
}
int swap_process_removed_device ( Manager * m , struct udev_device * dev ) {
const char * dn ;
int r = 0 ;
Swap * s ;
dn = udev_device_get_devnode ( dev ) ;
if ( ! dn )
return 0 ;
while ( ( s = hashmap_get ( m - > swaps_by_devnode , dn ) ) ) {
int q ;
q = swap_set_devnode ( s , NULL ) ;
if ( q < 0 )
r = q ;
}
return r ;
}
2010-08-31 02:23:34 +04:00
static void swap_reset_failed ( Unit * u ) {
2010-07-18 06:58:01 +04:00
Swap * s = SWAP ( u ) ;
assert ( s ) ;
2010-08-31 02:23:34 +04:00
if ( s - > state = = SWAP_FAILED )
2010-07-18 06:58:01 +04:00
swap_set_state ( s , SWAP_DEAD ) ;
2010-10-12 06:07:43 +04:00
2012-02-03 07:47:32 +04:00
s - > result = SWAP_SUCCESS ;
2010-07-18 06:58:01 +04:00
}
2013-11-20 00:12:59 +04:00
static int swap_kill ( Unit * u , KillWho who , int signo , sd_bus_error * error ) {
2013-03-03 01:31:09 +04:00
return unit_kill_common ( u , who , signo , - 1 , SWAP ( u ) - > control_pid , error ) ;
2010-10-22 18:11:50 +04:00
}
2014-01-27 09:57:34 +04:00
static int swap_get_timeout ( Unit * u , uint64_t * timeout ) {
Swap * s = SWAP ( u ) ;
int r ;
if ( ! s - > timer_event_source )
return 0 ;
r = sd_event_source_get_time ( s - > timer_event_source , timeout ) ;
if ( r < 0 )
return r ;
return 1 ;
}
2010-07-18 06:58:01 +04:00
static const char * const swap_state_table [ _SWAP_STATE_MAX ] = {
[ SWAP_DEAD ] = " dead " ,
2010-10-12 06:07:43 +04:00
[ SWAP_ACTIVATING ] = " activating " ,
2013-11-25 18:26:30 +04:00
[ SWAP_ACTIVATING_DONE ] = " activating-done " ,
2010-07-18 06:58:01 +04:00
[ SWAP_ACTIVE ] = " active " ,
2010-10-12 06:07:43 +04:00
[ SWAP_DEACTIVATING ] = " deactivating " ,
[ SWAP_ACTIVATING_SIGTERM ] = " activating-sigterm " ,
[ SWAP_ACTIVATING_SIGKILL ] = " activating-sigkill " ,
[ SWAP_DEACTIVATING_SIGTERM ] = " deactivating-sigterm " ,
[ SWAP_DEACTIVATING_SIGKILL ] = " deactivating-sigkill " ,
2010-08-31 02:23:34 +04:00
[ SWAP_FAILED ] = " failed "
2010-07-18 06:58:01 +04:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( swap_state , SwapState ) ;
2010-10-12 06:07:43 +04:00
static const char * const swap_exec_command_table [ _SWAP_EXEC_COMMAND_MAX ] = {
[ SWAP_EXEC_ACTIVATE ] = " ExecActivate " ,
[ SWAP_EXEC_DEACTIVATE ] = " ExecDeactivate " ,
} ;
DEFINE_STRING_TABLE_LOOKUP ( swap_exec_command , SwapExecCommand ) ;
2012-02-03 07:47:32 +04:00
static const char * const swap_result_table [ _SWAP_RESULT_MAX ] = {
[ SWAP_SUCCESS ] = " success " ,
[ SWAP_FAILURE_RESOURCES ] = " resources " ,
[ SWAP_FAILURE_TIMEOUT ] = " timeout " ,
[ SWAP_FAILURE_EXIT_CODE ] = " exit-code " ,
[ SWAP_FAILURE_SIGNAL ] = " signal " ,
[ SWAP_FAILURE_CORE_DUMP ] = " core-dump "
} ;
DEFINE_STRING_TABLE_LOOKUP ( swap_result , SwapResult ) ;
2010-05-09 20:44:11 +04:00
const UnitVTable swap_vtable = {
2012-01-15 13:53:49 +04:00
. object_size = sizeof ( Swap ) ,
2013-11-20 00:12:59 +04:00
. exec_context_offset = offsetof ( Swap , exec_context ) ,
. cgroup_context_offset = offsetof ( Swap , cgroup_context ) ,
. kill_context_offset = offsetof ( Swap , kill_context ) ,
2013-11-27 23:23:18 +04:00
. exec_runtime_offset = offsetof ( Swap , exec_runtime ) ,
2012-09-18 13:40:01 +04:00
2011-08-01 02:43:05 +04:00
. sections =
" Unit \0 "
" Swap \0 "
" Install \0 " ,
2013-06-27 06:14:27 +04:00
. private_section = " Swap " ,
2013-01-19 04:01:41 +04:00
2010-10-12 06:07:43 +04:00
. no_alias = true ,
2010-05-09 20:44:11 +04:00
. no_instances = true ,
2010-05-14 04:29:45 +04:00
. init = swap_init ,
2010-05-09 20:44:11 +04:00
. load = swap_load ,
2010-05-10 01:41:03 +04:00
. done = swap_done ,
2010-05-09 20:44:11 +04:00
. coldplug = swap_coldplug ,
. dump = swap_dump ,
. start = swap_start ,
. stop = swap_stop ,
2010-10-22 18:11:50 +04:00
. kill = swap_kill ,
2014-01-27 09:57:34 +04:00
. get_timeout = swap_get_timeout ,
2010-05-09 20:44:11 +04:00
. serialize = swap_serialize ,
. deserialize_item = swap_deserialize_item ,
. active_state = swap_active_state ,
. sub_state_to_string = swap_sub_state_to_string ,
. check_gc = swap_check_gc ,
2010-10-12 06:07:43 +04:00
. sigchld_event = swap_sigchld_event ,
. reset_failed = swap_reset_failed ,
2010-08-20 04:26:05 +04:00
. bus_interface = " org.freedesktop.systemd1.Swap " ,
2013-11-20 00:12:59 +04:00
. bus_vtable = bus_swap_vtable ,
2013-06-28 01:21:21 +04:00
. bus_set_property = bus_swap_set_property ,
. bus_commit_properties = bus_swap_commit_properties ,
2010-05-09 20:44:11 +04:00
2010-10-12 06:07:43 +04:00
. following = swap_following ,
2010-11-15 01:47:53 +03:00
. following_set = swap_following_set ,
2010-07-18 06:58:01 +04:00
2010-05-10 01:41:03 +04:00
. enumerate = swap_enumerate ,
2012-05-13 20:18:54 +04:00
. shutdown = swap_shutdown ,
. status_message_formats = {
. starting_stopping = {
[ 0 ] = " Activating swap %s... " ,
[ 1 ] = " Deactivating swap %s... " ,
} ,
. finished_start_job = {
[ JOB_DONE ] = " Activated swap %s. " ,
[ JOB_FAILED ] = " Failed to activate swap %s. " ,
[ JOB_DEPENDENCY ] = " Dependency failed for %s. " ,
[ JOB_TIMEOUT ] = " Timed out activating swap %s. " ,
} ,
. finished_stop_job = {
[ JOB_DONE ] = " Deactivated swap %s. " ,
[ JOB_FAILED ] = " Failed deactivating swap %s. " ,
[ JOB_TIMEOUT ] = " Timed out deactivating swap %s. " ,
} ,
} ,
2010-05-09 20:44:11 +04:00
} ;