1 /* $NetBSD: dmeventd_snapshot.c,v 1.1.1.2 2009/12/02 00:27:12 haad Exp $ */
2
3 /*
4 * Copyright (C) 2007-2008 Red Hat, Inc. All rights reserved.
5 *
6 * This file is part of LVM2.
7 *
8 * This copyrighted material is made available to anyone wishing to use,
9 * modify, copy, or redistribute it subject to the terms and conditions
10 * of the GNU Lesser General Public License v.2.1.
11 *
12 * You should have received a copy of the GNU Lesser General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "libdevmapper.h"
18 #include "libdevmapper-event.h"
19 #include "lvm2cmd.h"
20 #include "lvm-string.h"
21
22 #include <errno.h>
23 #include <signal.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <pthread.h>
28 #include <unistd.h>
29
30 #include <syslog.h> /* FIXME Replace syslog with multilog */
31 /* FIXME Missing openlog? */
32
33 /* First warning when snapshot is 80% full. */
34 #define WARNING_THRESH 80
35 /* Further warnings at 85%, 90% and 95% fullness. */
36 #define WARNING_STEP 5
37
38 static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER;
39
40 /*
41 * Number of active registrations.
42 */
43 static int _register_count = 0;
44
45 static struct dm_pool *_mem_pool = NULL;
46 static void *_lvm_handle = NULL;
47
48 struct snap_status {
49 int invalid;
50 int used;
51 int max;
52 };
53
54 /*
55 * Currently only one event can be processed at a time.
56 */
57 static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
58
_temporary_log_fn(int level,const char * file __attribute ((unused)),int line __attribute ((unused)),int dm_errno __attribute ((unused)),const char * format)59 static void _temporary_log_fn(int level,
60 const char *file __attribute((unused)),
61 int line __attribute((unused)),
62 int dm_errno __attribute((unused)),
63 const char *format)
64 {
65 if (!strncmp(format, "WARNING: ", 9) && (level < 5))
66 syslog(LOG_CRIT, "%s", format);
67 else
68 syslog(LOG_DEBUG, "%s", format);
69 }
70
71 /* FIXME possibly reconcile this with target_percent when we gain
72 access to regular LVM library here. */
_parse_snapshot_params(char * params,struct snap_status * stat)73 static void _parse_snapshot_params(char *params, struct snap_status *stat)
74 {
75 char *p;
76 /*
77 * xx/xx -- fractions used/max
78 * Invalid -- snapshot invalidated
79 * Unknown -- status unknown
80 */
81 stat->used = stat->max = 0;
82
83 if (!strncmp(params, "Invalid", 7)) {
84 stat->invalid = 1;
85 return;
86 }
87
88 /*
89 * When we return without setting non-zero max, the parent is
90 * responsible for reporting errors.
91 */
92 if (!strncmp(params, "Unknown", 7))
93 return;
94
95 if (!(p = strstr(params, "/")))
96 return;
97
98 *p = '\0';
99 p++;
100
101 stat->used = atoi(params);
102 stat->max = atoi(p);
103 }
104
process_event(struct dm_task * dmt,enum dm_event_mask event __attribute ((unused)),void ** private)105 void process_event(struct dm_task *dmt,
106 enum dm_event_mask event __attribute((unused)),
107 void **private)
108 {
109 void *next = NULL;
110 uint64_t start, length;
111 char *target_type = NULL;
112 char *params;
113 struct snap_status stat = { 0 };
114 const char *device = dm_task_get_name(dmt);
115 int percent, *percent_warning = (int*)private;
116
117 /* No longer monitoring, waiting for remove */
118 if (!*percent_warning)
119 return;
120
121 if (pthread_mutex_trylock(&_event_mutex)) {
122 syslog(LOG_NOTICE, "Another thread is handling an event. Waiting...");
123 pthread_mutex_lock(&_event_mutex);
124 }
125
126 dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
127 if (!target_type)
128 goto out;
129
130 _parse_snapshot_params(params, &stat);
131 /*
132 * If the snapshot has been invalidated or we failed to parse
133 * the status string. Report the full status string to syslog.
134 */
135 if (stat.invalid || !stat.max) {
136 syslog(LOG_ERR, "Snapshot %s changed state to: %s\n", device, params);
137 *percent_warning = 0;
138 goto out;
139 }
140
141 percent = 100 * stat.used / stat.max;
142 if (percent >= *percent_warning) {
143 syslog(LOG_WARNING, "Snapshot %s is now %i%% full.\n", device, percent);
144 /* Print warning on the next multiple of WARNING_STEP. */
145 *percent_warning = (percent / WARNING_STEP) * WARNING_STEP + WARNING_STEP;
146 }
147 out:
148 pthread_mutex_unlock(&_event_mutex);
149 }
150
register_device(const char * device,const char * uuid __attribute ((unused)),int major __attribute ((unused)),int minor __attribute ((unused)),void ** private)151 int register_device(const char *device,
152 const char *uuid __attribute((unused)),
153 int major __attribute((unused)),
154 int minor __attribute((unused)),
155 void **private)
156 {
157 int r = 0;
158 int *percent_warning = (int*)private;
159
160 pthread_mutex_lock(&_register_mutex);
161
162 /*
163 * Need some space for allocations. 1024 should be more
164 * than enough for what we need (device mapper name splitting)
165 */
166 if (!_mem_pool && !(_mem_pool = dm_pool_create("snapshot_dso", 1024)))
167 goto out;
168
169 *percent_warning = WARNING_THRESH; /* Print warning if snapshot is full */
170
171 if (!_lvm_handle) {
172 lvm2_log_fn(_temporary_log_fn);
173 if (!(_lvm_handle = lvm2_init())) {
174 dm_pool_destroy(_mem_pool);
175 _mem_pool = NULL;
176 goto out;
177 }
178 lvm2_log_level(_lvm_handle, LVM2_LOG_SUPPRESS);
179 /* FIXME Temporary: move to dmeventd core */
180 lvm2_run(_lvm_handle, "_memlock_inc");
181 }
182
183 syslog(LOG_INFO, "Monitoring snapshot %s\n", device);
184
185 _register_count++;
186 r = 1;
187
188 out:
189 pthread_mutex_unlock(&_register_mutex);
190
191 return r;
192 }
193
unregister_device(const char * device,const char * uuid __attribute ((unused)),int major __attribute ((unused)),int minor __attribute ((unused)),void ** unused __attribute ((unused)))194 int unregister_device(const char *device,
195 const char *uuid __attribute((unused)),
196 int major __attribute((unused)),
197 int minor __attribute((unused)),
198 void **unused __attribute((unused)))
199 {
200 pthread_mutex_lock(&_register_mutex);
201
202 syslog(LOG_INFO, "No longer monitoring snapshot %s\n",
203 device);
204
205 if (!--_register_count) {
206 dm_pool_destroy(_mem_pool);
207 _mem_pool = NULL;
208 lvm2_run(_lvm_handle, "_memlock_dec");
209 lvm2_exit(_lvm_handle);
210 _lvm_handle = NULL;
211 }
212
213 pthread_mutex_unlock(&_register_mutex);
214
215 return 1;
216 }
217