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 /*@}*/