void presto_set_ops(struct inode *inode, struct filter_fs *filter) { ENTRY; if (!inode || is_bad_inode(inode)) return; if (inode->i_gid == presto_excluded_gid ) { EXIT; CDEBUG(D_INODE, "excluded methods for %ld at %p, %p\n", inode->i_ino, inode->i_op, inode->i_fop); return; } if (S_ISREG(inode->i_mode)) { if ( !filter_c2cfiops(filter) ) { filter_setup_file_ops(filter, inode, &presto_file_iops, &presto_file_fops); } inode->i_op = filter_c2ufiops(filter); inode->i_fop = filter_c2uffops(filter); CDEBUG(D_INODE, "set file methods for %ld to %p\n", inode->i_ino, inode->i_op); } else if (S_ISDIR(inode->i_mode)) { inode->i_op = filter_c2udiops(filter); inode->i_fop = filter_c2udfops(filter); CDEBUG(D_INODE, "set dir methods for %ld to %p lookup %p\n", inode->i_ino, inode->i_op, inode->i_op->lookup); } else if (S_ISLNK(inode->i_mode)) { if ( !filter_c2csiops(filter)) { filter_setup_symlink_ops(filter, inode, &presto_sym_iops, &presto_sym_fops); } inode->i_op = filter_c2usiops(filter); inode->i_fop = filter_c2usfops(filter); CDEBUG(D_INODE, "set link methods for %ld to %p\n", inode->i_ino, inode->i_op); } EXIT; }
void filter_setup_dir_ops(struct filter_fs *cache, struct inode *inode, struct inode_operations *filter_iops, struct file_operations *filter_fops) { struct inode_operations *cache_filter_iops; struct inode_operations *cache_iops = inode->i_op; struct file_operations *cache_fops = inode->i_fop; FENTRY; if ( cache->o_flags & FILTER_DID_DIR_OPS ) { FEXIT; return; } cache->o_flags |= FILTER_DID_DIR_OPS; /* former ops become cache_ops */ cache->o_caops.cache_dir_iops = cache_iops; cache->o_caops.cache_dir_fops = cache_fops; FDEBUG(D_SUPER, "filter at %p, cache iops %p, iops %p\n", cache, cache_iops, filter_c2udiops(cache)); /* setup our dir iops: copy and modify */ memcpy(filter_c2udiops(cache), cache_iops, sizeof(*cache_iops)); /* abbreviate */ cache_filter_iops = filter_c2udiops(cache); /* methods that filter if cache filesystem has these ops */ if (cache_iops->lookup && filter_iops->lookup) cache_filter_iops->lookup = filter_iops->lookup; if (cache_iops->create && filter_iops->create) cache_filter_iops->create = filter_iops->create; if (cache_iops->link && filter_iops->link) cache_filter_iops->link = filter_iops->link; if (cache_iops->unlink && filter_iops->unlink) cache_filter_iops->unlink = filter_iops->unlink; if (cache_iops->mkdir && filter_iops->mkdir) cache_filter_iops->mkdir = filter_iops->mkdir; if (cache_iops->rmdir && filter_iops->rmdir) cache_filter_iops->rmdir = filter_iops->rmdir; if (cache_iops->symlink && filter_iops->symlink) cache_filter_iops->symlink = filter_iops->symlink; if (cache_iops->rename && filter_iops->rename) cache_filter_iops->rename = filter_iops->rename; if (cache_iops->mknod && filter_iops->mknod) cache_filter_iops->mknod = filter_iops->mknod; if (cache_iops->permission && filter_iops->permission) cache_filter_iops->permission = filter_iops->permission; if (cache_iops->getattr) cache_filter_iops->getattr = filter_iops->getattr; /* Some filesystems do not use a setattr method of their own instead relying on inode_setattr/write_inode. We still need to journal these so we make setattr an unconditional operation. XXX: we should probably check for write_inode. SHP */ /*if (cache_iops->setattr)*/ cache_filter_iops->setattr = filter_iops->setattr; #ifdef CONFIG_FS_EXT_ATTR /* For now we assume that posix acls are handled through extended * attributes. If this is not the case, we must explicitly trap * posix_set_acl. SHP */ if (cache_iops->set_ext_attr && filter_iops->set_ext_attr) cache_filter_iops->set_ext_attr = filter_iops->set_ext_attr; #endif /* copy dir fops */ memcpy(filter_c2udfops(cache), cache_fops, sizeof(*cache_fops)); /* unconditional filtering operations */ filter_c2udfops(cache)->ioctl = filter_fops->ioctl; FEXIT; }
/* We always need to remove the presto options before passing mount options to cache FS */ struct super_block * presto_read_super(struct super_block * sb, void * data, int silent) { struct file_system_type *fstype; struct presto_cache *cache = NULL; char *cache_data = NULL; char *cache_data_end; char *cache_type = NULL; char *fileset = NULL; char *channel = NULL; int err; unsigned int minor; ENTRY; /* reserve space for the cache's data */ PRESTO_ALLOC(cache_data, PAGE_SIZE); if ( !cache_data ) { CERROR("presto_read_super: Cannot allocate data page.\n"); EXIT; goto out_err; } /* read and validate options */ cache_data_end = presto_options(sb, data, cache_data, &cache_type, &fileset, &channel); /* was there anything for the cache filesystem in the data? */ if (cache_data_end == cache_data) { PRESTO_FREE(cache_data, PAGE_SIZE); cache_data = NULL; } else { CDEBUG(D_SUPER, "cache_data at %p is: %s\n", cache_data, cache_data); } /* set up the cache */ cache = presto_cache_init(); if ( !cache ) { CERROR("presto_read_super: failure allocating cache.\n"); EXIT; goto out_err; } cache->cache_type = cache_type; /* link cache to channel */ minor = presto_set_channel(cache, channel); if (minor < 0) { EXIT; goto out_err; } CDEBUG(D_SUPER, "Presto: type=%s, fset=%s, dev= %d, flags %x\n", cache_type, fileset?fileset:"NULL", minor, cache->cache_flags); MOD_INC_USE_COUNT; /* get the filter for the cache */ fstype = get_fs_type(cache_type); cache->cache_filter = filter_get_filter_fs((const char *)cache_type); if ( !fstype || !cache->cache_filter) { CERROR("Presto: unrecognized fs type or cache type\n"); MOD_DEC_USE_COUNT; EXIT; goto out_err; } /* can we in fact mount the cache */ if ((fstype->fs_flags & FS_REQUIRES_DEV) && !sb->s_bdev) { CERROR("filesystem \"%s\" requires a valid block device\n", cache_type); MOD_DEC_USE_COUNT; EXIT; goto out_err; } sb = fstype->read_super(sb, cache_data, silent); /* this might have been freed above */ if (cache_data) { PRESTO_FREE(cache_data, PAGE_SIZE); cache_data = NULL; } if ( !sb ) { CERROR("InterMezzo: cache mount failure.\n"); MOD_DEC_USE_COUNT; EXIT; goto out_err; } cache->cache_sb = sb; cache->cache_root = dget(sb->s_root); /* we now know the dev of the cache: hash the cache */ presto_cache_add(cache, sb->s_dev); err = izo_prepare_fileset(sb->s_root, fileset); filter_setup_journal_ops(cache->cache_filter, cache->cache_type); /* make sure we have our own super operations: sb still contains the cache operations */ filter_setup_super_ops(cache->cache_filter, sb->s_op, &presto_super_ops); sb->s_op = filter_c2usops(cache->cache_filter); /* get izo directory operations: sb->s_root->d_inode exists now */ filter_setup_dir_ops(cache->cache_filter, sb->s_root->d_inode, &presto_dir_iops, &presto_dir_fops); filter_setup_dentry_ops(cache->cache_filter, sb->s_root->d_op, &presto_dentry_ops); sb->s_root->d_inode->i_op = filter_c2udiops(cache->cache_filter); sb->s_root->d_inode->i_fop = filter_c2udfops(cache->cache_filter); sb->s_root->d_op = filter_c2udops(cache->cache_filter); EXIT; return sb; out_err: CDEBUG(D_SUPER, "out_err called\n"); if (cache) PRESTO_FREE(cache, sizeof(struct presto_cache)); if (cache_data) PRESTO_FREE(cache_data, PAGE_SIZE); if (fileset) PRESTO_FREE(fileset, strlen(fileset) + 1); if (channel) PRESTO_FREE(channel, strlen(channel) + 1); if (cache_type) PRESTO_FREE(cache_type, strlen(cache_type) + 1); CDEBUG(D_MALLOC, "mount error exit: kmem %ld, vmem %ld\n", presto_kmemory, presto_vmemory); return NULL; }