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