1/* 2 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 * Licensed under the GPL 4 */ 5 6#include <linux/ctype.h> 7#include <linux/dcache.h> 8#include <linux/file.h> 9#include <linux/fs.h> 10#include <linux/init.h> 11#include <linux/kernel.h> 12#include <linux/list.h> 13#include <linux/module.h> 14#include <linux/mount.h> 15#include <linux/slab.h> 16#include <linux/statfs.h> 17#include <linux/types.h> 18#include <linux/pid_namespace.h> 19#include <linux/namei.h> 20#include <asm/uaccess.h> 21#include <os.h> 22 23static struct inode *get_inode(struct super_block *, struct dentry *); 24 25struct hppfs_data { 26 struct list_head list; 27 char contents[PAGE_SIZE - sizeof(struct list_head)]; 28}; 29 30struct hppfs_private { 31 struct file *proc_file; 32 int host_fd; 33 loff_t len; 34 struct hppfs_data *contents; 35}; 36 37struct hppfs_inode_info { 38 struct dentry *proc_dentry; 39 struct inode vfs_inode; 40}; 41 42static inline struct hppfs_inode_info *HPPFS_I(struct inode *inode) 43{ 44 return container_of(inode, struct hppfs_inode_info, vfs_inode); 45} 46 47#define HPPFS_SUPER_MAGIC 0xb00000ee 48 49static const struct super_operations hppfs_sbops; 50 51static int is_pid(struct dentry *dentry) 52{ 53 struct super_block *sb; 54 int i; 55 56 sb = dentry->d_sb; 57 if (dentry->d_parent != sb->s_root) 58 return 0; 59 60 for (i = 0; i < dentry->d_name.len; i++) { 61 if (!isdigit(dentry->d_name.name[i])) 62 return 0; 63 } 64 return 1; 65} 66 67static char *dentry_name(struct dentry *dentry, int extra) 68{ 69 struct dentry *parent; 70 char *root, *name; 71 const char *seg_name; 72 int len, seg_len, root_len; 73 74 len = 0; 75 parent = dentry; 76 while (parent->d_parent != parent) { 77 if (is_pid(parent)) 78 len += strlen("pid") + 1; 79 else len += parent->d_name.len + 1; 80 parent = parent->d_parent; 81 } 82 83 root = "proc"; 84 root_len = strlen(root); 85 len += root_len; 86 name = kmalloc(len + extra + 1, GFP_KERNEL); 87 if (name == NULL) 88 return NULL; 89 90 name[len] = '\0'; 91 parent = dentry; 92 while (parent->d_parent != parent) { 93 if (is_pid(parent)) { 94 seg_name = "pid"; 95 seg_len = strlen(seg_name); 96 } 97 else { 98 seg_name = parent->d_name.name; 99 seg_len = parent->d_name.len; 100 } 101 102 len -= seg_len + 1; 103 name[len] = '/'; 104 memcpy(&name[len + 1], seg_name, seg_len); 105 parent = parent->d_parent; 106 } 107 memcpy(name, root, root_len); 108 return name; 109} 110 111static int file_removed(struct dentry *dentry, const char *file) 112{ 113 char *host_file; 114 int extra, fd; 115 116 extra = 0; 117 if (file != NULL) 118 extra += strlen(file) + 1; 119 120 host_file = dentry_name(dentry, extra + strlen("/remove")); 121 if (host_file == NULL) { 122 printk(KERN_ERR "file_removed : allocation failed\n"); 123 return -ENOMEM; 124 } 125 126 if (file != NULL) { 127 strcat(host_file, "/"); 128 strcat(host_file, file); 129 } 130 strcat(host_file, "/remove"); 131 132 fd = os_open_file(host_file, of_read(OPENFLAGS()), 0); 133 kfree(host_file); 134 if (fd > 0) { 135 os_close_file(fd); 136 return 1; 137 } 138 return 0; 139} 140 141static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, 142 unsigned int flags) 143{ 144 struct dentry *proc_dentry, *parent; 145 struct qstr *name = &dentry->d_name; 146 struct inode *inode; 147 int err, deleted; 148 149 deleted = file_removed(dentry, NULL); 150 if (deleted < 0) 151 return ERR_PTR(deleted); 152 else if (deleted) 153 return ERR_PTR(-ENOENT); 154 155 parent = HPPFS_I(ino)->proc_dentry; 156 mutex_lock(&d_inode(parent)->i_mutex); 157 proc_dentry = lookup_one_len(name->name, parent, name->len); 158 mutex_unlock(&d_inode(parent)->i_mutex); 159 160 if (IS_ERR(proc_dentry)) 161 return proc_dentry; 162 163 err = -ENOMEM; 164 inode = get_inode(ino->i_sb, proc_dentry); 165 if (!inode) 166 goto out; 167 168 d_add(dentry, inode); 169 return NULL; 170 171 out: 172 return ERR_PTR(err); 173} 174 175static const struct inode_operations hppfs_file_iops = { 176}; 177 178static ssize_t read_proc(struct file *file, char __user *buf, ssize_t count, 179 loff_t *ppos, int is_user) 180{ 181 ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); 182 ssize_t n; 183 184 read = file_inode(file)->i_fop->read; 185 186 if (!is_user) 187 set_fs(KERNEL_DS); 188 189 n = (*read)(file, buf, count, &file->f_pos); 190 191 if (!is_user) 192 set_fs(USER_DS); 193 194 if (ppos) 195 *ppos = file->f_pos; 196 return n; 197} 198 199static ssize_t hppfs_read_file(int fd, char __user *buf, ssize_t count) 200{ 201 ssize_t n; 202 int cur, err; 203 char *new_buf; 204 205 n = -ENOMEM; 206 new_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 207 if (new_buf == NULL) { 208 printk(KERN_ERR "hppfs_read_file : kmalloc failed\n"); 209 goto out; 210 } 211 n = 0; 212 while (count > 0) { 213 cur = min_t(ssize_t, count, PAGE_SIZE); 214 err = os_read_file(fd, new_buf, cur); 215 if (err < 0) { 216 printk(KERN_ERR "hppfs_read : read failed, " 217 "errno = %d\n", err); 218 n = err; 219 goto out_free; 220 } else if (err == 0) 221 break; 222 223 if (copy_to_user(buf, new_buf, err)) { 224 n = -EFAULT; 225 goto out_free; 226 } 227 n += err; 228 count -= err; 229 } 230 out_free: 231 kfree(new_buf); 232 out: 233 return n; 234} 235 236static ssize_t hppfs_read(struct file *file, char __user *buf, size_t count, 237 loff_t *ppos) 238{ 239 struct hppfs_private *hppfs = file->private_data; 240 struct hppfs_data *data; 241 loff_t off; 242 int err; 243 244 if (hppfs->contents != NULL) { 245 int rem; 246 247 if (*ppos >= hppfs->len) 248 return 0; 249 250 data = hppfs->contents; 251 off = *ppos; 252 while (off >= sizeof(data->contents)) { 253 data = list_entry(data->list.next, struct hppfs_data, 254 list); 255 off -= sizeof(data->contents); 256 } 257 258 if (off + count > hppfs->len) 259 count = hppfs->len - off; 260 rem = copy_to_user(buf, &data->contents[off], count); 261 *ppos += count - rem; 262 if (rem > 0) 263 return -EFAULT; 264 } else if (hppfs->host_fd != -1) { 265 err = os_seek_file(hppfs->host_fd, *ppos); 266 if (err) { 267 printk(KERN_ERR "hppfs_read : seek failed, " 268 "errno = %d\n", err); 269 return err; 270 } 271 err = hppfs_read_file(hppfs->host_fd, buf, count); 272 if (err < 0) { 273 printk(KERN_ERR "hppfs_read: read failed: %d\n", err); 274 return err; 275 } 276 count = err; 277 if (count > 0) 278 *ppos += count; 279 } 280 else count = read_proc(hppfs->proc_file, buf, count, ppos, 1); 281 282 return count; 283} 284 285static ssize_t hppfs_write(struct file *file, const char __user *buf, 286 size_t len, loff_t *ppos) 287{ 288 struct hppfs_private *data = file->private_data; 289 struct file *proc_file = data->proc_file; 290 ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); 291 292 write = file_inode(proc_file)->i_fop->write; 293 return (*write)(proc_file, buf, len, ppos); 294} 295 296static int open_host_sock(char *host_file, int *filter_out) 297{ 298 char *end; 299 int fd; 300 301 end = &host_file[strlen(host_file)]; 302 strcpy(end, "/rw"); 303 *filter_out = 1; 304 fd = os_connect_socket(host_file); 305 if (fd > 0) 306 return fd; 307 308 strcpy(end, "/r"); 309 *filter_out = 0; 310 fd = os_connect_socket(host_file); 311 return fd; 312} 313 314static void free_contents(struct hppfs_data *head) 315{ 316 struct hppfs_data *data; 317 struct list_head *ele, *next; 318 319 if (head == NULL) 320 return; 321 322 list_for_each_safe(ele, next, &head->list) { 323 data = list_entry(ele, struct hppfs_data, list); 324 kfree(data); 325 } 326 kfree(head); 327} 328 329static struct hppfs_data *hppfs_get_data(int fd, int filter, 330 struct file *proc_file, 331 struct file *hppfs_file, 332 loff_t *size_out) 333{ 334 struct hppfs_data *data, *new, *head; 335 int n, err; 336 337 err = -ENOMEM; 338 data = kmalloc(sizeof(*data), GFP_KERNEL); 339 if (data == NULL) { 340 printk(KERN_ERR "hppfs_get_data : head allocation failed\n"); 341 goto failed; 342 } 343 344 INIT_LIST_HEAD(&data->list); 345 346 head = data; 347 *size_out = 0; 348 349 if (filter) { 350 while ((n = read_proc(proc_file, data->contents, 351 sizeof(data->contents), NULL, 0)) > 0) 352 os_write_file(fd, data->contents, n); 353 err = os_shutdown_socket(fd, 0, 1); 354 if (err) { 355 printk(KERN_ERR "hppfs_get_data : failed to shut down " 356 "socket\n"); 357 goto failed_free; 358 } 359 } 360 while (1) { 361 n = os_read_file(fd, data->contents, sizeof(data->contents)); 362 if (n < 0) { 363 err = n; 364 printk(KERN_ERR "hppfs_get_data : read failed, " 365 "errno = %d\n", err); 366 goto failed_free; 367 } else if (n == 0) 368 break; 369 370 *size_out += n; 371 372 if (n < sizeof(data->contents)) 373 break; 374 375 new = kmalloc(sizeof(*data), GFP_KERNEL); 376 if (new == 0) { 377 printk(KERN_ERR "hppfs_get_data : data allocation " 378 "failed\n"); 379 err = -ENOMEM; 380 goto failed_free; 381 } 382 383 INIT_LIST_HEAD(&new->list); 384 list_add(&new->list, &data->list); 385 data = new; 386 } 387 return head; 388 389 failed_free: 390 free_contents(head); 391 failed: 392 return ERR_PTR(err); 393} 394 395static struct hppfs_private *hppfs_data(void) 396{ 397 struct hppfs_private *data; 398 399 data = kmalloc(sizeof(*data), GFP_KERNEL); 400 if (data == NULL) 401 return data; 402 403 *data = ((struct hppfs_private ) { .host_fd = -1, 404 .len = -1, 405 .contents = NULL } ); 406 return data; 407} 408 409static int file_mode(int fmode) 410{ 411 if (fmode == (FMODE_READ | FMODE_WRITE)) 412 return O_RDWR; 413 if (fmode == FMODE_READ) 414 return O_RDONLY; 415 if (fmode == FMODE_WRITE) 416 return O_WRONLY; 417 return 0; 418} 419 420static int hppfs_open(struct inode *inode, struct file *file) 421{ 422 const struct cred *cred = file->f_cred; 423 struct hppfs_private *data; 424 struct path path; 425 char *host_file; 426 int err, fd, type, filter; 427 428 err = -ENOMEM; 429 data = hppfs_data(); 430 if (data == NULL) 431 goto out; 432 433 host_file = dentry_name(file->f_path.dentry, strlen("/rw")); 434 if (host_file == NULL) 435 goto out_free2; 436 437 path.mnt = inode->i_sb->s_fs_info; 438 path.dentry = HPPFS_I(inode)->proc_dentry; 439 440 data->proc_file = dentry_open(&path, file_mode(file->f_mode), cred); 441 err = PTR_ERR(data->proc_file); 442 if (IS_ERR(data->proc_file)) 443 goto out_free1; 444 445 type = os_file_type(host_file); 446 if (type == OS_TYPE_FILE) { 447 fd = os_open_file(host_file, of_read(OPENFLAGS()), 0); 448 if (fd >= 0) 449 data->host_fd = fd; 450 else 451 printk(KERN_ERR "hppfs_open : failed to open '%s', " 452 "errno = %d\n", host_file, -fd); 453 454 data->contents = NULL; 455 } else if (type == OS_TYPE_DIR) { 456 fd = open_host_sock(host_file, &filter); 457 if (fd > 0) { 458 data->contents = hppfs_get_data(fd, filter, 459 data->proc_file, 460 file, &data->len); 461 if (!IS_ERR(data->contents)) 462 data->host_fd = fd; 463 } else 464 printk(KERN_ERR "hppfs_open : failed to open a socket " 465 "in '%s', errno = %d\n", host_file, -fd); 466 } 467 kfree(host_file); 468 469 file->private_data = data; 470 return 0; 471 472 out_free1: 473 kfree(host_file); 474 out_free2: 475 free_contents(data->contents); 476 kfree(data); 477 out: 478 return err; 479} 480 481static int hppfs_dir_open(struct inode *inode, struct file *file) 482{ 483 const struct cred *cred = file->f_cred; 484 struct hppfs_private *data; 485 struct path path; 486 int err; 487 488 err = -ENOMEM; 489 data = hppfs_data(); 490 if (data == NULL) 491 goto out; 492 493 path.mnt = inode->i_sb->s_fs_info; 494 path.dentry = HPPFS_I(inode)->proc_dentry; 495 data->proc_file = dentry_open(&path, file_mode(file->f_mode), cred); 496 err = PTR_ERR(data->proc_file); 497 if (IS_ERR(data->proc_file)) 498 goto out_free; 499 500 file->private_data = data; 501 return 0; 502 503 out_free: 504 kfree(data); 505 out: 506 return err; 507} 508 509static loff_t hppfs_llseek(struct file *file, loff_t off, int where) 510{ 511 struct hppfs_private *data = file->private_data; 512 struct file *proc_file = data->proc_file; 513 loff_t (*llseek)(struct file *, loff_t, int); 514 loff_t ret; 515 516 llseek = file_inode(proc_file)->i_fop->llseek; 517 if (llseek != NULL) { 518 ret = (*llseek)(proc_file, off, where); 519 if (ret < 0) 520 return ret; 521 } 522 523 return default_llseek(file, off, where); 524} 525 526static int hppfs_release(struct inode *inode, struct file *file) 527{ 528 struct hppfs_private *data = file->private_data; 529 struct file *proc_file = data->proc_file; 530 if (proc_file) 531 fput(proc_file); 532 kfree(data); 533 return 0; 534} 535 536static const struct file_operations hppfs_file_fops = { 537 .owner = NULL, 538 .llseek = hppfs_llseek, 539 .read = hppfs_read, 540 .write = hppfs_write, 541 .open = hppfs_open, 542 .release = hppfs_release, 543}; 544 545struct hppfs_dirent { 546 struct dir_context ctx; 547 struct dir_context *caller; 548 struct dentry *dentry; 549}; 550 551static int hppfs_filldir(struct dir_context *ctx, const char *name, int size, 552 loff_t offset, u64 inode, unsigned int type) 553{ 554 struct hppfs_dirent *dirent = 555 container_of(ctx, struct hppfs_dirent, ctx); 556 557 if (file_removed(dirent->dentry, name)) 558 return 0; 559 560 dirent->caller->pos = dirent->ctx.pos; 561 return !dir_emit(dirent->caller, name, size, inode, type); 562} 563 564static int hppfs_readdir(struct file *file, struct dir_context *ctx) 565{ 566 struct hppfs_private *data = file->private_data; 567 struct file *proc_file = data->proc_file; 568 struct hppfs_dirent d = { 569 .ctx.actor = hppfs_filldir, 570 .caller = ctx, 571 .dentry = file->f_path.dentry 572 }; 573 int err; 574 proc_file->f_pos = ctx->pos; 575 err = iterate_dir(proc_file, &d.ctx); 576 ctx->pos = d.ctx.pos; 577 return err; 578} 579 580static const struct file_operations hppfs_dir_fops = { 581 .owner = NULL, 582 .iterate = hppfs_readdir, 583 .open = hppfs_dir_open, 584 .llseek = default_llseek, 585 .release = hppfs_release, 586}; 587 588static int hppfs_statfs(struct dentry *dentry, struct kstatfs *sf) 589{ 590 sf->f_blocks = 0; 591 sf->f_bfree = 0; 592 sf->f_bavail = 0; 593 sf->f_files = 0; 594 sf->f_ffree = 0; 595 sf->f_type = HPPFS_SUPER_MAGIC; 596 return 0; 597} 598 599static struct inode *hppfs_alloc_inode(struct super_block *sb) 600{ 601 struct hppfs_inode_info *hi; 602 603 hi = kmalloc(sizeof(*hi), GFP_KERNEL); 604 if (!hi) 605 return NULL; 606 607 hi->proc_dentry = NULL; 608 inode_init_once(&hi->vfs_inode); 609 return &hi->vfs_inode; 610} 611 612void hppfs_evict_inode(struct inode *ino) 613{ 614 clear_inode(ino); 615 dput(HPPFS_I(ino)->proc_dentry); 616 mntput(ino->i_sb->s_fs_info); 617} 618 619static void hppfs_i_callback(struct rcu_head *head) 620{ 621 struct inode *inode = container_of(head, struct inode, i_rcu); 622 kfree(HPPFS_I(inode)); 623} 624 625static void hppfs_destroy_inode(struct inode *inode) 626{ 627 call_rcu(&inode->i_rcu, hppfs_i_callback); 628} 629 630static const struct super_operations hppfs_sbops = { 631 .alloc_inode = hppfs_alloc_inode, 632 .destroy_inode = hppfs_destroy_inode, 633 .evict_inode = hppfs_evict_inode, 634 .statfs = hppfs_statfs, 635}; 636 637static int hppfs_readlink(struct dentry *dentry, char __user *buffer, 638 int buflen) 639{ 640 struct dentry *proc_dentry = HPPFS_I(d_inode(dentry))->proc_dentry; 641 return d_inode(proc_dentry)->i_op->readlink(proc_dentry, buffer, 642 buflen); 643} 644 645static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) 646{ 647 struct dentry *proc_dentry = HPPFS_I(d_inode(dentry))->proc_dentry; 648 649 return d_inode(proc_dentry)->i_op->follow_link(proc_dentry, nd); 650} 651 652static void hppfs_put_link(struct dentry *dentry, struct nameidata *nd, 653 void *cookie) 654{ 655 struct dentry *proc_dentry = HPPFS_I(d_inode(dentry))->proc_dentry; 656 657 if (d_inode(proc_dentry)->i_op->put_link) 658 d_inode(proc_dentry)->i_op->put_link(proc_dentry, nd, cookie); 659} 660 661static const struct inode_operations hppfs_dir_iops = { 662 .lookup = hppfs_lookup, 663}; 664 665static const struct inode_operations hppfs_link_iops = { 666 .readlink = hppfs_readlink, 667 .follow_link = hppfs_follow_link, 668 .put_link = hppfs_put_link, 669}; 670 671static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) 672{ 673 struct inode *proc_ino = d_inode(dentry); 674 struct inode *inode = new_inode(sb); 675 676 if (!inode) { 677 dput(dentry); 678 return NULL; 679 } 680 681 if (d_is_dir(dentry)) { 682 inode->i_op = &hppfs_dir_iops; 683 inode->i_fop = &hppfs_dir_fops; 684 } else if (d_is_symlink(dentry)) { 685 inode->i_op = &hppfs_link_iops; 686 inode->i_fop = &hppfs_file_fops; 687 } else { 688 inode->i_op = &hppfs_file_iops; 689 inode->i_fop = &hppfs_file_fops; 690 } 691 692 HPPFS_I(inode)->proc_dentry = dentry; 693 694 inode->i_uid = proc_ino->i_uid; 695 inode->i_gid = proc_ino->i_gid; 696 inode->i_atime = proc_ino->i_atime; 697 inode->i_mtime = proc_ino->i_mtime; 698 inode->i_ctime = proc_ino->i_ctime; 699 inode->i_ino = proc_ino->i_ino; 700 inode->i_mode = proc_ino->i_mode; 701 set_nlink(inode, proc_ino->i_nlink); 702 inode->i_size = proc_ino->i_size; 703 inode->i_blocks = proc_ino->i_blocks; 704 705 return inode; 706} 707 708static int hppfs_fill_super(struct super_block *sb, void *d, int silent) 709{ 710 struct inode *root_inode; 711 struct vfsmount *proc_mnt; 712 int err = -ENOENT; 713 714 proc_mnt = mntget(task_active_pid_ns(current)->proc_mnt); 715 if (IS_ERR(proc_mnt)) 716 goto out; 717 718 sb->s_blocksize = 1024; 719 sb->s_blocksize_bits = 10; 720 sb->s_magic = HPPFS_SUPER_MAGIC; 721 sb->s_op = &hppfs_sbops; 722 sb->s_fs_info = proc_mnt; 723 724 err = -ENOMEM; 725 root_inode = get_inode(sb, dget(proc_mnt->mnt_root)); 726 sb->s_root = d_make_root(root_inode); 727 if (!sb->s_root) 728 goto out_mntput; 729 730 return 0; 731 732 out_mntput: 733 mntput(proc_mnt); 734 out: 735 return(err); 736} 737 738static struct dentry *hppfs_read_super(struct file_system_type *type, 739 int flags, const char *dev_name, 740 void *data) 741{ 742 return mount_nodev(type, flags, data, hppfs_fill_super); 743} 744 745static struct file_system_type hppfs_type = { 746 .owner = THIS_MODULE, 747 .name = "hppfs", 748 .mount = hppfs_read_super, 749 .kill_sb = kill_anon_super, 750 .fs_flags = 0, 751}; 752MODULE_ALIAS_FS("hppfs"); 753 754static int __init init_hppfs(void) 755{ 756 return register_filesystem(&hppfs_type); 757} 758 759static void __exit exit_hppfs(void) 760{ 761 unregister_filesystem(&hppfs_type); 762} 763 764module_init(init_hppfs) 765module_exit(exit_hppfs) 766MODULE_LICENSE("GPL"); 767