2 * kernel/power/tuxonice_storage.c
4 * Copyright (C) 2005-2010 Nigel Cunningham (nigel at tuxonice net)
6 * This file is released under the GPLv2.
8 * Routines for talking to a userspace program that manages storage.
11 * - starts the userspace program;
12 * - sends messages telling it when to open and close the connection;
13 * - tells it when to quit;
15 * The user space side:
16 * - passes messages regarding status;
20 #include <linux/module.h>
21 #include <linux/suspend.h>
22 #include <linux/freezer.h>
24 #include "tuxonice_sysfs.h"
25 #include "tuxonice_modules.h"
26 #include "tuxonice_netlink.h"
27 #include "tuxonice_storage.h"
28 #include "tuxonice_ui.h"
30 static struct user_helper_data usm_helper_data
;
31 static struct toi_module_ops usm_ops
;
32 static int message_received
, usm_prepare_count
;
33 static int storage_manager_last_action
, storage_manager_action
;
35 static int usm_user_rcv_msg(struct sk_buff
*skb
, struct nlmsghdr
*nlh
)
40 type
= nlh
->nlmsg_type
;
42 /* A control message: ignore them */
43 if (type
< NETLINK_MSG_BASE
)
46 /* Unknown message: reply with EINVAL */
47 if (type
>= USM_MSG_MAX
)
50 /* All operations require privileges, even GET */
51 if (!capable(CAP_NET_ADMIN
))
54 /* Only allow one task to receive NOFREEZE privileges */
55 if (type
== NETLINK_MSG_NOFREEZE_ME
&& usm_helper_data
.pid
!= -1)
58 data
= (int *)NLMSG_DATA(nlh
);
63 message_received
= type
;
64 complete(&usm_helper_data
.wait_for_process
);
67 printk(KERN_INFO
"Storage manager doesn't recognise " "message %d.\n", type
);
74 static int activations
;
76 int toi_activate_storage(int force
)
80 if (usm_helper_data
.pid
== -1 || !usm_ops
.enabled
)
86 if (activations
> 1 && !force
)
89 while ((!message_received
|| message_received
== USM_MSG_FAILED
) && tries
< 2) {
90 toi_prepare_status(DONT_CLEAR_BAR
, "Activate storage attempt " "%d.\n", tries
);
92 init_completion(&usm_helper_data
.wait_for_process
);
94 toi_send_netlink_message(&usm_helper_data
, USM_MSG_CONNECT
, NULL
, 0);
96 /* Wait 2 seconds for the userspace process to make contact */
97 wait_for_completion_timeout(&usm_helper_data
.wait_for_process
, 2 * HZ
);
105 int toi_deactivate_storage(int force
)
107 if (usm_helper_data
.pid
== -1 || !usm_ops
.enabled
)
110 message_received
= 0;
113 if (activations
&& !force
)
116 init_completion(&usm_helper_data
.wait_for_process
);
118 toi_send_netlink_message(&usm_helper_data
, USM_MSG_DISCONNECT
, NULL
, 0);
120 wait_for_completion_timeout(&usm_helper_data
.wait_for_process
, 2 * HZ
);
122 if (!message_received
|| message_received
== USM_MSG_FAILED
) {
123 printk(KERN_INFO
"Returning failure disconnecting storage.\n");
131 static void storage_manager_simulate(void)
133 printk(KERN_INFO
"--- Storage manager simulate ---\n");
136 printk(KERN_INFO
"--- Activate storage 1 ---\n");
137 toi_activate_storage(1);
139 printk(KERN_INFO
"--- Deactivate storage 1 ---\n");
140 toi_deactivate_storage(1);
142 printk(KERN_INFO
"--- Cleanup usm ---\n");
145 printk(KERN_INFO
"--- Storage manager simulate ends ---\n");
148 static int usm_storage_needed(void)
150 return sizeof(int) + strlen(usm_helper_data
.program
) + 1;
153 static int usm_save_config_info(char *buf
)
155 int len
= strlen(usm_helper_data
.program
);
156 memcpy(buf
, usm_helper_data
.program
, len
+ 1);
157 return sizeof(int) + len
+ 1;
160 static void usm_load_config_info(char *buf
, int size
)
162 /* Don't load the saved path if one has already been set */
163 if (usm_helper_data
.program
[0])
166 memcpy(usm_helper_data
.program
, buf
+ sizeof(int), *((int *)buf
));
169 static int usm_memory_needed(void)
171 /* ball park figure of 32 pages */
172 return 32 * PAGE_SIZE
;
177 int toi_prepare_usm(void)
181 if (usm_prepare_count
> 1 || !usm_ops
.enabled
)
184 usm_helper_data
.pid
= -1;
186 if (!*usm_helper_data
.program
)
189 toi_netlink_setup(&usm_helper_data
);
191 if (usm_helper_data
.pid
== -1)
192 printk(KERN_INFO
"TuxOnIce Storage Manager wanted, but couldn't" " start it.\n");
194 toi_activate_storage(0);
196 return usm_helper_data
.pid
!= -1;
199 void toi_cleanup_usm(void)
203 if (usm_helper_data
.pid
> -1 && !usm_prepare_count
) {
204 toi_deactivate_storage(0);
205 toi_netlink_close(&usm_helper_data
);
209 static void storage_manager_activate(void)
211 if (storage_manager_action
== storage_manager_last_action
)
214 if (storage_manager_action
)
219 storage_manager_last_action
= storage_manager_action
;
223 * User interface specific /sys/power/tuxonice entries.
226 static struct toi_sysfs_data sysfs_params
[] = {
227 SYSFS_NONE("simulate_atomic_copy", storage_manager_simulate
),
228 SYSFS_INT("enabled", SYSFS_RW
, &usm_ops
.enabled
, 0, 1, 0, NULL
),
229 SYSFS_STRING("program", SYSFS_RW
, usm_helper_data
.program
, 254, 0,
231 SYSFS_INT("activate_storage", SYSFS_RW
, &storage_manager_action
, 0, 1,
232 0, storage_manager_activate
)
235 static struct toi_module_ops usm_ops
= {
238 .directory
= "storage_manager",
239 .module
= THIS_MODULE
,
240 .storage_needed
= usm_storage_needed
,
241 .save_config_info
= usm_save_config_info
,
242 .load_config_info
= usm_load_config_info
,
243 .memory_needed
= usm_memory_needed
,
245 .sysfs_data
= sysfs_params
,
246 .num_sysfs_entries
= sizeof(sysfs_params
) / sizeof(struct toi_sysfs_data
),
249 /* toi_usm_sysfs_init
250 * Description: Boot time initialisation for user interface.
252 int toi_usm_init(void)
254 usm_helper_data
.nl
= NULL
;
255 usm_helper_data
.program
[0] = '\0';
256 usm_helper_data
.pid
= -1;
257 usm_helper_data
.skb_size
= 0;
258 usm_helper_data
.pool_limit
= 6;
259 usm_helper_data
.netlink_id
= NETLINK_TOI_USM
;
260 usm_helper_data
.name
= "userspace storage manager";
261 usm_helper_data
.rcv_msg
= usm_user_rcv_msg
;
262 usm_helper_data
.interface_version
= 2;
263 usm_helper_data
.must_init
= 0;
264 init_completion(&usm_helper_data
.wait_for_process
);
266 return toi_register_module(&usm_ops
);
269 void toi_usm_exit(void)
271 toi_netlink_close_complete(&usm_helper_data
);
272 toi_unregister_module(&usm_ops
);