xref: /dragonfly/contrib/lvm2/dist/daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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, &params);
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