1/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- 2 * vim:expandtab:shiftwidth=8:tabstop=8: 3 * 4 * Copyright (C) 2000 Stelias Computing, Inc. 5 * Copyright (C) 2000 Red Hat, Inc. 6 * Copyright (C) 2000 Mountain View Data, Inc. 7 * 8 * Extended Attribute Support 9 * Copyright (C) 2001 Shirish H. Phatak, Tacit Networks, Inc. 10 * 11 * This file is part of InterMezzo, http://www.inter-mezzo.org. 12 * 13 * InterMezzo is free software; you can redistribute it and/or 14 * modify it under the terms of version 2 of the GNU General Public 15 * License as published by the Free Software Foundation. 16 * 17 * InterMezzo is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with InterMezzo; if not, write to the Free Software 24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 25 * 26 */ 27 28#include <stdarg.h> 29 30#include <asm/bitops.h> 31#include <asm/uaccess.h> 32#include <asm/system.h> 33 34#include <linux/errno.h> 35#include <linux/fs.h> 36#include <linux/ext2_fs.h> 37#include <linux/slab.h> 38#include <linux/vmalloc.h> 39#include <linux/sched.h> 40#include <linux/stat.h> 41#include <linux/string.h> 42#include <linux/locks.h> 43#include <linux/blkdev.h> 44#include <linux/init.h> 45#define __NO_VERSION__ 46#include <linux/module.h> 47 48#include <linux/fsfilter.h> 49#include <linux/intermezzo_fs.h> 50 51 52int filter_print_entry = 0; 53int filter_debug = 0xfffffff; 54/* 55 * The function in this file are responsible for setting up the 56 * correct methods layered file systems like InterMezzo and snapfs 57 */ 58 59 60static struct filter_fs filter_oppar[FILTER_FS_TYPES]; 61 62/* get to the upper methods (intermezzo, snapfs) */ 63inline struct super_operations *filter_c2usops(struct filter_fs *cache) 64{ 65 return &cache->o_fops.filter_sops; 66} 67 68inline struct inode_operations *filter_c2udiops(struct filter_fs *cache) 69{ 70 return &cache->o_fops.filter_dir_iops; 71} 72 73 74inline struct inode_operations *filter_c2ufiops(struct filter_fs *cache) 75{ 76 return &cache->o_fops.filter_file_iops; 77} 78 79inline struct inode_operations *filter_c2usiops(struct filter_fs *cache) 80{ 81 return &cache->o_fops.filter_sym_iops; 82} 83 84 85inline struct file_operations *filter_c2udfops(struct filter_fs *cache) 86{ 87 return &cache->o_fops.filter_dir_fops; 88} 89 90inline struct file_operations *filter_c2uffops(struct filter_fs *cache) 91{ 92 return &cache->o_fops.filter_file_fops; 93} 94 95inline struct file_operations *filter_c2usfops(struct filter_fs *cache) 96{ 97 return &cache->o_fops.filter_sym_fops; 98} 99 100inline struct dentry_operations *filter_c2udops(struct filter_fs *cache) 101{ 102 return &cache->o_fops.filter_dentry_ops; 103} 104 105/* get to the cache (lower) methods */ 106inline struct super_operations *filter_c2csops(struct filter_fs *cache) 107{ 108 return cache->o_caops.cache_sops; 109} 110 111inline struct inode_operations *filter_c2cdiops(struct filter_fs *cache) 112{ 113 return cache->o_caops.cache_dir_iops; 114} 115 116inline struct inode_operations *filter_c2cfiops(struct filter_fs *cache) 117{ 118 return cache->o_caops.cache_file_iops; 119} 120 121inline struct inode_operations *filter_c2csiops(struct filter_fs *cache) 122{ 123 return cache->o_caops.cache_sym_iops; 124} 125 126inline struct file_operations *filter_c2cdfops(struct filter_fs *cache) 127{ 128 return cache->o_caops.cache_dir_fops; 129} 130 131inline struct file_operations *filter_c2cffops(struct filter_fs *cache) 132{ 133 return cache->o_caops.cache_file_fops; 134} 135 136inline struct file_operations *filter_c2csfops(struct filter_fs *cache) 137{ 138 return cache->o_caops.cache_sym_fops; 139} 140 141inline struct dentry_operations *filter_c2cdops(struct filter_fs *cache) 142{ 143 return cache->o_caops.cache_dentry_ops; 144} 145 146 147void filter_setup_journal_ops(struct filter_fs *ops, char *cache_type) 148{ 149 if ( strlen(cache_type) == strlen("ext2") && 150 memcmp(cache_type, "ext2", strlen("ext2")) == 0 ) { 151#if CONFIG_EXT2_FS 152 ops->o_trops = &presto_ext2_journal_ops; 153#else 154 ops->o_trops = NULL; 155#endif 156 FDEBUG(D_SUPER, "ops at %p\n", ops); 157 } 158 159 if ( strlen(cache_type) == strlen("ext3") && 160 memcmp(cache_type, "ext3", strlen("ext3")) == 0 ) { 161#if defined(CONFIG_EXT3_FS) || defined(CONFIG_EXT3_FS_MODULE) 162 ops->o_trops = &presto_ext3_journal_ops; 163#else 164 ops->o_trops = NULL; 165#endif 166 FDEBUG(D_SUPER, "ops at %p\n", ops); 167 } 168 169 if ( strlen(cache_type) == strlen("tmpfs") && 170 memcmp(cache_type, "tmpfs", strlen("tmpfs")) == 0 ) { 171#if defined(CONFIG_TMPFS) 172 ops->o_trops = &presto_tmpfs_journal_ops; 173#else 174 ops->o_trops = NULL; 175#endif 176 FDEBUG(D_SUPER, "ops at %p\n", ops); 177 } 178 179 if ( strlen(cache_type) == strlen("reiserfs") && 180 memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) { 181 ops->o_trops = NULL; 182 FDEBUG(D_SUPER, "ops at %p\n", ops); 183 } 184 185 if ( strlen(cache_type) == strlen("xfs") && 186 memcmp(cache_type, "xfs", strlen("xfs")) == 0 ) { 187 ops->o_trops = NULL; 188 FDEBUG(D_SUPER, "ops at %p\n", ops); 189 } 190 191 if ( strlen(cache_type) == strlen("obdfs") && 192 memcmp(cache_type, "obdfs", strlen("obdfs")) == 0 ) { 193#if defined(CONFIG_OBDFS_FS) || defined(CONFIG_OBDFS_FS_MODULE) 194 ops->o_trops = presto_obdfs_journal_ops; 195#else 196 ops->o_trops = NULL; 197#endif 198 FDEBUG(D_SUPER, "ops at %p\n", ops); 199 } 200} 201 202 203/* find the cache for this FS */ 204struct filter_fs *filter_get_filter_fs(const char *cache_type) 205{ 206 struct filter_fs *ops = NULL; 207 FENTRY; 208 209 if ( strlen(cache_type) == strlen("ext2") && 210 memcmp(cache_type, "ext2", strlen("ext2")) == 0 ) { 211 ops = &filter_oppar[FILTER_FS_EXT2]; 212 FDEBUG(D_SUPER, "ops at %p\n", ops); 213 } 214 215 if ( strlen(cache_type) == strlen("xfs") && 216 memcmp(cache_type, "xfs", strlen("xfs")) == 0 ) { 217 ops = &filter_oppar[FILTER_FS_XFS]; 218 FDEBUG(D_SUPER, "ops at %p\n", ops); 219 } 220 221 if ( strlen(cache_type) == strlen("ext3") && 222 memcmp(cache_type, "ext3", strlen("ext3")) == 0 ) { 223 ops = &filter_oppar[FILTER_FS_EXT3]; 224 FDEBUG(D_SUPER, "ops at %p\n", ops); 225 } 226 227 if ( strlen(cache_type) == strlen("tmpfs") && 228 memcmp(cache_type, "tmpfs", strlen("tmpfs")) == 0 ) { 229 ops = &filter_oppar[FILTER_FS_TMPFS]; 230 FDEBUG(D_SUPER, "ops at %p\n", ops); 231 } 232 233 if ( strlen(cache_type) == strlen("reiserfs") && 234 memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) { 235 ops = &filter_oppar[FILTER_FS_REISERFS]; 236 FDEBUG(D_SUPER, "ops at %p\n", ops); 237 } 238 if ( strlen(cache_type) == strlen("obdfs") && 239 memcmp(cache_type, "obdfs", strlen("obdfs")) == 0 ) { 240 ops = &filter_oppar[FILTER_FS_OBDFS]; 241 FDEBUG(D_SUPER, "ops at %p\n", ops); 242 } 243 244 if (ops == NULL) { 245 CERROR("prepare to die: unrecognized cache type for Filter\n"); 246 } 247 return ops; 248 FEXIT; 249} 250 251 252/* 253 * Frobnicate the InterMezzo operations 254 * this establishes the link between the InterMezzo file system 255 * and the underlying file system used for the cache. 256 */ 257 258void filter_setup_super_ops(struct filter_fs *cache, struct super_operations *cache_sops, struct super_operations *filter_sops) 259{ 260 /* Get ptr to the shared struct snapfs_ops structure. */ 261 struct filter_ops *props = &cache->o_fops; 262 /* Get ptr to the shared struct cache_ops structure. */ 263 struct cache_ops *caops = &cache->o_caops; 264 265 FENTRY; 266 267 if ( cache->o_flags & FILTER_DID_SUPER_OPS ) { 268 FEXIT; 269 return; 270 } 271 cache->o_flags |= FILTER_DID_SUPER_OPS; 272 273 /* Set the cache superblock operations to point to the 274 superblock operations of the underlying file system. */ 275 caops->cache_sops = cache_sops; 276 277 /* 278 * Copy the cache (real fs) superblock ops to the "filter" 279 * superblock ops as defaults. Some will be changed below 280 */ 281 memcpy(&props->filter_sops, cache_sops, sizeof(*cache_sops)); 282 283 /* 'put_super' unconditionally is that of filter */ 284 if (filter_sops->put_super) { 285 props->filter_sops.put_super = filter_sops->put_super; 286 } 287 288 if (cache_sops->read_inode) { 289 props->filter_sops.read_inode = filter_sops->read_inode; 290 FDEBUG(D_INODE, "setting filter_read_inode, cache_ops %p, cache %p, ri at %p\n", 291 cache, cache, props->filter_sops.read_inode); 292 } 293 294 if (cache_sops->remount_fs) 295 props->filter_sops.remount_fs = filter_sops->remount_fs; 296 FEXIT; 297} 298 299 300void filter_setup_dir_ops(struct filter_fs *cache, struct inode *inode, struct inode_operations *filter_iops, struct file_operations *filter_fops) 301{ 302 struct inode_operations *cache_filter_iops; 303 struct inode_operations *cache_iops = inode->i_op; 304 struct file_operations *cache_fops = inode->i_fop; 305 FENTRY; 306 307 if ( cache->o_flags & FILTER_DID_DIR_OPS ) { 308 FEXIT; 309 return; 310 } 311 cache->o_flags |= FILTER_DID_DIR_OPS; 312 313 /* former ops become cache_ops */ 314 cache->o_caops.cache_dir_iops = cache_iops; 315 cache->o_caops.cache_dir_fops = cache_fops; 316 FDEBUG(D_SUPER, "filter at %p, cache iops %p, iops %p\n", 317 cache, cache_iops, filter_c2udiops(cache)); 318 319 /* setup our dir iops: copy and modify */ 320 memcpy(filter_c2udiops(cache), cache_iops, sizeof(*cache_iops)); 321 322 /* abbreviate */ 323 cache_filter_iops = filter_c2udiops(cache); 324 325 /* methods that filter if cache filesystem has these ops */ 326 if (cache_iops->lookup && filter_iops->lookup) 327 cache_filter_iops->lookup = filter_iops->lookup; 328 if (cache_iops->create && filter_iops->create) 329 cache_filter_iops->create = filter_iops->create; 330 if (cache_iops->link && filter_iops->link) 331 cache_filter_iops->link = filter_iops->link; 332 if (cache_iops->unlink && filter_iops->unlink) 333 cache_filter_iops->unlink = filter_iops->unlink; 334 if (cache_iops->mkdir && filter_iops->mkdir) 335 cache_filter_iops->mkdir = filter_iops->mkdir; 336 if (cache_iops->rmdir && filter_iops->rmdir) 337 cache_filter_iops->rmdir = filter_iops->rmdir; 338 if (cache_iops->symlink && filter_iops->symlink) 339 cache_filter_iops->symlink = filter_iops->symlink; 340 if (cache_iops->rename && filter_iops->rename) 341 cache_filter_iops->rename = filter_iops->rename; 342 if (cache_iops->mknod && filter_iops->mknod) 343 cache_filter_iops->mknod = filter_iops->mknod; 344 if (cache_iops->permission && filter_iops->permission) 345 cache_filter_iops->permission = filter_iops->permission; 346 if (cache_iops->getattr) 347 cache_filter_iops->getattr = filter_iops->getattr; 348 /*if (cache_iops->setattr)*/ 349 cache_filter_iops->setattr = filter_iops->setattr; 350#ifdef CONFIG_FS_EXT_ATTR 351 /* For now we assume that posix acls are handled through extended 352 * attributes. If this is not the case, we must explicitly trap 353 * posix_set_acl. SHP 354 */ 355 if (cache_iops->set_ext_attr && filter_iops->set_ext_attr) 356 cache_filter_iops->set_ext_attr = filter_iops->set_ext_attr; 357#endif 358 359 360 /* copy dir fops */ 361 memcpy(filter_c2udfops(cache), cache_fops, sizeof(*cache_fops)); 362 363 /* unconditional filtering operations */ 364 filter_c2udfops(cache)->ioctl = filter_fops->ioctl; 365 366 FEXIT; 367} 368 369 370void filter_setup_file_ops(struct filter_fs *cache, struct inode *inode, struct inode_operations *filter_iops, struct file_operations *filter_fops) 371{ 372 struct inode_operations *pr_iops; 373 struct inode_operations *cache_iops = inode->i_op; 374 struct file_operations *cache_fops = inode->i_fop; 375 FENTRY; 376 377 if ( cache->o_flags & FILTER_DID_FILE_OPS ) { 378 FEXIT; 379 return; 380 } 381 cache->o_flags |= FILTER_DID_FILE_OPS; 382 383 /* steal the old ops */ 384 /* former ops become cache_ops */ 385 cache->o_caops.cache_file_iops = cache_iops; 386 cache->o_caops.cache_file_fops = cache_fops; 387 388 /* abbreviate */ 389 pr_iops = filter_c2ufiops(cache); 390 391 /* setup our dir iops: copy and modify */ 392 memcpy(pr_iops, cache_iops, sizeof(*cache_iops)); 393 394 /* copy dir fops */ 395 CERROR("*** cache file ops at %p\n", cache_fops); 396 memcpy(filter_c2uffops(cache), cache_fops, sizeof(*cache_fops)); 397 398 /* assign */ 399 /* See comments above in filter_setup_dir_ops. SHP */ 400 /*if (cache_iops->setattr)*/ 401 pr_iops->setattr = filter_iops->setattr; 402 if (cache_iops->getattr) 403 pr_iops->getattr = filter_iops->getattr; 404 pr_iops->permission = filter_iops->permission; 405#ifdef CONFIG_FS_EXT_ATTR 406 /* For now we assume that posix acls are handled through extended 407 * attributes. If this is not the case, we must explicitly trap and 408 * posix_set_acl 409 */ 410 if (cache_iops->set_ext_attr && filter_iops->set_ext_attr) 411 pr_iops->set_ext_attr = filter_iops->set_ext_attr; 412#endif 413 414 415 /* unconditional filtering operations */ 416 filter_c2uffops(cache)->open = filter_fops->open; 417 filter_c2uffops(cache)->release = filter_fops->release; 418 filter_c2uffops(cache)->write = filter_fops->write; 419 filter_c2uffops(cache)->ioctl = filter_fops->ioctl; 420 421 FEXIT; 422} 423 424void filter_setup_symlink_ops(struct filter_fs *cache, struct inode *inode, struct inode_operations *filter_iops, struct file_operations *filter_fops) 425{ 426 struct inode_operations *pr_iops; 427 struct inode_operations *cache_iops = inode->i_op; 428 struct file_operations *cache_fops = inode->i_fop; 429 FENTRY; 430 431 if ( cache->o_flags & FILTER_DID_SYMLINK_OPS ) { 432 FEXIT; 433 return; 434 } 435 cache->o_flags |= FILTER_DID_SYMLINK_OPS; 436 437 /* steal the old ops */ 438 cache->o_caops.cache_sym_iops = cache_iops; 439 cache->o_caops.cache_sym_fops = cache_fops; 440 441 /* abbreviate */ 442 pr_iops = filter_c2usiops(cache); 443 444 /* setup our dir iops: copy and modify */ 445 memcpy(pr_iops, cache_iops, sizeof(*cache_iops)); 446 447 /* See comments above in filter_setup_dir_ops. SHP */ 448 /* if (cache_iops->setattr) */ 449 pr_iops->setattr = filter_iops->setattr; 450 if (cache_iops->getattr) 451 pr_iops->getattr = filter_iops->getattr; 452 453 /* assign */ 454 /* copy fops - careful for symlinks they might be NULL */ 455 if ( cache_fops ) { 456 memcpy(filter_c2usfops(cache), cache_fops, sizeof(*cache_fops)); 457 } 458 459 FEXIT; 460} 461 462void filter_setup_dentry_ops(struct filter_fs *cache, 463 struct dentry_operations *cache_dop, 464 struct dentry_operations *filter_dop) 465{ 466 if ( cache->o_flags & FILTER_DID_DENTRY_OPS ) { 467 FEXIT; 468 return; 469 } 470 cache->o_flags |= FILTER_DID_DENTRY_OPS; 471 472 cache->o_caops.cache_dentry_ops = cache_dop; 473 memcpy(&cache->o_fops.filter_dentry_ops, 474 filter_dop, sizeof(*filter_dop)); 475 476 if (cache_dop && cache_dop != filter_dop && cache_dop->d_revalidate){ 477 CERROR("WARNING: filter overriding revalidation!\n"); 478 } 479 return; 480} 481