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 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. */ 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 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 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 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