1/* 2 * SPU file system 3 * 4 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 5 * 6 * Author: Arnd Bergmann <arndb@de.ibm.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2, or (at your option) 11 * any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23#include <linux/file.h> 24#include <linux/fs.h> 25#include <linux/backing-dev.h> 26#include <linux/init.h> 27#include <linux/ioctl.h> 28#include <linux/module.h> 29#include <linux/mount.h> 30#include <linux/namei.h> 31#include <linux/pagemap.h> 32#include <linux/poll.h> 33#include <linux/slab.h> 34#include <linux/parser.h> 35 36#include <asm/prom.h> 37#include <asm/semaphore.h> 38#include <asm/spu.h> 39#include <asm/spu_priv1.h> 40#include <asm/uaccess.h> 41 42#include "spufs.h" 43 44static struct kmem_cache *spufs_inode_cache; 45char *isolated_loader; 46 47static struct inode * 48spufs_alloc_inode(struct super_block *sb) 49{ 50 struct spufs_inode_info *ei; 51 52 ei = kmem_cache_alloc(spufs_inode_cache, GFP_KERNEL); 53 if (!ei) 54 return NULL; 55 56 ei->i_gang = NULL; 57 ei->i_ctx = NULL; 58 ei->i_openers = 0; 59 60 return &ei->vfs_inode; 61} 62 63static void 64spufs_destroy_inode(struct inode *inode) 65{ 66 kmem_cache_free(spufs_inode_cache, SPUFS_I(inode)); 67} 68 69static void 70spufs_init_once(void *p, struct kmem_cache * cachep, unsigned long flags) 71{ 72 struct spufs_inode_info *ei = p; 73 74 inode_init_once(&ei->vfs_inode); 75} 76 77static struct inode * 78spufs_new_inode(struct super_block *sb, int mode) 79{ 80 struct inode *inode; 81 82 inode = new_inode(sb); 83 if (!inode) 84 goto out; 85 86 inode->i_mode = mode; 87 inode->i_uid = current->fsuid; 88 inode->i_gid = current->fsgid; 89 inode->i_blocks = 0; 90 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 91out: 92 return inode; 93} 94 95static int 96spufs_setattr(struct dentry *dentry, struct iattr *attr) 97{ 98 struct inode *inode = dentry->d_inode; 99 100 if ((attr->ia_valid & ATTR_SIZE) && 101 (attr->ia_size != inode->i_size)) 102 return -EINVAL; 103 return inode_setattr(inode, attr); 104} 105 106 107static int 108spufs_new_file(struct super_block *sb, struct dentry *dentry, 109 const struct file_operations *fops, int mode, 110 struct spu_context *ctx) 111{ 112 static struct inode_operations spufs_file_iops = { 113 .setattr = spufs_setattr, 114 }; 115 struct inode *inode; 116 int ret; 117 118 ret = -ENOSPC; 119 inode = spufs_new_inode(sb, S_IFREG | mode); 120 if (!inode) 121 goto out; 122 123 ret = 0; 124 inode->i_op = &spufs_file_iops; 125 inode->i_fop = fops; 126 inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx); 127 d_add(dentry, inode); 128out: 129 return ret; 130} 131 132static void 133spufs_delete_inode(struct inode *inode) 134{ 135 struct spufs_inode_info *ei = SPUFS_I(inode); 136 137 if (ei->i_ctx) 138 put_spu_context(ei->i_ctx); 139 if (ei->i_gang) 140 put_spu_gang(ei->i_gang); 141 clear_inode(inode); 142} 143 144static void spufs_prune_dir(struct dentry *dir) 145{ 146 struct dentry *dentry, *tmp; 147 148 mutex_lock(&dir->d_inode->i_mutex); 149 list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { 150 spin_lock(&dcache_lock); 151 spin_lock(&dentry->d_lock); 152 if (!(d_unhashed(dentry)) && dentry->d_inode) { 153 dget_locked(dentry); 154 __d_drop(dentry); 155 spin_unlock(&dentry->d_lock); 156 simple_unlink(dir->d_inode, dentry); 157 spin_unlock(&dcache_lock); 158 dput(dentry); 159 } else { 160 spin_unlock(&dentry->d_lock); 161 spin_unlock(&dcache_lock); 162 } 163 } 164 shrink_dcache_parent(dir); 165 mutex_unlock(&dir->d_inode->i_mutex); 166} 167 168/* Caller must hold parent->i_mutex */ 169static int spufs_rmdir(struct inode *parent, struct dentry *dir) 170{ 171 /* remove all entries */ 172 spufs_prune_dir(dir); 173 174 return simple_rmdir(parent, dir); 175} 176 177static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, 178 int mode, struct spu_context *ctx) 179{ 180 struct dentry *dentry, *tmp; 181 int ret; 182 183 while (files->name && files->name[0]) { 184 ret = -ENOMEM; 185 dentry = d_alloc_name(dir, files->name); 186 if (!dentry) 187 goto out; 188 ret = spufs_new_file(dir->d_sb, dentry, files->ops, 189 files->mode & mode, ctx); 190 if (ret) 191 goto out; 192 files++; 193 } 194 return 0; 195out: 196 /* 197 * remove all children from dir. dir->inode is not set so don't 198 * just simply use spufs_prune_dir() and panic afterwards :) 199 * dput() looks like it will do the right thing: 200 * - dec parent's ref counter 201 * - remove child from parent's child list 202 * - free child's inode if possible 203 * - free child 204 */ 205 list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { 206 dput(dentry); 207 } 208 209 shrink_dcache_parent(dir); 210 return ret; 211} 212 213static int spufs_dir_close(struct inode *inode, struct file *file) 214{ 215 struct spu_context *ctx; 216 struct inode *parent; 217 struct dentry *dir; 218 int ret; 219 220 dir = file->f_path.dentry; 221 parent = dir->d_parent->d_inode; 222 ctx = SPUFS_I(dir->d_inode)->i_ctx; 223 224 mutex_lock(&parent->i_mutex); 225 ret = spufs_rmdir(parent, dir); 226 mutex_unlock(&parent->i_mutex); 227 WARN_ON(ret); 228 229 /* We have to give up the mm_struct */ 230 spu_forget(ctx); 231 232 return dcache_dir_close(inode, file); 233} 234 235const struct inode_operations spufs_dir_inode_operations = { 236 .lookup = simple_lookup, 237}; 238 239const struct file_operations spufs_context_fops = { 240 .open = dcache_dir_open, 241 .release = spufs_dir_close, 242 .llseek = dcache_dir_lseek, 243 .read = generic_read_dir, 244 .readdir = dcache_readdir, 245 .fsync = simple_sync_file, 246}; 247EXPORT_SYMBOL_GPL(spufs_context_fops); 248 249static int 250spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, 251 int mode) 252{ 253 int ret; 254 struct inode *inode; 255 struct spu_context *ctx; 256 257 ret = -ENOSPC; 258 inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR); 259 if (!inode) 260 goto out; 261 262 if (dir->i_mode & S_ISGID) { 263 inode->i_gid = dir->i_gid; 264 inode->i_mode &= S_ISGID; 265 } 266 ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); 267 SPUFS_I(inode)->i_ctx = ctx; 268 if (!ctx) 269 goto out_iput; 270 271 ctx->flags = flags; 272 inode->i_op = &spufs_dir_inode_operations; 273 inode->i_fop = &simple_dir_operations; 274 if (flags & SPU_CREATE_NOSCHED) 275 ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents, 276 mode, ctx); 277 else 278 ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx); 279 280 if (ret) 281 goto out_free_ctx; 282 283 d_instantiate(dentry, inode); 284 dget(dentry); 285 dir->i_nlink++; 286 dentry->d_inode->i_nlink++; 287 goto out; 288 289out_free_ctx: 290 spu_forget(ctx); 291 put_spu_context(ctx); 292out_iput: 293 iput(inode); 294out: 295 return ret; 296} 297 298static int spufs_context_open(struct dentry *dentry, struct vfsmount *mnt) 299{ 300 int ret; 301 struct file *filp; 302 303 ret = get_unused_fd(); 304 if (ret < 0) { 305 dput(dentry); 306 mntput(mnt); 307 goto out; 308 } 309 310 filp = dentry_open(dentry, mnt, O_RDONLY); 311 if (IS_ERR(filp)) { 312 put_unused_fd(ret); 313 ret = PTR_ERR(filp); 314 goto out; 315 } 316 317 filp->f_op = &spufs_context_fops; 318 fd_install(ret, filp); 319out: 320 return ret; 321} 322 323static int spufs_create_context(struct inode *inode, 324 struct dentry *dentry, 325 struct vfsmount *mnt, int flags, int mode) 326{ 327 int ret; 328 329 ret = -EPERM; 330 if ((flags & SPU_CREATE_NOSCHED) && 331 !capable(CAP_SYS_NICE)) 332 goto out_unlock; 333 334 ret = -EINVAL; 335 if ((flags & (SPU_CREATE_NOSCHED | SPU_CREATE_ISOLATE)) 336 == SPU_CREATE_ISOLATE) 337 goto out_unlock; 338 339 ret = -ENODEV; 340 if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader) 341 goto out_unlock; 342 343 ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO); 344 if (ret) 345 goto out_unlock; 346 347 /* 348 * get references for dget and mntget, will be released 349 * in error path of *_open(). 350 */ 351 ret = spufs_context_open(dget(dentry), mntget(mnt)); 352 if (ret < 0) { 353 WARN_ON(spufs_rmdir(inode, dentry)); 354 mutex_unlock(&inode->i_mutex); 355 spu_forget(SPUFS_I(dentry->d_inode)->i_ctx); 356 goto out; 357 } 358 359out_unlock: 360 mutex_unlock(&inode->i_mutex); 361out: 362 dput(dentry); 363 return ret; 364} 365 366static int 367spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode) 368{ 369 int ret; 370 struct inode *inode; 371 struct spu_gang *gang; 372 373 ret = -ENOSPC; 374 inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR); 375 if (!inode) 376 goto out; 377 378 ret = 0; 379 if (dir->i_mode & S_ISGID) { 380 inode->i_gid = dir->i_gid; 381 inode->i_mode &= S_ISGID; 382 } 383 gang = alloc_spu_gang(); 384 SPUFS_I(inode)->i_ctx = NULL; 385 SPUFS_I(inode)->i_gang = gang; 386 if (!gang) 387 goto out_iput; 388 389 inode->i_op = &spufs_dir_inode_operations; 390 inode->i_fop = &simple_dir_operations; 391 392 d_instantiate(dentry, inode); 393 dir->i_nlink++; 394 dentry->d_inode->i_nlink++; 395 return ret; 396 397out_iput: 398 iput(inode); 399out: 400 return ret; 401} 402 403static int spufs_gang_open(struct dentry *dentry, struct vfsmount *mnt) 404{ 405 int ret; 406 struct file *filp; 407 408 ret = get_unused_fd(); 409 if (ret < 0) { 410 dput(dentry); 411 mntput(mnt); 412 goto out; 413 } 414 415 filp = dentry_open(dentry, mnt, O_RDONLY); 416 if (IS_ERR(filp)) { 417 put_unused_fd(ret); 418 ret = PTR_ERR(filp); 419 goto out; 420 } 421 422 filp->f_op = &simple_dir_operations; 423 fd_install(ret, filp); 424out: 425 return ret; 426} 427 428static int spufs_create_gang(struct inode *inode, 429 struct dentry *dentry, 430 struct vfsmount *mnt, int mode) 431{ 432 int ret; 433 434 ret = spufs_mkgang(inode, dentry, mode & S_IRWXUGO); 435 if (ret) 436 goto out; 437 438 /* 439 * get references for dget and mntget, will be released 440 * in error path of *_open(). 441 */ 442 ret = spufs_gang_open(dget(dentry), mntget(mnt)); 443 if (ret < 0) { 444 int err = simple_rmdir(inode, dentry); 445 WARN_ON(err); 446 } 447 448out: 449 mutex_unlock(&inode->i_mutex); 450 dput(dentry); 451 return ret; 452} 453 454 455static struct file_system_type spufs_type; 456 457long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode) 458{ 459 struct dentry *dentry; 460 int ret; 461 462 ret = -EINVAL; 463 /* check if we are on spufs */ 464 if (nd->dentry->d_sb->s_type != &spufs_type) 465 goto out; 466 467 /* don't accept undefined flags */ 468 if (flags & (~SPU_CREATE_FLAG_ALL)) 469 goto out; 470 471 /* only threads can be underneath a gang */ 472 if (nd->dentry != nd->dentry->d_sb->s_root) { 473 if ((flags & SPU_CREATE_GANG) || 474 !SPUFS_I(nd->dentry->d_inode)->i_gang) 475 goto out; 476 } 477 478 dentry = lookup_create(nd, 1); 479 ret = PTR_ERR(dentry); 480 if (IS_ERR(dentry)) 481 goto out_dir; 482 483 ret = -EEXIST; 484 if (dentry->d_inode) 485 goto out_dput; 486 487 mode &= ~current->fs->umask; 488 489 if (flags & SPU_CREATE_GANG) 490 return spufs_create_gang(nd->dentry->d_inode, 491 dentry, nd->mnt, mode); 492 else 493 return spufs_create_context(nd->dentry->d_inode, 494 dentry, nd->mnt, flags, mode); 495 496out_dput: 497 dput(dentry); 498out_dir: 499 mutex_unlock(&nd->dentry->d_inode->i_mutex); 500out: 501 return ret; 502} 503 504/* File system initialization */ 505enum { 506 Opt_uid, Opt_gid, Opt_mode, Opt_err, 507}; 508 509static match_table_t spufs_tokens = { 510 { Opt_uid, "uid=%d" }, 511 { Opt_gid, "gid=%d" }, 512 { Opt_mode, "mode=%o" }, 513 { Opt_err, NULL }, 514}; 515 516static int 517spufs_parse_options(char *options, struct inode *root) 518{ 519 char *p; 520 substring_t args[MAX_OPT_ARGS]; 521 522 while ((p = strsep(&options, ",")) != NULL) { 523 int token, option; 524 525 if (!*p) 526 continue; 527 528 token = match_token(p, spufs_tokens, args); 529 switch (token) { 530 case Opt_uid: 531 if (match_int(&args[0], &option)) 532 return 0; 533 root->i_uid = option; 534 break; 535 case Opt_gid: 536 if (match_int(&args[0], &option)) 537 return 0; 538 root->i_gid = option; 539 break; 540 case Opt_mode: 541 if (match_octal(&args[0], &option)) 542 return 0; 543 root->i_mode = option | S_IFDIR; 544 break; 545 default: 546 return 0; 547 } 548 } 549 return 1; 550} 551 552static void spufs_exit_isolated_loader(void) 553{ 554 kfree(isolated_loader); 555} 556 557static void 558spufs_init_isolated_loader(void) 559{ 560 struct device_node *dn; 561 const char *loader; 562 int size; 563 564 dn = of_find_node_by_path("/spu-isolation"); 565 if (!dn) 566 return; 567 568 loader = of_get_property(dn, "loader", &size); 569 if (!loader) 570 return; 571 572 /* kmalloc should align on a 16 byte boundary..* */ 573 isolated_loader = kmalloc(size, GFP_KERNEL); 574 if (!isolated_loader) 575 return; 576 577 memcpy(isolated_loader, loader, size); 578 printk(KERN_INFO "spufs: SPU isolation mode enabled\n"); 579} 580 581static int 582spufs_create_root(struct super_block *sb, void *data) 583{ 584 struct inode *inode; 585 int ret; 586 587 ret = -ENODEV; 588 if (!spu_management_ops) 589 goto out; 590 591 ret = -ENOMEM; 592 inode = spufs_new_inode(sb, S_IFDIR | 0775); 593 if (!inode) 594 goto out; 595 596 inode->i_op = &spufs_dir_inode_operations; 597 inode->i_fop = &simple_dir_operations; 598 SPUFS_I(inode)->i_ctx = NULL; 599 600 ret = -EINVAL; 601 if (!spufs_parse_options(data, inode)) 602 goto out_iput; 603 604 ret = -ENOMEM; 605 sb->s_root = d_alloc_root(inode); 606 if (!sb->s_root) 607 goto out_iput; 608 609 return 0; 610out_iput: 611 iput(inode); 612out: 613 return ret; 614} 615 616static int 617spufs_fill_super(struct super_block *sb, void *data, int silent) 618{ 619 static struct super_operations s_ops = { 620 .alloc_inode = spufs_alloc_inode, 621 .destroy_inode = spufs_destroy_inode, 622 .statfs = simple_statfs, 623 .delete_inode = spufs_delete_inode, 624 .drop_inode = generic_delete_inode, 625 }; 626 627 sb->s_maxbytes = MAX_LFS_FILESIZE; 628 sb->s_blocksize = PAGE_CACHE_SIZE; 629 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 630 sb->s_magic = SPUFS_MAGIC; 631 sb->s_op = &s_ops; 632 633 return spufs_create_root(sb, data); 634} 635 636static int 637spufs_get_sb(struct file_system_type *fstype, int flags, 638 const char *name, void *data, struct vfsmount *mnt) 639{ 640 return get_sb_single(fstype, flags, data, spufs_fill_super, mnt); 641} 642 643static struct file_system_type spufs_type = { 644 .owner = THIS_MODULE, 645 .name = "spufs", 646 .get_sb = spufs_get_sb, 647 .kill_sb = kill_litter_super, 648}; 649 650static int __init spufs_init(void) 651{ 652 int ret; 653 654 ret = -ENODEV; 655 if (!spu_management_ops) 656 goto out; 657 658 ret = -ENOMEM; 659 spufs_inode_cache = kmem_cache_create("spufs_inode_cache", 660 sizeof(struct spufs_inode_info), 0, 661 SLAB_HWCACHE_ALIGN, spufs_init_once, NULL); 662 663 if (!spufs_inode_cache) 664 goto out; 665 ret = spu_sched_init(); 666 if (ret) 667 goto out_cache; 668 ret = register_filesystem(&spufs_type); 669 if (ret) 670 goto out_sched; 671 ret = register_spu_syscalls(&spufs_calls); 672 if (ret) 673 goto out_fs; 674 ret = register_arch_coredump_calls(&spufs_coredump_calls); 675 if (ret) 676 goto out_syscalls; 677 678 spufs_init_isolated_loader(); 679 680 return 0; 681 682out_syscalls: 683 unregister_spu_syscalls(&spufs_calls); 684out_fs: 685 unregister_filesystem(&spufs_type); 686out_sched: 687 spu_sched_exit(); 688out_cache: 689 kmem_cache_destroy(spufs_inode_cache); 690out: 691 return ret; 692} 693module_init(spufs_init); 694 695static void __exit spufs_exit(void) 696{ 697 spu_sched_exit(); 698 spufs_exit_isolated_loader(); 699 unregister_arch_coredump_calls(&spufs_coredump_calls); 700 unregister_spu_syscalls(&spufs_calls); 701 unregister_filesystem(&spufs_type); 702 kmem_cache_destroy(spufs_inode_cache); 703} 704module_exit(spufs_exit); 705 706MODULE_LICENSE("GPL"); 707MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); 708