xenbus_xs.c

来自「linux 内核源代码」· C语言 代码 · 共 862 行 · 第 1/2 页

C
862
字号
	char *id_str;	down_read(&xs_state.transaction_mutex);	id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL);	if (IS_ERR(id_str)) {		up_read(&xs_state.transaction_mutex);		return PTR_ERR(id_str);	}	t->id = simple_strtoul(id_str, NULL, 0);	kfree(id_str);	return 0;}EXPORT_SYMBOL_GPL(xenbus_transaction_start);/* End a transaction. * If abandon is true, transaction is discarded instead of committed. */int xenbus_transaction_end(struct xenbus_transaction t, int abort){	char abortstr[2];	int err;	if (abort)		strcpy(abortstr, "F");	else		strcpy(abortstr, "T");	err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL));	up_read(&xs_state.transaction_mutex);	return err;}EXPORT_SYMBOL_GPL(xenbus_transaction_end);/* Single read and scanf: returns -errno or num scanned. */int xenbus_scanf(struct xenbus_transaction t,		 const char *dir, const char *node, const char *fmt, ...){	va_list ap;	int ret;	char *val;	val = xenbus_read(t, dir, node, NULL);	if (IS_ERR(val))		return PTR_ERR(val);	va_start(ap, fmt);	ret = vsscanf(val, fmt, ap);	va_end(ap);	kfree(val);	/* Distinctive errno. */	if (ret == 0)		return -ERANGE;	return ret;}EXPORT_SYMBOL_GPL(xenbus_scanf);/* Single printf and write: returns -errno or 0. */int xenbus_printf(struct xenbus_transaction t,		  const char *dir, const char *node, const char *fmt, ...){	va_list ap;	int ret;#define PRINTF_BUFFER_SIZE 4096	char *printf_buffer;	printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);	if (printf_buffer == NULL)		return -ENOMEM;	va_start(ap, fmt);	ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap);	va_end(ap);	BUG_ON(ret > PRINTF_BUFFER_SIZE-1);	ret = xenbus_write(t, dir, node, printf_buffer);	kfree(printf_buffer);	return ret;}EXPORT_SYMBOL_GPL(xenbus_printf);/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */int xenbus_gather(struct xenbus_transaction t, const char *dir, ...){	va_list ap;	const char *name;	int ret = 0;	va_start(ap, dir);	while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {		const char *fmt = va_arg(ap, char *);		void *result = va_arg(ap, void *);		char *p;		p = xenbus_read(t, dir, name, NULL);		if (IS_ERR(p)) {			ret = PTR_ERR(p);			break;		}		if (fmt) {			if (sscanf(p, fmt, result) == 0)				ret = -EINVAL;			kfree(p);		} else			*(char **)result = p;	}	va_end(ap);	return ret;}EXPORT_SYMBOL_GPL(xenbus_gather);static int xs_watch(const char *path, const char *token){	struct kvec iov[2];	iov[0].iov_base = (void *)path;	iov[0].iov_len = strlen(path) + 1;	iov[1].iov_base = (void *)token;	iov[1].iov_len = strlen(token) + 1;	return xs_error(xs_talkv(XBT_NIL, XS_WATCH, iov,				 ARRAY_SIZE(iov), NULL));}static int xs_unwatch(const char *path, const char *token){	struct kvec iov[2];	iov[0].iov_base = (char *)path;	iov[0].iov_len = strlen(path) + 1;	iov[1].iov_base = (char *)token;	iov[1].iov_len = strlen(token) + 1;	return xs_error(xs_talkv(XBT_NIL, XS_UNWATCH, iov,				 ARRAY_SIZE(iov), NULL));}static struct xenbus_watch *find_watch(const char *token){	struct xenbus_watch *i, *cmp;	cmp = (void *)simple_strtoul(token, NULL, 16);	list_for_each_entry(i, &watches, list)		if (i == cmp)			return i;	return NULL;}/* Register callback to watch this node. */int register_xenbus_watch(struct xenbus_watch *watch){	/* Pointer in ascii is the token. */	char token[sizeof(watch) * 2 + 1];	int err;	sprintf(token, "%lX", (long)watch);	down_read(&xs_state.watch_mutex);	spin_lock(&watches_lock);	BUG_ON(find_watch(token));	list_add(&watch->list, &watches);	spin_unlock(&watches_lock);	err = xs_watch(watch->node, token);	/* Ignore errors due to multiple registration. */	if ((err != 0) && (err != -EEXIST)) {		spin_lock(&watches_lock);		list_del(&watch->list);		spin_unlock(&watches_lock);	}	up_read(&xs_state.watch_mutex);	return err;}EXPORT_SYMBOL_GPL(register_xenbus_watch);void unregister_xenbus_watch(struct xenbus_watch *watch){	struct xs_stored_msg *msg, *tmp;	char token[sizeof(watch) * 2 + 1];	int err;	sprintf(token, "%lX", (long)watch);	down_read(&xs_state.watch_mutex);	spin_lock(&watches_lock);	BUG_ON(!find_watch(token));	list_del(&watch->list);	spin_unlock(&watches_lock);	err = xs_unwatch(watch->node, token);	if (err)		printk(KERN_WARNING		       "XENBUS Failed to release watch %s: %i\n",		       watch->node, err);	up_read(&xs_state.watch_mutex);	/* Make sure there are no callbacks running currently (unless	   its us) */	if (current->pid != xenwatch_pid)		mutex_lock(&xenwatch_mutex);	/* Cancel pending watch events. */	spin_lock(&watch_events_lock);	list_for_each_entry_safe(msg, tmp, &watch_events, list) {		if (msg->u.watch.handle != watch)			continue;		list_del(&msg->list);		kfree(msg->u.watch.vec);		kfree(msg);	}	spin_unlock(&watch_events_lock);	if (current->pid != xenwatch_pid)		mutex_unlock(&xenwatch_mutex);}EXPORT_SYMBOL_GPL(unregister_xenbus_watch);void xs_suspend(void){	down_write(&xs_state.transaction_mutex);	down_write(&xs_state.watch_mutex);	mutex_lock(&xs_state.request_mutex);	mutex_lock(&xs_state.response_mutex);}void xs_resume(void){	struct xenbus_watch *watch;	char token[sizeof(watch) * 2 + 1];	mutex_unlock(&xs_state.response_mutex);	mutex_unlock(&xs_state.request_mutex);	up_write(&xs_state.transaction_mutex);	/* No need for watches_lock: the watch_mutex is sufficient. */	list_for_each_entry(watch, &watches, list) {		sprintf(token, "%lX", (long)watch);		xs_watch(watch->node, token);	}	up_write(&xs_state.watch_mutex);}void xs_suspend_cancel(void){	mutex_unlock(&xs_state.response_mutex);	mutex_unlock(&xs_state.request_mutex);	up_write(&xs_state.watch_mutex);	up_write(&xs_state.transaction_mutex);}static int xenwatch_thread(void *unused){	struct list_head *ent;	struct xs_stored_msg *msg;	for (;;) {		wait_event_interruptible(watch_events_waitq,					 !list_empty(&watch_events));		if (kthread_should_stop())			break;		mutex_lock(&xenwatch_mutex);		spin_lock(&watch_events_lock);		ent = watch_events.next;		if (ent != &watch_events)			list_del(ent);		spin_unlock(&watch_events_lock);		if (ent != &watch_events) {			msg = list_entry(ent, struct xs_stored_msg, list);			msg->u.watch.handle->callback(				msg->u.watch.handle,				(const char **)msg->u.watch.vec,				msg->u.watch.vec_size);			kfree(msg->u.watch.vec);			kfree(msg);		}		mutex_unlock(&xenwatch_mutex);	}	return 0;}static int process_msg(void){	struct xs_stored_msg *msg;	char *body;	int err;	/*	 * We must disallow save/restore while reading a xenstore message.	 * A partial read across s/r leaves us out of sync with xenstored.	 */	for (;;) {		err = xb_wait_for_data_to_read();		if (err)			return err;		mutex_lock(&xs_state.response_mutex);		if (xb_data_to_read())			break;		/* We raced with save/restore: pending data 'disappeared'. */		mutex_unlock(&xs_state.response_mutex);	}	msg = kmalloc(sizeof(*msg), GFP_KERNEL);	if (msg == NULL) {		err = -ENOMEM;		goto out;	}	err = xb_read(&msg->hdr, sizeof(msg->hdr));	if (err) {		kfree(msg);		goto out;	}	body = kmalloc(msg->hdr.len + 1, GFP_KERNEL);	if (body == NULL) {		kfree(msg);		err = -ENOMEM;		goto out;	}	err = xb_read(body, msg->hdr.len);	if (err) {		kfree(body);		kfree(msg);		goto out;	}	body[msg->hdr.len] = '\0';	if (msg->hdr.type == XS_WATCH_EVENT) {		msg->u.watch.vec = split(body, msg->hdr.len,					 &msg->u.watch.vec_size);		if (IS_ERR(msg->u.watch.vec)) {			err = PTR_ERR(msg->u.watch.vec);			kfree(msg);			goto out;		}		spin_lock(&watches_lock);		msg->u.watch.handle = find_watch(			msg->u.watch.vec[XS_WATCH_TOKEN]);		if (msg->u.watch.handle != NULL) {			spin_lock(&watch_events_lock);			list_add_tail(&msg->list, &watch_events);			wake_up(&watch_events_waitq);			spin_unlock(&watch_events_lock);		} else {			kfree(msg->u.watch.vec);			kfree(msg);		}		spin_unlock(&watches_lock);	} else {		msg->u.reply.body = body;		spin_lock(&xs_state.reply_lock);		list_add_tail(&msg->list, &xs_state.reply_list);		spin_unlock(&xs_state.reply_lock);		wake_up(&xs_state.reply_waitq);	} out:	mutex_unlock(&xs_state.response_mutex);	return err;}static int xenbus_thread(void *unused){	int err;	for (;;) {		err = process_msg();		if (err)			printk(KERN_WARNING "XENBUS error %d while reading "			       "message\n", err);		if (kthread_should_stop())			break;	}	return 0;}int xs_init(void){	int err;	struct task_struct *task;	INIT_LIST_HEAD(&xs_state.reply_list);	spin_lock_init(&xs_state.reply_lock);	init_waitqueue_head(&xs_state.reply_waitq);	mutex_init(&xs_state.request_mutex);	mutex_init(&xs_state.response_mutex);	init_rwsem(&xs_state.transaction_mutex);	init_rwsem(&xs_state.watch_mutex);	/* Initialize the shared memory rings to talk to xenstored */	err = xb_init_comms();	if (err)		return err;	task = kthread_run(xenwatch_thread, NULL, "xenwatch");	if (IS_ERR(task))		return PTR_ERR(task);	xenwatch_pid = task->pid;	task = kthread_run(xenbus_thread, NULL, "xenbus");	if (IS_ERR(task))		return PTR_ERR(task);	return 0;}

⌨️ 快捷键说明

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