Home | History | Annotate | Line # | Download | only in snapshot
      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, &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 
    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