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/io.h> 37 #include <asm/semaphore.h> 38 #include <asm/spu.h> 39 #include <asm/uaccess.h> 40 41 #include "spufs.h" 42 43 static kmem_cache_t *spufs_inode_cache; 44 45 static struct inode * 46 spufs_alloc_inode(struct super_block *sb) 47 { 48 struct spufs_inode_info *ei; 49 50 ei = kmem_cache_alloc(spufs_inode_cache, SLAB_KERNEL); 51 if (!ei) 52 return NULL; 53 return &ei->vfs_inode; 54 } 55 56 static void 57 spufs_destroy_inode(struct inode *inode) 58 { 59 kmem_cache_free(spufs_inode_cache, SPUFS_I(inode)); 60 } 61 62 static void 63 spufs_init_once(void *p, kmem_cache_t * cachep, unsigned long flags) 64 { 65 struct spufs_inode_info *ei = p; 66 67 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == 68 SLAB_CTOR_CONSTRUCTOR) { 69 inode_init_once(&ei->vfs_inode); 70 } 71 } 72 73 static struct inode * 74 spufs_new_inode(struct super_block *sb, int mode) 75 { 76 struct inode *inode; 77 78 inode = new_inode(sb); 79 if (!inode) 80 goto out; 81 82 inode->i_mode = mode; 83 inode->i_uid = current->fsuid; 84 inode->i_gid = current->fsgid; 85 inode->i_blksize = PAGE_CACHE_SIZE; 86 inode->i_blocks = 0; 87 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 88 out: 89 return inode; 90 } 91 92 static int 93 spufs_setattr(struct dentry *dentry, struct iattr *attr) 94 { 95 struct inode *inode = dentry->d_inode; 96 97 if ((attr->ia_valid & ATTR_SIZE) && 98 (attr->ia_size != inode->i_size)) 99 return -EINVAL; 100 return inode_setattr(inode, attr); 101 } 102 103 104 static int 105 spufs_new_file(struct super_block *sb, struct dentry *dentry, 106 struct file_operations *fops, int mode, 107 struct spu_context *ctx) 108 { 109 static struct inode_operations spufs_file_iops = { 110 .setattr = spufs_setattr, 111 }; 112 struct inode *inode; 113 int ret; 114 115 ret = -ENOSPC; 116 inode = spufs_new_inode(sb, S_IFREG | mode); 117 if (!inode) 118 goto out; 119 120 ret = 0; 121 inode->i_op = &spufs_file_iops; 122 inode->i_fop = fops; 123 inode->u.generic_ip = SPUFS_I(inode)->i_ctx = get_spu_context(ctx); 124 d_add(dentry, inode); 125 out: 126 return ret; 127 } 128 129 static void 130 spufs_delete_inode(struct inode *inode) 131 { 132 if (SPUFS_I(inode)->i_ctx) 133 put_spu_context(SPUFS_I(inode)->i_ctx); 134 clear_inode(inode); 135 } 136 137 static void spufs_prune_dir(struct dentry *dir) 138 { 139 struct dentry *dentry, *tmp; 140 mutex_lock(&dir->d_inode->i_mutex); 141 list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { 142 spin_lock(&dcache_lock); 143 spin_lock(&dentry->d_lock); 144 if (!(d_unhashed(dentry)) && dentry->d_inode) { 145 dget_locked(dentry); 146 __d_drop(dentry); 147 spin_unlock(&dentry->d_lock); 148 simple_unlink(dir->d_inode, dentry); 149 spin_unlock(&dcache_lock); 150 dput(dentry); 151 } else { 152 spin_unlock(&dentry->d_lock); 153 spin_unlock(&dcache_lock); 154 } 155 } 156 shrink_dcache_parent(dir); 157 mutex_unlock(&dir->d_inode->i_mutex); 158 } 159 160 static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) 161 { 162 struct spu_context *ctx; 163 164 /* remove all entries */ 165 mutex_lock(&root->i_mutex); 166 spufs_prune_dir(dir_dentry); 167 mutex_unlock(&root->i_mutex); 168 169 /* We have to give up the mm_struct */ 170 ctx = SPUFS_I(dir_dentry->d_inode)->i_ctx; 171 spu_forget(ctx); 172 173 /* XXX Do we need to hold i_mutex here ? */ 174 return simple_rmdir(root, dir_dentry); 175 } 176 177 static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, 178 int mode, struct spu_context *ctx) 179 { 180 struct dentry *dentry; 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; 195 out: 196 spufs_prune_dir(dir); 197 return ret; 198 } 199 200 static int spufs_dir_close(struct inode *inode, struct file *file) 201 { 202 struct inode *dir; 203 struct dentry *dentry; 204 int ret; 205 206 dentry = file->f_dentry; 207 dir = dentry->d_parent->d_inode; 208 209 ret = spufs_rmdir(dir, dentry); 210 WARN_ON(ret); 211 212 return dcache_dir_close(inode, file); 213 } 214 215 struct inode_operations spufs_dir_inode_operations = { 216 .lookup = simple_lookup, 217 }; 218 219 struct file_operations spufs_context_fops = { 220 .open = dcache_dir_open, 221 .release = spufs_dir_close, 222 .llseek = dcache_dir_lseek, 223 .read = generic_read_dir, 224 .readdir = dcache_readdir, 225 .fsync = simple_sync_file, 226 }; 227 228 static int 229 spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 230 { 231 int ret; 232 struct inode *inode; 233 struct spu_context *ctx; 234 235 ret = -ENOSPC; 236 inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR); 237 if (!inode) 238 goto out; 239 240 if (dir->i_mode & S_ISGID) { 241 inode->i_gid = dir->i_gid; 242 inode->i_mode &= S_ISGID; 243 } 244 ctx = alloc_spu_context(inode->i_mapping); 245 SPUFS_I(inode)->i_ctx = ctx; 246 if (!ctx) 247 goto out_iput; 248 249 inode->i_op = &spufs_dir_inode_operations; 250 inode->i_fop = &simple_dir_operations; 251 ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx); 252 if (ret) 253 goto out_free_ctx; 254 255 d_instantiate(dentry, inode); 256 dget(dentry); 257 dir->i_nlink++; 258 dentry->d_inode->i_nlink++; 259 goto out; 260 261 out_free_ctx: 262 put_spu_context(ctx); 263 out_iput: 264 iput(inode); 265 out: 266 return ret; 267 } 268 269 static int spufs_context_open(struct dentry *dentry, struct vfsmount *mnt) 270 { 271 int ret; 272 struct file *filp; 273 274 ret = get_unused_fd(); 275 if (ret < 0) { 276 dput(dentry); 277 mntput(mnt); 278 goto out; 279 } 280 281 filp = dentry_open(dentry, mnt, O_RDONLY); 282 if (IS_ERR(filp)) { 283 put_unused_fd(ret); 284 ret = PTR_ERR(filp); 285 goto out; 286 } 287 288 filp->f_op = &spufs_context_fops; 289 fd_install(ret, filp); 290 out: 291 return ret; 292 } 293 294 static struct file_system_type spufs_type; 295 296 long spufs_create_thread(struct nameidata *nd, 297 unsigned int flags, mode_t mode) 298 { 299 struct dentry *dentry; 300 int ret; 301 302 /* need to be at the root of spufs */ 303 ret = -EINVAL; 304 if (nd->dentry->d_sb->s_type != &spufs_type || 305 nd->dentry != nd->dentry->d_sb->s_root) 306 goto out; 307 308 dentry = lookup_create(nd, 1); 309 ret = PTR_ERR(dentry); 310 if (IS_ERR(dentry)) 311 goto out_dir; 312 313 ret = -EEXIST; 314 if (dentry->d_inode) 315 goto out_dput; 316 317 mode &= ~current->fs->umask; 318 ret = spufs_mkdir(nd->dentry->d_inode, dentry, mode & S_IRWXUGO); 319 if (ret) 320 goto out_dput; 321 322 /* 323 * get references for dget and mntget, will be released 324 * in error path of *_open(). 325 */ 326 ret = spufs_context_open(dget(dentry), mntget(nd->mnt)); 327 if (ret < 0) 328 spufs_rmdir(nd->dentry->d_inode, dentry); 329 330 out_dput: 331 dput(dentry); 332 out_dir: 333 mutex_unlock(&nd->dentry->d_inode->i_mutex); 334 out: 335 return ret; 336 } 337 338 /* File system initialization */ 339 enum { 340 Opt_uid, Opt_gid, Opt_err, 341 }; 342 343 static match_table_t spufs_tokens = { 344 { Opt_uid, "uid=%d" }, 345 { Opt_gid, "gid=%d" }, 346 { Opt_err, NULL }, 347 }; 348 349 static int 350 spufs_parse_options(char *options, struct inode *root) 351 { 352 char *p; 353 substring_t args[MAX_OPT_ARGS]; 354 355 while ((p = strsep(&options, ",")) != NULL) { 356 int token, option; 357 358 if (!*p) 359 continue; 360 361 token = match_token(p, spufs_tokens, args); 362 switch (token) { 363 case Opt_uid: 364 if (match_int(&args[0], &option)) 365 return 0; 366 root->i_uid = option; 367 break; 368 case Opt_gid: 369 if (match_int(&args[0], &option)) 370 return 0; 371 root->i_gid = option; 372 break; 373 default: 374 return 0; 375 } 376 } 377 return 1; 378 } 379 380 static int 381 spufs_create_root(struct super_block *sb, void *data) 382 { 383 struct inode *inode; 384 int ret; 385 386 ret = -ENOMEM; 387 inode = spufs_new_inode(sb, S_IFDIR | 0775); 388 if (!inode) 389 goto out; 390 391 inode->i_op = &spufs_dir_inode_operations; 392 inode->i_fop = &simple_dir_operations; 393 SPUFS_I(inode)->i_ctx = NULL; 394 395 ret = -EINVAL; 396 if (!spufs_parse_options(data, inode)) 397 goto out_iput; 398 399 ret = -ENOMEM; 400 sb->s_root = d_alloc_root(inode); 401 if (!sb->s_root) 402 goto out_iput; 403 404 return 0; 405 out_iput: 406 iput(inode); 407 out: 408 return ret; 409 } 410 411 static int 412 spufs_fill_super(struct super_block *sb, void *data, int silent) 413 { 414 static struct super_operations s_ops = { 415 .alloc_inode = spufs_alloc_inode, 416 .destroy_inode = spufs_destroy_inode, 417 .statfs = simple_statfs, 418 .delete_inode = spufs_delete_inode, 419 .drop_inode = generic_delete_inode, 420 }; 421 422 sb->s_maxbytes = MAX_LFS_FILESIZE; 423 sb->s_blocksize = PAGE_CACHE_SIZE; 424 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 425 sb->s_magic = SPUFS_MAGIC; 426 sb->s_op = &s_ops; 427 428 return spufs_create_root(sb, data); 429 } 430 431 static struct super_block * 432 spufs_get_sb(struct file_system_type *fstype, int flags, 433 const char *name, void *data) 434 { 435 return get_sb_single(fstype, flags, data, spufs_fill_super); 436 } 437 438 static struct file_system_type spufs_type = { 439 .owner = THIS_MODULE, 440 .name = "spufs", 441 .get_sb = spufs_get_sb, 442 .kill_sb = kill_litter_super, 443 }; 444 445 static int spufs_init(void) 446 { 447 int ret; 448 ret = -ENOMEM; 449 spufs_inode_cache = kmem_cache_create("spufs_inode_cache", 450 sizeof(struct spufs_inode_info), 0, 451 SLAB_HWCACHE_ALIGN, spufs_init_once, NULL); 452 453 if (!spufs_inode_cache) 454 goto out; 455 if (spu_sched_init() != 0) { 456 kmem_cache_destroy(spufs_inode_cache); 457 goto out; 458 } 459 ret = register_filesystem(&spufs_type); 460 if (ret) 461 goto out_cache; 462 ret = register_spu_syscalls(&spufs_calls); 463 if (ret) 464 goto out_fs; 465 return 0; 466 out_fs: 467 unregister_filesystem(&spufs_type); 468 out_cache: 469 kmem_cache_destroy(spufs_inode_cache); 470 out: 471 return ret; 472 } 473 module_init(spufs_init); 474 475 static void spufs_exit(void) 476 { 477 spu_sched_exit(); 478 unregister_spu_syscalls(&spufs_calls); 479 unregister_filesystem(&spufs_type); 480 kmem_cache_destroy(spufs_inode_cache); 481 } 482 module_exit(spufs_exit); 483 484 MODULE_LICENSE("GPL"); 485 MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); 486 487