Module: xenomai-rpm Branch: queue/vfile Commit: 2ca77b4777a3b8a9171ed2db4c8df5aedec39d2b URL: http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=2ca77b4777a3b8a9171ed2db4c8df5aedec39d2b
Author: Philippe Gerum <r...@xenomai.org> Date: Tue May 25 17:36:56 2010 +0200 nucleus: introduce virtual file support Virtual files provide a mean to export Xenomai object states to user-space, based on common kernel interfaces. This encapsulation is aimed at: - supporting consistent collection of very large record-based output, without encurring latency peaks for undergoing real-time activities. - in the future, hiding discrepancies between linux kernel releases, regarding the proper way to export kernel object states to userland, either via the /proc interface or by any other mean. This virtual file implementation offers record-based read support based on seq_files, single-buffer write support, directory and link handling, all visible from the /proc namespace. --- include/nucleus/vfile.h | 285 ++++++++++++++++++++ ksrc/nucleus/vfile.c | 658 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 943 insertions(+), 0 deletions(-) diff --git a/include/nucleus/vfile.h b/include/nucleus/vfile.h new file mode 100644 index 0000000..ab1fd91 --- /dev/null +++ b/include/nucleus/vfile.h @@ -0,0 +1,285 @@ +/** + * @file + * This file is part of the Xenomai project. + * + * @note Copyright (C) 2010 Philippe Gerum <r...@xenomai.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * \ingroup vfile + */ + +#ifndef _XENO_NUCLEUS_VFILE_H +#define _XENO_NUCLEUS_VFILE_H + +#ifdef CONFIG_PROC_FS + +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <nucleus/types.h> + +struct xnvfile_directory; +struct xnvfile_regular_iterator; +struct xnvfile_snapshot_iterator; +struct xnvfile_lock_ops; + +struct xnvfile { + struct proc_dir_entry *pde; + struct xnvfile_directory *parent; + struct xnvfile_lock_ops *lockops; + void *private; +}; + +struct xnvfile_lock_ops { + void (*get)(struct xnvfile *vfile); + void (*put)(struct xnvfile *vfile); +}; + +/* + * XXX: struct semaphore is legacy for mutual exclusion, but supported + * on both 2.4 and 2.6 kernels. Will be changed to mutex when 2.4 + * support is dropped from Xenomai. + */ +struct xnvfile_hostlock_class { + struct xnvfile_lock_ops ops; + struct semaphore sem; +}; + +struct xnvfile_nklock_class { + struct xnvfile_lock_ops ops; + spl_t s; +}; + +struct xnvfile_input { + const char __user *u_buf; + size_t size; + struct xnvfile *vfile; +}; + +struct xnvfile_regular_ops { + void *(*begin)(struct xnvfile_regular_iterator *it); + void *(*next)(struct xnvfile_regular_iterator *it); + void (*end)(struct xnvfile_regular_iterator *it); + int (*show)(struct xnvfile_regular_iterator *it, void *data); + ssize_t (*store)(struct xnvfile_input *input); +}; + +struct xnvfile_regular { + struct xnvfile entry; + size_t privsz; + struct xnvfile_regular_ops *ops; +}; + +struct xnvfile_regular_template { + size_t privsz; + struct xnvfile_regular_ops *ops; + struct xnvfile_lock_ops *lockops; +}; + +struct xnvfile_regular_iterator { + loff_t pos; + struct seq_file *seq; + struct xnvfile_regular *vfile; + char private[0]; +}; + +struct xnvfile_snapshot_ops { + int (*rewind)(struct xnvfile_snapshot_iterator *it); + void *(*begin)(struct xnvfile_snapshot_iterator *it); + int (*next)(struct xnvfile_snapshot_iterator *it, void *data); + void (*end)(struct xnvfile_snapshot_iterator *it, void *buf); + int (*show)(struct xnvfile_snapshot_iterator *it, void *data); + ssize_t (*store)(struct xnvfile_input *input); +}; + +struct xnvfile_rev_tag { + int rev; +}; + +struct xnvfile_snapshot_template { + size_t privsz; + size_t datasz; + struct xnvfile_rev_tag *tag; + struct xnvfile_snapshot_ops *ops; + struct xnvfile_lock_ops *lockops; +}; + +struct xnvfile_snapshot { + struct xnvfile entry; + size_t privsz; + size_t datasz; + struct xnvfile_rev_tag *tag; + struct xnvfile_snapshot_ops *ops; +}; + +struct xnvfile_snapshot_iterator { + int nrdata; + caddr_t databuf; + struct seq_file *seq; + struct xnvfile_snapshot *vfile; + void (*endfn)(struct xnvfile_snapshot_iterator *it, void *buf); + char private[0]; +}; + +struct xnvfile_directory { + struct xnvfile entry; +}; + +struct xnvfile_link { + struct xnvfile entry; +}; + +/* vfile.begin()=> */ +#define VFILE_SEQ_EMPTY ((void *)-1) +/* =>vfile.show() */ +#define VFILE_SEQ_START SEQ_START_TOKEN +/* vfile.next/show()=> */ +#define VFILE_SEQ_SKIP 2 + +#define xnvfile_printf(it, args...) seq_printf((it)->seq, ##args) +#define xnvfile_write(it, data, len) seq_write((it)->seq, (data),(len)) +#define xnvfile_puts(it, s) seq_puts((it)->seq, (s)) +#define xnvfile_putc(it, c) seq_putc((it)->seq, (c)) + +static inline void xnvfile_touch_tag(struct xnvfile_rev_tag *tag) +{ + tag->rev++; +} + +static inline void xnvfile_touch(struct xnvfile_snapshot *vfile) +{ + xnvfile_touch_tag(vfile->tag); +} + +static inline void *xnvfile_snapshot_iterator_priv(struct xnvfile_snapshot_iterator *it) +{ + return &it->private; +} + +static inline int xnvfile_reg_p(struct xnvfile *entry) +{ + return S_ISREG(entry->pde->mode); +} + +static inline int xnvfile_dir_p(struct xnvfile *entry) +{ + return S_ISDIR(entry->pde->mode); +} + +static inline int xnvfile_link_p(struct xnvfile *entry) +{ + return S_ISLNK(entry->pde->mode); +} + +#define xnvfile_noentry \ + { \ + .pde = NULL, \ + .parent = NULL, \ + .private = NULL, \ + } + +#define xnvfile_nodir { .entry = xnvfile_noentry } +#define xnvfile_nolink { .entry = xnvfile_noentry } +#define xnvfile_nofile { .entry = xnvfile_noentry } + +#define xnvfile_parent(e) ((e)->entry.parent) +#define xnvfile_priv(e) ((e)->entry.private) + +extern struct xnvfile_nklock_class xnvfile_nucleus_lock; + +extern struct xnvfile_directory nkvfroot; + +int xnvfile_init_root(void); + +void xnvfile_destroy_root(void); + +#ifdef __cplusplus +extern "C" { +#endif + +int xnvfile_init_snapshot(const char *name, + struct xnvfile_snapshot *vfile, + struct xnvfile_directory *parent); + +int xnvfile_init_regular(const char *name, + struct xnvfile_regular *vfile, + struct xnvfile_directory *parent); + +int xnvfile_init_dir(const char *name, + struct xnvfile_directory *vdir, + struct xnvfile_directory *parent); + +int xnvfile_init_link(const char *from, + const char *to, + struct xnvfile_link *vlink, + struct xnvfile_directory *parent); + +void xnvfile_destroy(struct xnvfile *vfile); + +ssize_t xnvfile_get_blob(struct xnvfile_input *input, + void *data, size_t size); + +ssize_t xnvfile_get_integer(struct xnvfile_input *input, long *valp); + +void __vfile_hostlock_get(struct xnvfile *vfile); + +void __vfile_hostlock_put(struct xnvfile *vfile); + +#ifdef __cplusplus +} +#endif + +static inline +void xnvfile_destroy_snapshot(struct xnvfile_snapshot *vfile) +{ + xnvfile_destroy(&vfile->entry); +} + +static inline +void xnvfile_destroy_regular(struct xnvfile_regular *vfile) +{ + xnvfile_destroy(&vfile->entry); +} + +static inline +void xnvfile_destroy_dir(struct xnvfile_directory *vdir) +{ + xnvfile_destroy(&vdir->entry); +} + +static inline +void xnvfile_destroy_link(struct xnvfile_link *vlink) +{ + xnvfile_destroy(&vlink->entry); +} + +#define DEFINE_VFILE_HOSTLOCK(name) \ + struct xnvfile_hostlock_class name = { \ + .ops = { \ + .get = __vfile_hostlock_get, \ + .put = __vfile_hostlock_put, \ + }, \ + .sem = __SEMAPHORE_INITIALIZER(name.sem, 1), \ + } + +#else /* !CONFIG_PROC_FS */ + +#define xnvfile_touch_tag(tag) do { } while (0) + +#define xnvfile_touch(vfile) do { } while (0) + +#endif /* !CONFIG_PROC_FS */ + +#endif /* !_XENO_NUCLEUS_VFILE_H */ diff --git a/ksrc/nucleus/vfile.c b/ksrc/nucleus/vfile.c new file mode 100644 index 0000000..f7649a0 --- /dev/null +++ b/ksrc/nucleus/vfile.c @@ -0,0 +1,658 @@ +/** + * @file + * This file is part of the Xenomai project. + * + * @note Copyright (C) 2010 Philippe Gerum <r...@xenomai.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * \ingroup vfile + */ + +/*! + * \ingroup nucleus + * \defgroup vfile Virtual file services. + * + * Virtual files provide a mean to export Xenomai object states to + * user-space, based on common kernel interfaces. This encapsulation + * is aimed at: + * + * - supporting consistent collection of very large record-based + * output, without encurring latency peaks for undergoing real-time + * activities. + * + * - in the future, hiding discrepancies between linux kernel + * releases, regarding the proper way to export kernel object states + * to userland, either via the /proc interface or by any other mean. + * + * This virtual file implementation offers record-based read support + * based on seq_files, single-buffer write support, directory and link + * handling, all visible from the /proc namespace. + * + *...@{*/ + +#include <stdarg.h> +#include <linux/ctype.h> +#include <nucleus/pod.h> +#include <nucleus/assert.h> +#include <nucleus/vfile.h> + +struct xnvfile_directory nkvfroot; +EXPORT_SYMBOL_GPL(nkvfroot); + +static void *vfile_snapshot_start(struct seq_file *seq, loff_t *offp) +{ + struct xnvfile_snapshot_iterator *it = seq->private; + loff_t pos = *offp; + + if (pos > it->nrdata) + return NULL; + + if (pos == 0) + return SEQ_START_TOKEN; + + return it->databuf + (pos - 1) * it->vfile->datasz; +} + +static void *vfile_snapshot_next(struct seq_file *seq, void *v, loff_t *offp) +{ + struct xnvfile_snapshot_iterator *it = seq->private; + loff_t pos = ++*offp; + + if (pos > it->nrdata) + return NULL; + + return it->databuf + (pos - 1) * it->vfile->datasz; +} + +static void vfile_snapshot_stop(struct seq_file *seq, void *v) +{ +} + +static int vfile_snapshot_show(struct seq_file *seq, void *v) +{ + struct xnvfile_snapshot_iterator *it = seq->private; + void *data = v == SEQ_START_TOKEN ? NULL : v; + int ret; + + ret = it->vfile->ops->show(it, data); + + return ret == VFILE_SEQ_SKIP ? SEQ_SKIP : ret; +} + +static struct seq_operations vfile_snapshot_ops = { + .start = vfile_snapshot_start, + .next = vfile_snapshot_next, + .stop = vfile_snapshot_stop, + .show = vfile_snapshot_show +}; + +static void vfile_snapshot_free(struct xnvfile_snapshot_iterator *it, void *buf) +{ + kfree(buf); +} + +static int vfile_snapshot_open(struct inode *inode, struct file *file) +{ + struct proc_dir_entry *pde = PDE(inode); + struct xnvfile_snapshot *vfile = pde->data; + struct xnvfile_snapshot_ops *ops = vfile->ops; + struct xnvfile_snapshot_iterator *it; + int revtag, ret, nrdata; + struct seq_file *seq; + caddr_t data; + + /* + * There is no point in reading/writing to v-files that must + * be connected to Xenomai resources if the system has not + * been initialized yet (i.e. xnpod_init() called). + */ + if (!xnpod_active_p()) + return -ESRCH; + + if ((file->f_mode & FMODE_WRITE) != 0 && ops->store == NULL) + return -EACCES; + + /* + * Make sure to create the seq_file backend only when reading + * from the v-file is possible. + */ + if ((file->f_mode & FMODE_READ) == 0) { + file->private_data = NULL; + return 0; + } + + it = kzalloc(sizeof(*it) + vfile->privsz, GFP_KERNEL); + if (it == NULL) + return -ENOMEM; + + it->vfile = vfile; + + vfile->entry.lockops->get(&vfile->entry); +redo: + /* + * The ->rewind() method is optional; there may be cases where + * we don't have to take an atomic snapshot of the v-file + * contents before proceeding. In case ->rewind() detects a + * stale backend object, it can force us to bail out. + * + * If present, ->rewind() may return a strictly positive + * value, indicating how many records at most may be returned + * by ->next(). We use this hint to allocate the snapshot + * buffer, in case ->begin() is not provided. The size of this + * buffer would then be vfile->datasz * hint value. + * + * If ->begin() is given, we always expect the latter do the + * allocation for us regardless of the hint value. Otherwise, + * a null return from ->rewind() tells us that the vfile won't + * output any snapshot data via ->show(). + */ + it->endfn = ops->end; + nrdata = 0; + if (ops->rewind) { + nrdata = ops->rewind(it); + if (nrdata < 0) { + ret = nrdata; + vfile->entry.lockops->put(&vfile->entry); + goto fail; + } + } + revtag = vfile->tag->rev; + + vfile->entry.lockops->put(&vfile->entry); + + /* Release the data buffer, in case we had to restart. */ + if (it->databuf) { + it->endfn(it, it->databuf); + it->databuf = NULL; + } + + /* + * Having no record to output is fine, in which case ->begin() + * shall return VFILE_SEQ_EMPTY if present. ->begin() may be + * absent, meaning that no allocation is even required to + * collect the records to output. NULL is kept for allocation + * errors in all other cases. + */ + if (ops->begin) { + XENO_BUGON(NUCLEUS, ops->end == NULL); + data = ops->begin(it); + if (data == NULL) { + kfree(it); + return -ENOMEM; + } + if (data != VFILE_SEQ_EMPTY) + it->databuf = data; + } else if (nrdata > 0) { /* Any hint for auto-allocation? */ + data = kmalloc(vfile->datasz * nrdata, GFP_KERNEL); + if (data == NULL) { + kfree(it); + return -ENOMEM; + } + it->databuf = data; + it->endfn = vfile_snapshot_free; + } + + ret = seq_open(file, &vfile_snapshot_ops); + if (ret) + goto fail; + + it->nrdata = 0; + data = it->databuf; + if (data == NULL) + goto finish; + + /* + * Take a snapshot of the vfile contents, redo if the revision + * tag of the scanned data set changed concurrently. + */ + for (;;) { + vfile->entry.lockops->get(&vfile->entry); + if (vfile->tag->rev != revtag) + goto redo; + ret = ops->next(it, data); + vfile->entry.lockops->put(&vfile->entry); + if (ret <= 0) + break; + if (ret != VFILE_SEQ_SKIP) { + data += vfile->datasz; + it->nrdata++; + } + } + + if (ret < 0) { + seq_release(inode, file); + fail: + if (it->databuf) + it->endfn(it, it->databuf); + kfree(it); + return ret; + } + +finish: + seq = file->private_data; + it->seq = seq; + seq->private = it; + + return 0; +} + +static int vfile_snapshot_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct xnvfile_snapshot_iterator *it; + + if (seq) { + it = seq->private; + if (it) { + if (it->databuf) + it->endfn(it, it->databuf); + kfree(it); + } + + return seq_release(inode, file); + } + + return 0; +} + +ssize_t vfile_snapshot_write(struct file *file, const char __user *buf, + size_t size, loff_t *ppos) +{ + struct proc_dir_entry *pde = PDE(wrap_f_inode(file)); + struct xnvfile_snapshot *vfile = pde->data; + struct xnvfile_input input; + + input.u_buf = buf; + input.size = size; + input.vfile = &vfile->entry; + + return vfile->ops->store(&input); +} + +static struct file_operations vfile_snapshot_fops = { + .owner = THIS_MODULE, + .open = vfile_snapshot_open, + .read = seq_read, + .write = vfile_snapshot_write, + .llseek = seq_lseek, + .release = vfile_snapshot_release, +}; + +int xnvfile_init_snapshot(const char *name, + struct xnvfile_snapshot *vfile, + struct xnvfile_directory *parent) +{ + struct proc_dir_entry *ppde, *pde; + int mode; + + XENO_BUGON(NUCLEUS, vfile->tag == NULL); + + if (vfile->entry.lockops == NULL) + /* Defaults to nucleus lock */ + vfile->entry.lockops = &xnvfile_nucleus_lock.ops; + + if (parent == NULL) + parent = &nkvfroot; + + mode = vfile->ops->store ? 0644 : 0444; + ppde = parent->entry.pde; + pde = create_proc_entry(name, mode, ppde); + if (pde == NULL) + return -ENOMEM; + + pde->proc_fops = &vfile_snapshot_fops; + wrap_proc_dir_entry_owner(pde); + + vfile->entry.parent = parent; + vfile->entry.pde = pde; + pde->data = vfile; + + return 0; +} +EXPORT_SYMBOL_GPL(xnvfile_init_snapshot); + +static void *vfile_regular_start(struct seq_file *seq, loff_t *offp) +{ + struct xnvfile_regular_iterator *it = seq->private; + struct xnvfile_regular *vfile = it->vfile; + + it->pos = *offp; + + if (vfile->entry.lockops) + vfile->entry.lockops->get(&vfile->entry); + + /* + * If we have no begin() op, then we allow a single call only + * to ->show(), by returning the start token once. Otherwise, + * we are done. + */ + if (vfile->ops->begin == NULL) + return it->pos > 0 ? NULL : SEQ_START_TOKEN; + + return vfile->ops->begin(it); +} + +static void *vfile_regular_next(struct seq_file *seq, void *v, loff_t *offp) +{ + struct xnvfile_regular_iterator *it = seq->private; + struct xnvfile_regular *vfile = it->vfile; + loff_t pos = ++*offp; + + if (vfile->ops->next == NULL) + return NULL; + + it->pos = pos; + + return vfile->ops->next(it); +} + +static void vfile_regular_stop(struct seq_file *seq, void *v) +{ + struct xnvfile_regular_iterator *it = seq->private; + struct xnvfile_regular *vfile = it->vfile; + + if (vfile->entry.lockops) + vfile->entry.lockops->put(&vfile->entry); + + if (vfile->ops->end) + vfile->ops->end(it); +} + +static int vfile_regular_show(struct seq_file *seq, void *v) +{ + struct xnvfile_regular_iterator *it = seq->private; + struct xnvfile_regular *vfile = it->vfile; + void *data = v == SEQ_START_TOKEN ? NULL : v; + int ret; + + ret = vfile->ops->show(it, data); + + return ret == VFILE_SEQ_SKIP ? SEQ_SKIP : ret; +} + +static struct seq_operations vfile_regular_ops = { + .start = vfile_regular_start, + .next = vfile_regular_next, + .stop = vfile_regular_stop, + .show = vfile_regular_show +}; + +static int vfile_regular_open(struct inode *inode, struct file *file) +{ + struct proc_dir_entry *pde = PDE(inode); + struct xnvfile_regular *vfile = pde->data; + struct xnvfile_regular_ops *ops = vfile->ops; + struct xnvfile_regular_iterator *it; + struct seq_file *seq; + int ret; + + if ((file->f_mode & FMODE_WRITE) != 0 && + ops->store == NULL) + return -EACCES; + + if ((file->f_mode & FMODE_READ) == 0) { + file->private_data = NULL; + return 0; + } + + it = kzalloc(sizeof(*it) + vfile->privsz, GFP_KERNEL); + if (it == NULL) + return -ENOMEM; + + it->vfile = vfile; + + ret = seq_open(file, &vfile_regular_ops); + if (ret) { + kfree(it); + return ret; + } + + seq = file->private_data; + it->seq = seq; + seq->private = it; + + return 0; +} + +static int vfile_regular_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct xnvfile_regular_iterator *it; + + if (seq) { + it = seq->private; + if (it) + kfree(it); + + return seq_release(inode, file); + } + + return 0; +} + +ssize_t vfile_regular_write(struct file *file, const char __user *buf, + size_t size, loff_t *ppos) +{ + struct proc_dir_entry *pde = PDE(wrap_f_inode(file)); + struct xnvfile_regular *vfile = pde->data; + struct xnvfile_input input; + + input.u_buf = buf; + input.size = size; + input.vfile = &vfile->entry; + + return vfile->ops->store(&input); +} + +static struct file_operations vfile_regular_fops = { + .owner = THIS_MODULE, + .open = vfile_regular_open, + .read = seq_read, + .write = vfile_regular_write, + .llseek = seq_lseek, + .release = vfile_regular_release, +}; + +int xnvfile_init_regular(const char *name, + struct xnvfile_regular *vfile, + struct xnvfile_directory *parent) +{ + struct proc_dir_entry *ppde, *pde; + int mode; + + if (parent == NULL) + parent = &nkvfroot; + + mode = vfile->ops->store ? 0644 : 0444; + ppde = parent->entry.pde; + pde = create_proc_entry(name, mode, ppde); + if (pde == NULL) + return -ENOMEM; + + pde->proc_fops = &vfile_regular_fops; + wrap_proc_dir_entry_owner(pde); + + vfile->entry.parent = parent; + vfile->entry.pde = pde; + pde->data = vfile; + + return 0; +} +EXPORT_SYMBOL_GPL(xnvfile_init_regular); + +int xnvfile_init_dir(const char *name, + struct xnvfile_directory *vdir, + struct xnvfile_directory *parent) +{ + struct proc_dir_entry *ppde, *pde; + + if (parent == NULL) + parent = &nkvfroot; + + ppde = parent->entry.pde; + pde = create_proc_entry(name, S_IFDIR, ppde); + if (pde == NULL) + return -ENOMEM; + + vdir->entry.parent = parent; + vdir->entry.pde = pde; + vdir->entry.lockops = NULL; + vdir->entry.private = NULL; + wrap_proc_dir_entry_owner(pde); + + return 0; +} +EXPORT_SYMBOL_GPL(xnvfile_init_dir); + +int xnvfile_init_link(const char *from, + const char *to, + struct xnvfile_link *vlink, + struct xnvfile_directory *parent) +{ + struct proc_dir_entry *ppde, *pde; + + if (parent == NULL) + parent = &nkvfroot; + + ppde = parent->entry.pde; + pde = proc_symlink(from, ppde, to); + if (vlink->entry.pde == NULL) + return -ENOMEM; + + vlink->entry.parent = parent; + vlink->entry.pde = pde; + vlink->entry.lockops = NULL; + vlink->entry.private = NULL; + wrap_proc_dir_entry_owner(pde); + + return 0; +} +EXPORT_SYMBOL_GPL(xnvfile_init_link); + +void xnvfile_destroy(struct xnvfile *vfile) +{ + struct proc_dir_entry *ppde; + + ppde = vfile->parent ? vfile->parent->entry.pde : nkvfroot.entry.pde; + remove_proc_entry(vfile->pde->name, ppde); +} +EXPORT_SYMBOL_GPL(xnvfile_destroy); + +ssize_t xnvfile_get_blob(struct xnvfile_input *input, + void *data, size_t size) +{ + ssize_t nbytes = input->size; + + if (nbytes < size) + nbytes = size; + + if (nbytes > 0 && + __xn_safe_copy_from_user(data, input->u_buf, nbytes)) + return -EFAULT; + + return nbytes; +} +EXPORT_SYMBOL_GPL(xnvfile_get_blob); + +ssize_t xnvfile_get_integer(struct xnvfile_input *input, long *valp) +{ + char *end, buf[32]; + ssize_t nbytes; + long val; + + nbytes = xnvfile_get_blob(input, buf, sizeof(buf)); + if (nbytes < 0) + return nbytes; + + if (nbytes == 0) + return -EINVAL; + + buf[nbytes] = '\0'; + val = simple_strtol(buf, &end, 0); + + if (*end != '\0' && !isspace(*end)) + return -EINVAL; + + *valp = val; + + return nbytes; +} +EXPORT_SYMBOL_GPL(xnvfile_get_integer); + +void __vfile_hostlock_get(struct xnvfile *vfile) +{ + struct xnvfile_hostlock_class *lc; + + lc = container_of(vfile->lockops, struct xnvfile_hostlock_class, ops); + down(&lc->sem); +} +EXPORT_SYMBOL_GPL(__vfile_hostlock_get); + +void __vfile_hostlock_put(struct xnvfile *vfile) +{ + struct xnvfile_hostlock_class *lc; + + lc = container_of(vfile->lockops, struct xnvfile_hostlock_class, ops); + up(&lc->sem); +} +EXPORT_SYMBOL_GPL(__vfile_hostlock_put); + +static void __vfile_nklock_get(struct xnvfile *vfile) +{ + struct xnvfile_nklock_class *lc; + + lc = container_of(vfile->lockops, struct xnvfile_nklock_class, ops); + xnlock_get_irqsave(&nklock, lc->s); +} + +static void __vfile_nklock_put(struct xnvfile *vfile) +{ + struct xnvfile_nklock_class *lc; + + lc = container_of(vfile->lockops, struct xnvfile_nklock_class, ops); + xnlock_put_irqrestore(&nklock, lc->s); +} + +struct xnvfile_nklock_class xnvfile_nucleus_lock = { + .ops = { + .get = __vfile_nklock_get, + .put = __vfile_nklock_put, + }, +}; + +int __init xnvfile_init_root(void) +{ + struct xnvfile_directory *vdir = &nkvfroot; + struct proc_dir_entry *pde; + + pde = create_proc_entry("xenomai", S_IFDIR, NULL); + if (pde == NULL) + return -ENOMEM; + + vdir->entry.parent = NULL; + vdir->entry.pde = pde; + vdir->entry.lockops = NULL; + vdir->entry.private = NULL; + wrap_proc_dir_entry_owner(pde); + + return 0; +} + +void __exit xnvfile_destroy_root(void) +{ + nkvfroot.entry.pde = NULL; + remove_proc_entry("xenomai", NULL); +} _______________________________________________ Xenomai-git mailing list Xenomai-git@gna.org https://mail.gna.org/listinfo/xenomai-git