⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dmeventd.c

📁 Linux Device Mapper Source Code
💻 C
📖 第 1 页 / 共 3 页
字号:
#define DM_WAIT_FATAL 2/* Wait on a device until an event occurs. */static int _event_wait(struct thread_status *thread, struct dm_task **task){	sigset_t set;	int ret = DM_WAIT_RETRY;	struct dm_task *dmt;	struct dm_info info;	*task = 0;	if (!(dmt = dm_task_create(DM_DEVICE_WAITEVENT)))		return DM_WAIT_RETRY;	thread->current_task = dmt;	if (!dm_task_set_uuid(dmt, thread->device.uuid) ||	    !dm_task_set_event_nr(dmt, thread->event_nr))		goto out;	/*	 * This is so that you can break out of waiting on an event,	 * either for a timeout event, or to cancel the thread.	 */	set = _unblock_sigalrm();	dm_log_init(_no_intr_log);	errno = 0;	if (dm_task_run(dmt)) {		thread->current_events |= DM_EVENT_DEVICE_ERROR;		ret = DM_WAIT_INTR;		if ((ret = dm_task_get_info(dmt, &info)))			thread->event_nr = info.event_nr;	} else if (thread->events & DM_EVENT_TIMEOUT && errno == EINTR) {		thread->current_events |= DM_EVENT_TIMEOUT;		ret = DM_WAIT_INTR;	} else if (thread->status == DM_THREAD_SHUTDOWN && errno == EINTR) {		ret = DM_WAIT_FATAL;	} else {		syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s",		       errno, strerror(errno));		if (errno == ENXIO) {			syslog(LOG_ERR, "%s disappeared, detaching",			       thread->device.name);			ret = DM_WAIT_FATAL;		}	}	pthread_sigmask(SIG_SETMASK, &set, NULL);	dm_log_init(NULL);      out:	if (ret == DM_WAIT_FATAL || ret == DM_WAIT_RETRY) {		dm_task_destroy(dmt);		thread->current_task = NULL;	} else		*task = dmt;	return ret;}/* Register a device with the DSO. */static int _do_register_device(struct thread_status *thread){	return thread->dso_data->register_device(thread->device.name,						 thread->device.uuid,						 thread->device.major,						 thread->device.minor,						 &(thread->dso_private));}/* Unregister a device with the DSO. */static int _do_unregister_device(struct thread_status *thread){	return thread->dso_data->unregister_device(thread->device.name,						   thread->device.uuid,						   thread->device.major,						   thread->device.minor,						   &(thread->dso_private));}/* Process an event in the DSO. */static void _do_process_event(struct thread_status *thread, struct dm_task *task){	thread->dso_data->process_event(task, thread->current_events, &(thread->dso_private));}/* Thread cleanup handler to unregister device. */static void _monitor_unregister(void *arg){	struct thread_status *thread = arg, *thread_iter;	if (!_do_unregister_device(thread))		syslog(LOG_ERR, "%s: %s unregister failed\n", __func__,		       thread->device.name);	if (thread->current_task)		dm_task_destroy(thread->current_task);	thread->current_task = NULL;	_lock_mutex();	if (thread->events & DM_EVENT_TIMEOUT) {		/* _unregister_for_timeout locks another mutex, we		   don't want to deadlock so we release our mutex for		   a bit */		_unlock_mutex();		_unregister_for_timeout(thread);		_lock_mutex();	}	/* we may have been relinked to unused registry since we were	   called, so check that */	list_iterate_items(thread_iter, &_thread_registry_unused)		if (thread_iter == thread) {			thread->status = DM_THREAD_DONE;			_unlock_mutex();			return;		}	thread->status = DM_THREAD_DONE;	UNLINK_THREAD(thread);	LINK(thread, &_thread_registry_unused);	_unlock_mutex();}static struct dm_task *_get_device_status(struct thread_status *ts){	struct dm_task *dmt = dm_task_create(DM_DEVICE_STATUS);	if (!dmt)		return NULL;	dm_task_set_uuid(dmt, ts->device.uuid);	if (!dm_task_run(dmt)) {		dm_task_destroy(dmt);		return NULL;	}	return dmt;}/* Device monitoring thread. */static void *_monitor_thread(void *arg){	struct thread_status *thread = arg;	int wait_error = 0;	struct dm_task *task;	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);	pthread_cleanup_push(_monitor_unregister, thread);	/* Wait for do_process_request() to finish its task. */	_lock_mutex();	thread->status = DM_THREAD_RUNNING;	_unlock_mutex();	/* Loop forever awaiting/analyzing device events. */	while (1) {		thread->current_events = 0;		wait_error = _event_wait(thread, &task);		if (wait_error == DM_WAIT_RETRY)			continue;		if (wait_error == DM_WAIT_FATAL)			break;		/* Timeout occurred, task is not filled properly.		 * We get device status here for processing it in DSO.		 */		if (wait_error == DM_WAIT_INTR &&		    thread->current_events & DM_EVENT_TIMEOUT) {			dm_task_destroy(task);			task = _get_device_status(thread);			/* FIXME: syslog fail here ? */			if (!(thread->current_task = task))				continue;		}		/*		 * We know that wait succeeded and stored a		 * pointer to dm_task with device status into task.		 */		/*		 * Check against filter.		 *		 * If there's current events delivered from _event_wait() AND		 * the device got registered for those events AND		 * those events haven't been processed yet, call		 * the DSO's process_event() handler.		 */		_lock_mutex();		if (thread->status == DM_THREAD_SHUTDOWN) {			_unlock_mutex();			break;		}		_unlock_mutex();		if (thread->events & thread->current_events) {			_lock_mutex();			thread->processing = 1;			_unlock_mutex();			_do_process_event(thread, task);			dm_task_destroy(task);			thread->current_task = NULL;			_lock_mutex();			thread->processing = 0;			_unlock_mutex();		} else {			dm_task_destroy(task);			thread->current_task = NULL;		}	}	pthread_cleanup_pop(1);	return NULL;}/* Create a device monitoring thread. */static int _create_thread(struct thread_status *thread){	return _pthread_create_smallstack(&thread->thread, _monitor_thread, thread);}static int _terminate_thread(struct thread_status *thread){	return pthread_kill(thread->thread, SIGALRM);}/* DSO reference counting. Call with _global_mutex locked! */static void _lib_get(struct dso_data *data){	data->ref_count++;}static void _lib_put(struct dso_data *data){	if (!--data->ref_count) {		dlclose(data->dso_handle);		UNLINK_DSO(data);		_free_dso_data(data);	}}/* Find DSO data. */static struct dso_data *_lookup_dso(struct message_data *data){	struct dso_data *dso_data, *ret = NULL;	list_iterate_items(dso_data, &_dso_registry)	    if (!strcmp(data->dso_name, dso_data->dso_name)) {		_lib_get(dso_data);		ret = dso_data;		break;	}	return ret;}/* Lookup DSO symbols we need. */static int _lookup_symbol(void *dl, void **symbol, const char *name){	if ((*symbol = dlsym(dl, name)))		return 1;	return 0;}static int lookup_symbols(void *dl, struct dso_data *data){	return _lookup_symbol(dl, (void *) &data->process_event,			     "process_event") &&	    _lookup_symbol(dl, (void *) &data->register_device,			  "register_device") &&	    _lookup_symbol(dl, (void *) &data->unregister_device,			  "unregister_device");}/* Load an application specific DSO. */static struct dso_data *_load_dso(struct message_data *data){	void *dl;	struct dso_data *ret = NULL;	if (!(dl = dlopen(data->dso_name, RTLD_NOW))) {		const char *dlerr = dlerror();		syslog(LOG_ERR, "dmeventd %s dlopen failed: %s", data->dso_name,		       dlerr);		data->msg->size =		    dm_asprintf(&(data->msg->data), "%s %s dlopen failed: %s",				data->id, data->dso_name, dlerr);		return NULL;	}	if (!(ret = _alloc_dso_data(data))) {		dlclose(dl);		return NULL;	}	if (!(lookup_symbols(dl, ret))) {		_free_dso_data(ret);		dlclose(dl);		return NULL;	}	/*	 * Keep handle to close the library once	 * we've got no references to it any more.	 */	ret->dso_handle = dl;	_lib_get(ret);	_lock_mutex();	LINK_DSO(ret);	_unlock_mutex();	return ret;}/* Return success on daemon active check. */static int _active(struct message_data *message_data){	return 0;}/* * Register for an event. * * Only one caller at a time here, because we use * a FIFO and lock it against multiple accesses. */static int _register_for_event(struct message_data *message_data){	int ret = 0;	struct thread_status *thread, *thread_new = NULL;	struct dso_data *dso_data;	if (!(dso_data = _lookup_dso(message_data)) &&	    !(dso_data = _load_dso(message_data))) {		stack;#ifdef ELIBACC		ret = -ELIBACC;#else		ret = -ENODEV;#endif		goto out;	}	/* Preallocate thread status struct to avoid deadlock. */	if (!(thread_new = _alloc_thread_status(message_data, dso_data))) {		stack;		ret = -ENOMEM;		goto out;	}	if (!_fill_device_data(thread_new)) {		stack;		ret = -ENODEV;		goto out;	}	_lock_mutex();	/* If creation of timeout thread fails (as it may), we fail	   here completely. The client is responsible for either	   retrying later or trying to register without timeout	   events. However, if timeout thread cannot be started, it	   usually means we are so starved on resources that we are	   almost as good as dead already... */	if (thread_new->events & DM_EVENT_TIMEOUT) {		ret = -_register_for_timeout(thread_new);		if (ret) {		    _unlock_mutex();		    goto out;		}	}	if (!(thread = _lookup_thread_status(message_data))) {		_unlock_mutex();		if (!(ret = _do_register_device(thread_new)))			goto out;		thread = thread_new;		thread_new = NULL;		/* Try to create the monitoring thread for this device. */		_lock_mutex();		if ((ret = -_create_thread(thread))) {			_unlock_mutex();			_do_unregister_device(thread);			_free_thread_status(thread);			goto out;		} else			LINK_THREAD(thread);	}	/* Or event # into events bitfield. */	thread->events |= message_data->events.field;	_unlock_mutex();      out:	/*	 * Deallocate thread status after releasing	 * the lock in case we haven't used it.	 */	if (thread_new)		_free_thread_status(thread_new);	return ret;}/* * Unregister for an event. * * Only one caller at a time here as with register_for_event(). */static int _unregister_for_event(struct message_data *message_data){	int ret = 0;	struct thread_status *thread;	/*	 * Clear event in bitfield and deactivate	 * monitoring thread in case bitfield is 0.	 */	_lock_mutex();	if (!(thread = _lookup_thread_status(message_data))) {		_unlock_mutex();		ret = -ENODEV;		goto out;	}	if (thread->status == DM_THREAD_DONE) {		/* the thread has terminated while we were not		   watching */		_unlock_mutex();		return 0;	}	thread->events &= ~message_data->events.field;	if (!(thread->events & DM_EVENT_TIMEOUT))		_unregister_for_timeout(thread);	/*	 * In case there's no events to monitor on this device ->	 * unlink and terminate its monitoring thread.	 */	if (!thread->events) {		UNLINK_THREAD(thread);		LINK(thread, &_thread_registry_unused);	}	_unlock_mutex();      out:	return ret;}/* * Get registered device. * * Only one caller at a time here as with register_for_event(). */static int _registered_device(struct message_data *message_data,			     struct thread_status *thread){	struct dm_event_daemon_message *msg = message_data->msg;	const char *fmt = "%s %s %s %u";	const char *id = message_data->id;	const char *dso = thread->dso_data->dso_name;	const char *dev = thread->device.uuid;	unsigned events = ((thread->status == DM_THREAD_RUNNING)			   && (thread->events)) ? thread->events : thread->	    events | DM_EVENT_REGISTRATION_PENDING;	if (msg->data)		dm_free(msg->data);	msg->size = dm_asprintf(&(msg->data), fmt, id, dso, dev, events);	_unlock_mutex();	return 0;}static int _want_registered_device(char *dso_name, char *device_uuid,				  struct thread_status *thread){	/* If DSO names and device paths are equal. */	if (dso_name && device_uuid)		return !strcmp(dso_name, thread->dso_data->dso_name) &&		    !strcmp(device_uuid, thread->device.uuid) &&			(thread->status == DM_THREAD_RUNNING ||			 (thread->events & DM_EVENT_REGISTRATION_PENDING));	/* If DSO names are equal. */	if (dso_name)		return !strcmp(dso_name, thread->dso_data->dso_name) &&			(thread->status == DM_THREAD_RUNNING ||			 (thread->events & DM_EVENT_REGISTRATION_PENDING));	/* If device paths are equal. */	if (device_uuid)		return !strcmp(device_uuid, thread->device.uuid) &&			(thread->status == DM_THREAD_RUNNING ||			 (thread->events & DM_EVENT_REGISTRATION_PENDING));	return 1;}static int _get_registered_dev(struct message_data *message_data, int next){	struct thread_status *thread, *hit = NULL;	_lock_mutex();	/* Iterate list of threads checking if we want a particular one. */	list_iterate_items(thread, &_thread_registry)		if (_want_registered_device(message_data->dso_name,					    message_data->device_uuid,					    thread)) {			hit = thread;			break;		}	/*	 * If we got a registered device and want the next one ->	 * fetch next conforming element off the list.	 */	if (hit && !next) {		_unlock_mutex();		return _registered_device(message_data, hit);	}	if (!hit)		goto out;	thread = hit;	while (1) {		if (list_end(&_thread_registry, &thread->list))			goto out;		thread = list_item(thread->list.n, struct thread_status);		if (_want_registered_device(message_data->dso_name, NULL, thread)) {			hit = thread;			break;		}	}	_unlock_mutex();	return _registered_device(message_data, hit);      out:	_unlock_mutex();		return -ENOENT;}static int _get_registered_device(struct message_data *message_data){	return _get_registered_dev(message_data, 0);}static int _get_next_registered_device(struct message_data *message_data){	return _get_registered_dev(message_data, 1);}static int _set_timeout(struct message_data *message_data){	struct thread_status *thread;	_lock_mutex();	if ((thread = _lookup_thread_status(message_data)))		thread->timeout = message_data->timeout.secs;	_unlock_mutex();	return thread ? 0 : -ENODEV;}static int _get_timeout(struct message_data *message_data)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -