/ addons / rtdm / vfile.c
vfile.c
  1  /**
  2   * @file
  3   * This file is part of the Xenomai project.
  4   *
  5   * @note Copyright (C) 2010 Philippe Gerum <rpm@xenomai.org>
  6   *
  7   * adapted to RTAI by Paolo Mantegazza <mantegazza@aero.polimi.it>
  8   *
  9   * This program is free software; you can redistribute it and/or
 10   * modify it under the terms of the GNU General Public License as
 11   * published by the Free Software Foundation; either version 2 of the
 12   * License, or (at your option) any later version.
 13   *
 14   * This program is distributed in the hope that it will be useful,
 15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 17   * GNU General Public License for more details.
 18   *
 19   * You should have received a copy of the GNU General Public License
 20   * along with this program; if not, write to the Free Software
 21   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 22   */
 23  
 24  /*!
 25   * @ingroup nucleus
 26   * @defgroup vfile Virtual file services
 27   *
 28   * Virtual files provide a mean to export RTAI object states to
 29   * user-space, based on common kernel interfaces.  This encapsulation
 30   * is aimed at:
 31   *
 32   * - supporting consistent collection of very large record-based
 33   * output, without encurring latency peaks for undergoing real-time
 34   * activities.
 35   *
 36   * - in the future, hiding discrepancies between linux kernel
 37   * releases, regarding the proper way to export kernel object states
 38   * to userland, either via the /proc interface or by any other mean.
 39   *
 40   * This virtual file implementation offers record-based read support
 41   * based on seq_files, single-buffer write support, directory and link
 42   * handling, all visible from the /proc namespace.
 43   *
 44   * The vfile support exposes four filesystem object types:
 45   *
 46   * - snapshot-driven file (struct xnvfile_snapshot). This is commonly
 47   * used to export real-time object states via the /proc filesystem. To
 48   * minimize the latency involved in protecting the vfile routines from
 49   * changes applied by real-time code on such objects, a snapshot of
 50   * the data to output is first taken under proper locking, before the
 51   * collected data is formatted and sent out in a lockless manner.
 52   *
 53   * Because a large number of records may have to be output, the data
 54   * collection phase is not strictly atomic as a whole, but only
 55   * protected at record level. The vfile implementation can be notified
 56   * of updates to the underlying data set, and restart the collection
 57   * from scratch until the snapshot is fully consistent.
 58   *
 59   * - regular sequential file (struct xnvfile_regular). This is
 60   * basically an encapsulated sequential file object as available from
 61   * the host kernel (i.e. seq_file), with a few additional features to
 62   * make it more handy in an RTAI environment, like implicit locking
 63   * support and shortened declaration for simplest, single-record
 64   * output.
 65   *
 66   * - virtual link (struct xnvfile_link). This is a symbolic link
 67   * feature integrated with the vfile semantics. The link target is
 68   * computed dynamically at creation time from a user-given helper
 69   * routine.
 70   *
 71   * - virtual directory (struct xnvfile_directory). A directory object,
 72   * which can be used to create a hierarchy for ordering a set of vfile
 73   * objects.
 74   *
 75   *@{*/
 76  
 77  #include <stdarg.h>
 78  #include <linux/ctype.h>
 79  
 80  #include <rtdm/vfile.h>
 81  
 82  /**
 83   * @var struct xnvfile_directory nkvfroot
 84   * @brief RTAI vfile root directory
 85   *
 86   * This vdir maps the /proc/rtai directory. It can be used to
 87   * create a hierarchy of RTAI-related vfiles under this root.
 88   */
 89  struct xnvfile_directory nkvfroot;
 90  EXPORT_SYMBOL_GPL(nkvfroot);
 91  
 92  static struct xnvfile_directory sysroot;
 93  
 94  static void *vfile_snapshot_start(struct seq_file *seq, loff_t *offp)
 95  {
 96  	struct xnvfile_snapshot_iterator *it = seq->private;
 97  	loff_t pos = *offp;
 98  
 99  	if (pos > it->nrdata)
100  		return NULL;
101  
102  	if (pos == 0)
103  		return SEQ_START_TOKEN;
104  
105  	return it->databuf + (pos - 1) * it->vfile->datasz;
106  }
107  
108  static void *vfile_snapshot_next(struct seq_file *seq, void *v, loff_t *offp)
109  {
110  	struct xnvfile_snapshot_iterator *it = seq->private;
111  	loff_t pos = *offp;
112  
113  	if (pos >= it->nrdata)
114  		return NULL;
115  
116  	++*offp;
117  
118  	return it->databuf + pos * it->vfile->datasz;
119  }
120  
121  static void vfile_snapshot_stop(struct seq_file *seq, void *v)
122  {
123  }
124  
125  static int vfile_snapshot_show(struct seq_file *seq, void *v)
126  {
127  	struct xnvfile_snapshot_iterator *it = seq->private;
128  	void *data = v == SEQ_START_TOKEN ? NULL : v;
129  	int ret;
130  
131  	ret = it->vfile->ops->show(it, data);
132  
133  	return ret == VFILE_SEQ_SKIP ? SEQ_SKIP : ret;
134  }
135  
136  static struct seq_operations vfile_snapshot_ops = {
137  	.start = vfile_snapshot_start,
138  	.next = vfile_snapshot_next,
139  	.stop = vfile_snapshot_stop,
140  	.show = vfile_snapshot_show
141  };
142  
143  static void vfile_snapshot_free(struct xnvfile_snapshot_iterator *it, void *buf)
144  {
145  	kfree(buf);
146  }
147  
148  static int vfile_snapshot_open(struct inode *inode, struct file *file)
149  {
150  	struct xnvfile_snapshot *vfile = PDE_DATA(inode);
151  	struct xnvfile_snapshot_ops *ops = vfile->ops;
152  	struct xnvfile_snapshot_iterator *it;
153  	int revtag, ret, nrdata;
154  	struct seq_file *seq;
155  	caddr_t data;
156  
157  	if ((file->f_mode & FMODE_WRITE) != 0 && ops->store == NULL)
158  		return -EACCES;
159  
160  	/*
161  	 * Make sure to create the seq_file backend only when reading
162  	 * from the v-file is possible.
163  	 */
164  	if ((file->f_mode & FMODE_READ) == 0) {
165  		file->private_data = NULL;
166  		return 0;
167  	}
168  
169  	if ((file->f_flags & O_EXCL) != 0 && xnvfile_nref(vfile) > 0)
170  		return -EBUSY;
171  
172  	it = kzalloc(sizeof(*it) + vfile->privsz, GFP_KERNEL);
173  	if (it == NULL)
174  		return -ENOMEM;
175  
176  	it->vfile = vfile;
177  	xnvfile_file(vfile) = file;
178  
179  	ret = vfile->entry.lockops->get(&vfile->entry);
180  	if (ret)
181  		goto fail;
182  redo:
183  	/*
184  	 * The ->rewind() method is optional; there may be cases where
185  	 * we don't have to take an atomic snapshot of the v-file
186  	 * contents before proceeding. In case ->rewind() detects a
187  	 * stale backend object, it can force us to bail out.
188  	 *
189  	 * If present, ->rewind() may return a strictly positive
190  	 * value, indicating how many records at most may be returned
191  	 * by ->next(). We use this hint to allocate the snapshot
192  	 * buffer, in case ->begin() is not provided. The size of this
193  	 * buffer would then be vfile->datasz * hint value.
194  	 *
195  	 * If ->begin() is given, we always expect the latter do the
196  	 * allocation for us regardless of the hint value. Otherwise,
197  	 * a NULL return from ->rewind() tells us that the vfile won't
198  	 * output any snapshot data via ->show().
199  	 */
200  	nrdata = 0;
201  	if (ops->rewind) {
202  		nrdata = ops->rewind(it);
203  		if (nrdata < 0) {
204  			ret = nrdata;
205  			vfile->entry.lockops->put(&vfile->entry);
206  			goto fail;
207  		}
208  	}
209  	revtag = vfile->tag->rev;
210  
211  	vfile->entry.lockops->put(&vfile->entry);
212  
213  	/* Release the data buffer, in case we had to restart. */
214  	if (it->databuf) {
215  		it->endfn(it, it->databuf);
216  		it->databuf = NULL;
217  	}
218  
219  	/*
220  	 * Having no record to output is fine, in which case ->begin()
221  	 * shall return VFILE_SEQ_EMPTY if present. ->begin() may be
222  	 * absent, meaning that no allocation is even required to
223  	 * collect the records to output. NULL is kept for allocation
224  	 * errors in all other cases.
225  	 */
226  	if (ops->begin) {
227  		RTAI_BUGON(NUCLEUS, ops->end == NULL);
228  		data = ops->begin(it);
229  		if (data == NULL) {
230  			kfree(it);
231  			return -ENOMEM;
232  		}
233  		if (data != VFILE_SEQ_EMPTY) {
234  			it->databuf = data;
235  			it->endfn = ops->end;
236  		}
237  	} else if (nrdata > 0 && vfile->datasz > 0) {
238  		/* We have a hint for auto-allocation. */
239  		data = kmalloc(vfile->datasz * nrdata, GFP_KERNEL);
240  		if (data == NULL) {
241  			kfree(it);
242  			return -ENOMEM;
243  		}
244  		it->databuf = data;
245  		it->endfn = vfile_snapshot_free;
246  	}
247  
248  	ret = seq_open(file, &vfile_snapshot_ops);
249  	if (ret)
250  		goto fail;
251  
252  	it->nrdata = 0;
253  	data = it->databuf;
254  	if (data == NULL)
255  		goto finish;
256  
257  	/*
258  	 * Take a snapshot of the vfile contents, redo if the revision
259  	 * tag of the scanned data set changed concurrently.
260  	 */
261  	for (;;) {
262  		ret = vfile->entry.lockops->get(&vfile->entry);
263  		if (ret)
264  			break;
265  		if (vfile->tag->rev != revtag)
266  			goto redo;
267  		ret = ops->next(it, data);
268  		vfile->entry.lockops->put(&vfile->entry);
269  		if (ret <= 0)
270  			break;
271  		if (ret != VFILE_SEQ_SKIP) {
272  			data += vfile->datasz;
273  			it->nrdata++;
274  		}
275  	}
276  
277  	if (ret < 0) {
278  		seq_release(inode, file);
279  	fail:
280  		if (it->databuf)
281  			it->endfn(it, it->databuf);
282  		kfree(it);
283  		return ret;
284  	}
285  
286  finish:
287  	seq = file->private_data;
288  	it->seq = seq;
289  	seq->private = it;
290  	xnvfile_nref(vfile)++;
291  
292  	return 0;
293  }
294  
295  static int vfile_snapshot_release(struct inode *inode, struct file *file)
296  {
297  	struct seq_file *seq = file->private_data;
298  	struct xnvfile_snapshot_iterator *it;
299  
300  	if (seq) {
301  		it = seq->private;
302  		if (it) {
303  			--xnvfile_nref(it->vfile);
304  			RTAI_BUGON(NUCLEUS, it->vfile->entry.refcnt < 0);
305  			if (it->databuf)
306  				it->endfn(it, it->databuf);
307  			kfree(it);
308  		}
309  
310  		return seq_release(inode, file);
311  	}
312  
313  	return 0;
314  }
315  
316  ssize_t vfile_snapshot_write(struct file *file, const char __user *buf,
317  			     size_t size, loff_t *ppos)
318  {
319  	struct xnvfile_snapshot *vfile = PDE_DATA(wrap_f_inode(file));
320  	struct xnvfile_input input;
321  	ssize_t ret;
322  
323  	if (vfile->entry.lockops) {
324  		ret = vfile->entry.lockops->get(&vfile->entry);
325  		if (ret)
326  			return ret;
327  	}
328  
329  	input.u_buf = buf;
330  	input.size = size;
331  	input.vfile = &vfile->entry;
332  
333  	ret = vfile->ops->store(&input);
334  
335  	if (vfile->entry.lockops)
336  		vfile->entry.lockops->put(&vfile->entry);
337  
338  	return ret;
339  }
340  
341  static struct file_operations vfile_snapshot_fops = {
342  	.owner = THIS_MODULE,
343  	.open = vfile_snapshot_open,
344  	.read = seq_read,
345  	.write = vfile_snapshot_write,
346  	.llseek = seq_lseek,
347  	.release = vfile_snapshot_release,
348  };
349  
350  /**
351   * @fn int xnvfile_init_snapshot(const char *name, struct xnvfile_snapshot *vfile, struct xnvfile_directory *parent)
352   * @brief Initialize a snapshot-driven vfile.
353   *
354   * @param name The name which should appear in the pseudo-filesystem,
355   * identifying the vfile entry.
356   *
357   * @param vfile A pointer to a vfile descriptor to initialize
358   * from. The following fields in this structure should be filled in
359   * prior to call this routine:
360   *
361   * - .privsz is the size (in bytes) of the private data area to be
362   * reserved in the @ref snapshot_iterator "vfile iterator". A NULL
363   * value indicates that no private area should be reserved.
364   *
365   * - .datasz is the size (in bytes) of a single record to be collected
366   * by the @ref snapshot_next "next() handler" from the @ref
367   * snapshot_ops "operation descriptor".
368   *
369   * - .tag is a pointer to a mandatory vfile revision tag structure
370   * (struct xnvfile_rev_tag). This tag will be monitored for changes by
371   * the vfile core while collecting data to output, so that any update
372   * detected will cause the current snapshot data to be dropped, and
373   * the collection to restart from the beginning. To this end, any
374   * change to the data which may be part of the collected records,
375   * should also invoke xnvfile_touch() on the associated tag.
376   *
377   * - entry.lockops is a pointer to a @ref vfile_lockops "locking
378   * descriptor", defining the lock and unlock operations for the
379   * vfile. This pointer may be left to NULL, in which case the
380   * operations on the nucleus lock (i.e. nklock) will be used
381   * internally around calls to data collection handlers (see @ref
382   * snapshot_ops "operation descriptor").
383   *
384   * - .ops is a pointer to an @ref snapshot_ops "operation descriptor".
385   *
386   * @param parent A pointer to a virtual directory descriptor; the
387   * vfile entry will be created into this directory. If NULL, the /proc
388   * root directory will be used. /proc/rtai is mapped on the
389   * globally available @a nkvfroot vdir.
390   *
391   * @return 0 is returned on success. Otherwise:
392   *
393   * - -ENOMEM is returned if the virtual file entry cannot be created
394   * in the /proc hierarchy.
395   */
396  int xnvfile_init_snapshot(const char *name,
397  			  struct xnvfile_snapshot *vfile,
398  			  struct xnvfile_directory *parent)
399  {
400  	struct proc_dir_entry *ppde, *pde;
401  	int mode;
402  
403  	RTAI_BUGON(NUCLEUS, vfile->tag == NULL);
404  
405  	if (vfile->entry.lockops == NULL)
406  		/* Defaults to nucleus lock */
407  		vfile->entry.lockops = &xnvfile_nucleus_lock.ops;
408  
409  	if (parent == NULL)
410  		parent = &sysroot;
411  
412  	mode = vfile->ops->store ? 0644 : 0444;
413  	ppde = parent->entry.pde;
414  	pde = proc_create_data(name, mode, ppde, &vfile_snapshot_fops, vfile);
415  	if (pde == NULL)
416  		return -ENOMEM;
417  
418  	wrap_proc_dir_entry_owner(pde);
419  
420  	vfile->entry.pde = pde;
421  
422  	return 0;
423  }
424  EXPORT_SYMBOL_GPL(xnvfile_init_snapshot);
425  
426  static void *vfile_regular_start(struct seq_file *seq, loff_t *offp)
427  {
428  	struct xnvfile_regular_iterator *it = seq->private;
429  	struct xnvfile_regular *vfile = it->vfile;
430  	int ret;
431  
432  	it->pos = *offp;
433  
434  	if (vfile->entry.lockops) {
435  		ret = vfile->entry.lockops->get(&vfile->entry);
436  		if (ret)
437  			return ERR_PTR(ret);
438  	}
439  
440  	/*
441  	 * If we have no begin() op, then we allow a single call only
442  	 * to ->show(), by returning the start token once. Otherwise,
443  	 * we are done.
444  	 */
445  	if (vfile->ops->begin == NULL)
446  		return it->pos > 0 ? NULL : SEQ_START_TOKEN;
447  
448  	return vfile->ops->begin(it);
449  }
450  
451  static void *vfile_regular_next(struct seq_file *seq, void *v, loff_t *offp)
452  {
453  	struct xnvfile_regular_iterator *it = seq->private;
454  	struct xnvfile_regular *vfile = it->vfile;
455  	void *data;
456  
457  	if (vfile->ops->next == NULL)
458  		return NULL;
459  
460  	it->pos = *offp + 1;
461  
462  	data = vfile->ops->next(it);
463  	if (data == NULL)
464  		return NULL;
465  
466  	*offp = it->pos;
467  
468  	return data;
469  }
470  
471  static void vfile_regular_stop(struct seq_file *seq, void *v)
472  {
473  	struct xnvfile_regular_iterator *it = seq->private;
474  	struct xnvfile_regular *vfile = it->vfile;
475  
476  	if (vfile->entry.lockops)
477  		vfile->entry.lockops->put(&vfile->entry);
478  
479  	if (vfile->ops->end)
480  		vfile->ops->end(it);
481  }
482  
483  static int vfile_regular_show(struct seq_file *seq, void *v)
484  {
485  	struct xnvfile_regular_iterator *it = seq->private;
486  	struct xnvfile_regular *vfile = it->vfile;
487  	void *data = v == SEQ_START_TOKEN ? NULL : v;
488  	int ret;
489  
490  	ret = vfile->ops->show(it, data);
491  
492  	return ret == VFILE_SEQ_SKIP ? SEQ_SKIP : ret;
493  }
494  
495  static struct seq_operations vfile_regular_ops = {
496  	.start = vfile_regular_start,
497  	.next = vfile_regular_next,
498  	.stop = vfile_regular_stop,
499  	.show = vfile_regular_show
500  };
501  
502  static int vfile_regular_open(struct inode *inode, struct file *file)
503  {
504  	struct xnvfile_regular *vfile = PDE_DATA(inode);
505  	struct xnvfile_regular_ops *ops = vfile->ops;
506  	struct xnvfile_regular_iterator *it;
507  	struct seq_file *seq;
508  	int ret;
509  
510  	if ((file->f_flags & O_EXCL) != 0 && xnvfile_nref(vfile) > 0)
511  		return -EBUSY;
512  
513  	if ((file->f_mode & FMODE_WRITE) != 0 && ops->store == NULL)
514  		return -EACCES;
515  
516  	if ((file->f_mode & FMODE_READ) == 0) {
517  		file->private_data = NULL;
518  		return 0;
519  	}
520  
521  	it = kzalloc(sizeof(*it) + vfile->privsz, GFP_KERNEL);
522  	if (it == NULL)
523  		return -ENOMEM;
524  
525  	it->vfile = vfile;
526  	it->pos = -1;
527  	xnvfile_file(vfile) = file;
528  
529  	if (ops->rewind) {
530  		ret = ops->rewind(it);
531  		if (ret) {
532  		fail:
533  			kfree(it);
534  			return ret;
535  		}
536  	}
537  
538  	ret = seq_open(file, &vfile_regular_ops);
539  	if (ret)
540  		goto fail;
541  
542  	seq = file->private_data;
543  	it->seq = seq;
544  	seq->private = it;
545  	xnvfile_nref(vfile)++;
546  
547  	return 0;
548  }
549  
550  static int vfile_regular_release(struct inode *inode, struct file *file)
551  {
552  	struct seq_file *seq = file->private_data;
553  	struct xnvfile_regular_iterator *it;
554  
555  	if (seq) {
556  		it = seq->private;
557  		if (it) {
558  			--xnvfile_nref(it->vfile);
559  			RTAI_BUGON(NUCLEUS, xnvfile_nref(it->vfile) < 0);
560  			kfree(it);
561  		}
562  
563  		return seq_release(inode, file);
564  	}
565  
566  	return 0;
567  }
568  
569  ssize_t vfile_regular_write(struct file *file, const char __user *buf,
570  			    size_t size, loff_t *ppos)
571  {
572  	struct xnvfile_regular *vfile = PDE_DATA(wrap_f_inode(file));
573  	struct xnvfile_input input;
574  	ssize_t ret;
575  
576  	if (vfile->entry.lockops) {
577  		ret = vfile->entry.lockops->get(&vfile->entry);
578  		if (ret)
579  			return ret;
580  	}
581  
582  	input.u_buf = buf;
583  	input.size = size;
584  	input.vfile = &vfile->entry;
585  
586  	ret = vfile->ops->store(&input);
587  
588  	if (vfile->entry.lockops)
589  		vfile->entry.lockops->put(&vfile->entry);
590  
591  	return ret;
592  }
593  
594  static struct file_operations vfile_regular_fops = {
595  	.owner = THIS_MODULE,
596  	.open = vfile_regular_open,
597  	.read = seq_read,
598  	.write = vfile_regular_write,
599  	.llseek = seq_lseek,
600  	.release = vfile_regular_release,
601  };
602  
603  /**
604   * @fn int xnvfile_init_regular(const char *name, struct xnvfile_regular *vfile, struct xnvfile_directory *parent)
605   * @brief Initialize a regular vfile.
606   *
607   * @param name The name which should appear in the pseudo-filesystem,
608   * identifying the vfile entry.
609   *
610   * @param vfile A pointer to a vfile descriptor to initialize
611   * from. The following fields in this structure should be filled in
612   * prior to call this routine:
613   *
614   * - .privsz is the size (in bytes) of the private data area to be
615   * reserved in the @ref regular_iterator "vfile iterator". A NULL
616   * value indicates that no private area should be reserved.
617   *
618   * - entry.lockops is a pointer to a @ref vfile_lockops "locking
619   * descriptor", defining the lock and unlock operations for the
620   * vfile. This pointer may be left to NULL, in which case no
621   * locking will be applied.
622   *
623   * - .ops is a pointer to an @ref regular_ops "operation descriptor".
624   *
625   * @param parent A pointer to a virtual directory descriptor; the
626   * vfile entry will be created into this directory. If NULL, the /proc
627   * root directory will be used. /proc/rtai is mapped on the
628   * globally available @a nkvfroot vdir.
629   *
630   * @return 0 is returned on success. Otherwise:
631   *
632   * - -ENOMEM is returned if the virtual file entry cannot be created
633   * in the /proc hierarchy.
634   */
635  int xnvfile_init_regular(const char *name,
636  			 struct xnvfile_regular *vfile,
637  			 struct xnvfile_directory *parent)
638  {
639  	struct proc_dir_entry *ppde, *pde;
640  	int mode;
641  
642  	if (parent == NULL)
643  		parent = &sysroot;
644  
645  	mode = vfile->ops->store ? 0644 : 0444;
646  	ppde = parent->entry.pde;
647  	pde = proc_create_data(name, mode, ppde, &vfile_regular_fops, vfile);
648  	if (pde == NULL)
649  		return -ENOMEM;
650  
651  	wrap_proc_dir_entry_owner(pde);
652  
653  	vfile->entry.pde = pde;
654  
655  	return 0;
656  }
657  EXPORT_SYMBOL_GPL(xnvfile_init_regular);
658  
659  /**
660   * @fn int xnvfile_init_dir(const char *name, struct xnvfile_directory *vdir, struct xnvfile_directory *parent)
661   * @brief Initialize a virtual directory entry.
662   *
663   * @param name The name which should appear in the pseudo-filesystem,
664   * identifying the vdir entry.
665   *
666   * @param vdir A pointer to the virtual directory descriptor to
667   * initialize.
668   *
669   * @param parent A pointer to a virtual directory descriptor standing
670   * for the parent directory of the new vdir.  If NULL, the /proc root
671   * directory will be used. /proc/rtai is mapped on the globally
672   * available @a nkvfroot vdir.
673   *
674   * @return 0 is returned on success. Otherwise:
675   *
676   * - -ENOMEM is returned if the virtual directory entry cannot be
677   * created in the /proc hierarchy.
678   */
679  int xnvfile_init_dir(const char *name,
680  		     struct xnvfile_directory *vdir,
681  		     struct xnvfile_directory *parent)
682  {
683  	struct proc_dir_entry *ppde, *pde;
684  
685  	if (parent == NULL)
686  		parent = &sysroot;
687  
688  	ppde = parent->entry.pde;
689  	pde = proc_mkdir(name, ppde);
690  	if (pde == NULL)
691  		return -ENOMEM;
692  
693  	vdir->entry.pde = pde;
694  	vdir->entry.lockops = NULL;
695  	vdir->entry.private = NULL;
696  	wrap_proc_dir_entry_owner(pde);
697  
698  	return 0;
699  }
700  EXPORT_SYMBOL_GPL(xnvfile_init_dir);
701  
702  /**
703   * @fn int xnvfile_init_link(const char *from, const char *to, struct xnvfile_link *vlink, struct xnvfile_directory *parent)
704   * @brief Initialize a virtual link entry.
705   *
706   * @param from The name which should appear in the pseudo-filesystem,
707   * identifying the vlink entry.
708   *
709   * @param to The target file name which should be referred to
710   * symbolically by @a name.
711   *
712   * @param vlink A pointer to the virtual link descriptor to
713   * initialize.
714   *
715   * @param parent A pointer to a virtual directory descriptor standing
716   * for the parent directory of the new vlink. If NULL, the /proc root
717   * directory will be used. /proc/rtai is mapped on the globally
718   * available @a nkvfroot vdir.
719   *
720   * @return 0 is returned on success. Otherwise:
721   *
722   * - -ENOMEM is returned if the virtual link entry cannot be created
723   * in the /proc hierarchy.
724   */
725  int xnvfile_init_link(const char *from,
726  		      const char *to,
727  		      struct xnvfile_link *vlink,
728  		      struct xnvfile_directory *parent)
729  {
730  	struct proc_dir_entry *ppde, *pde;
731  
732  	if (parent == NULL)
733  		parent = &sysroot;
734  
735  	ppde = parent->entry.pde;
736  	pde = proc_symlink(from, ppde, to);
737  	if (pde == NULL)
738  		return -ENOMEM;
739  
740  	vlink->entry.pde = pde;
741  	vlink->entry.lockops = NULL;
742  	vlink->entry.private = NULL;
743  	wrap_proc_dir_entry_owner(pde);
744  
745  	return 0;
746  }
747  EXPORT_SYMBOL_GPL(xnvfile_init_link);
748  
749  /**
750   * @fn void xnvfile_destroy(struct xnvfile *vfile)
751   * @brief Removes a virtual file entry.
752   *
753   * @param vfile A pointer to the virtual file descriptor to
754   * remove.
755   */
756  void xnvfile_destroy(struct xnvfile *vfile)
757  {
758  	proc_remove(vfile->pde);
759  }
760  EXPORT_SYMBOL_GPL(xnvfile_destroy);
761  
762  /**
763   * @fn ssize_t xnvfile_get_blob(struct xnvfile_input *input, void *data, size_t size)
764   * @brief Read in a data bulk written to the vfile.
765   *
766   * When writing to a vfile, the associated store() handler from the
767   * @ref snapshot_store "snapshot-driven vfile" or @ref regular_store
768   * "regular vfile" is called, with a single argument describing the
769   * input data. xnvfile_get_blob() retrieves this data as an untyped
770   * binary blob, and copies it back to the caller's buffer.
771   *
772   * @param input A pointer to the input descriptor passed to the
773   * store() handler.
774   *
775   * @param data The address of the destination buffer to copy the input
776   * data to.
777   *
778   * @param size The maximum number of bytes to copy to the destination
779   * buffer. If @a size is larger than the actual data size, the input
780   * is truncated to @a size.
781   *
782   * @return The number of bytes read and copied to the destination
783   * buffer upon success. Otherwise, a negative error code is returned:
784   *
785   * - -EFAULT indicates an invalid source buffer address.
786   */
787  ssize_t xnvfile_get_blob(struct xnvfile_input *input,
788  			 void *data, size_t size)
789  {
790  	ssize_t nbytes = input->size;
791  
792  	if (nbytes > size)
793  		nbytes = size;
794  
795  	if (nbytes > 0 && copy_from_user(data, input->u_buf, nbytes))
796  		return -EFAULT;
797  
798  	return nbytes;
799  }
800  EXPORT_SYMBOL_GPL(xnvfile_get_blob);
801  
802  /**
803   * @fn ssize_t xnvfile_get_string(struct xnvfile_input *input, char *s, size_t maxlen)
804   * @brief Read in a C-string written to the vfile.
805   *
806   * When writing to a vfile, the associated store() handler from the
807   * @ref snapshot_store "snapshot-driven vfile" or @ref regular_store
808   * "regular vfile" is called, with a single argument describing the
809   * input data. xnvfile_get_string() retrieves this data as a
810   * null-terminated character string, and copies it back to the
811   * caller's buffer.
812   *
813   * @param input A pointer to the input descriptor passed to the
814   * store() handler.
815   *
816   * @param s The address of the destination string buffer to copy the
817   * input data to.
818   *
819   * @param maxlen The maximum number of bytes to copy to the
820   * destination buffer, including the ending null character. If @a
821   * maxlen is larger than the actual string length, the input is
822   * truncated to @a maxlen.
823   *
824   * @return The number of characters read and copied to the destination
825   * buffer upon success. Otherwise, a negative error code is returned:
826   *
827   * - -EFAULT indicates an invalid source buffer address.
828   */
829  ssize_t xnvfile_get_string(struct xnvfile_input *input,
830  			   char *s, size_t maxlen)
831  {
832  	ssize_t nbytes;
833  
834  	if (maxlen < 1)
835  		return -EINVAL;
836  
837  	nbytes = xnvfile_get_blob(input, s, maxlen - 1);
838  	if (nbytes < 0)
839  		return nbytes;
840  
841  	if (nbytes > 0 && s[nbytes - 1] == '\n')
842  		nbytes--;
843  
844  	s[nbytes] = '\0';
845  
846  	return nbytes;
847  }
848  EXPORT_SYMBOL_GPL(xnvfile_get_string);
849  
850  /**
851   * @fn ssize_t xnvfile_get_integer(struct xnvfile_input *input, long *valp)
852   * @brief Evaluate the string written to the vfile as a long integer.
853   *
854   * When writing to a vfile, the associated store() handler from the
855   * @ref snapshot_store "snapshot-driven vfile" or @ref regular_store
856   * "regular vfile" is called, with a single argument describing the
857   * input data. xnvfile_get_integer() retrieves and interprets this
858   * data as a long integer, and copies the resulting value back to @a
859   * valp.
860   *
861   * The long integer can be expressed in decimal, octal or hexadecimal
862   * bases depending on the prefix found.
863   *
864   * @param input A pointer to the input descriptor passed to the
865   * store() handler.
866   *
867   * @param valp The address of a long integer variable to receive the
868   * value.
869   *
870   * @return The number of characters read while evaluating the input as
871   * a long integer upon success. Otherwise, a negative error code is
872   * returned:
873   *
874   * - -EINVAL indicates a parse error on the input stream; the written
875   * text cannot be evaluated as a long integer.
876   *
877   * - -EFAULT indicates an invalid source buffer address.
878   */
879  ssize_t xnvfile_get_integer(struct xnvfile_input *input, long *valp)
880  {
881  	char *end, buf[32];
882  	ssize_t nbytes;
883  	long val;
884  
885  	nbytes = xnvfile_get_blob(input, buf, sizeof(buf) - 1);
886  	if (nbytes < 0)
887  		return nbytes;
888  
889  	if (nbytes == 0)
890  		return -EINVAL;
891  
892  	buf[nbytes] = '\0';
893  	val = simple_strtol(buf, &end, 0);
894  
895  	if (*end != '\0' && !isspace(*end))
896  		return -EINVAL;
897  
898  	*valp = val;
899  
900  	return nbytes;
901  }
902  EXPORT_SYMBOL_GPL(xnvfile_get_integer);
903  
904  int __vfile_hostlock_get(struct xnvfile *vfile)
905  {
906  	struct xnvfile_hostlock_class *lc;
907  
908  	lc = container_of(vfile->lockops, struct xnvfile_hostlock_class, ops);
909  	return down_interruptible(&lc->sem) ? -ERESTARTSYS : 0;
910  }
911  EXPORT_SYMBOL_GPL(__vfile_hostlock_get);
912  
913  void __vfile_hostlock_put(struct xnvfile *vfile)
914  {
915  	struct xnvfile_hostlock_class *lc;
916  
917  	lc = container_of(vfile->lockops, struct xnvfile_hostlock_class, ops);
918  	up(&lc->sem);
919  }
920  EXPORT_SYMBOL_GPL(__vfile_hostlock_put);
921  
922  static int __vfile_nklock_get(struct xnvfile *vfile)
923  {
924  	struct xnvfile_nklock_class *lc;
925  
926  	lc = container_of(vfile->lockops, struct xnvfile_nklock_class, ops);
927  	xnlock_get_irqsave(&nklock, lc->s);
928  
929  	return 0;
930  }
931  
932  static void __vfile_nklock_put(struct xnvfile *vfile)
933  {
934  	struct xnvfile_nklock_class *lc;
935  
936  	lc = container_of(vfile->lockops, struct xnvfile_nklock_class, ops);
937  	xnlock_put_irqrestore(&nklock, lc->s);
938  }
939  
940  struct xnvfile_nklock_class xnvfile_nucleus_lock = {
941  	.ops = {
942  		.get = __vfile_nklock_get,
943  		.put = __vfile_nklock_put,
944  	},
945  };
946  
947  int __init xnvfile_init_root(void)
948  {
949  	struct xnvfile_directory *vdir = &nkvfroot;
950  	struct proc_dir_entry *pde;
951  
952  	pde = proc_mkdir("rtai", NULL);
953  	if (pde == NULL)
954  		return -ENOMEM;
955  
956  	vdir->entry.pde = pde;
957  	vdir->entry.lockops = NULL;
958  	vdir->entry.private = NULL;
959  	wrap_proc_dir_entry_owner(pde);
960  
961  	return 0;
962  }
963  
964  void xnvfile_destroy_root(void)
965  {
966  	nkvfroot.entry.pde = NULL;
967  	remove_proc_entry("rtai", NULL);
968  }
969  
970  /*@}*/