static struct izo_upcall_hdr *upc_pack(__u32 opcode, int pathlen, char *path, char *fsetname, int reclen, char *rec, int *size) { struct izo_upcall_hdr *hdr; char *ptr; ENTRY; *size = sizeof(struct izo_upcall_hdr); if ( fsetname ) { *size += round_strlen(fsetname); } if ( path ) { *size += round_strlen(path); } if ( rec ) { *size += size_round(reclen); } PRESTO_ALLOC(hdr, *size); if (!hdr) { CERROR("intermezzo upcall: out of memory (opc %d)\n", opcode); EXIT; return NULL; } memset(hdr, 0, *size); ptr = (char *)hdr + sizeof(*hdr); /* XXX do we need fsuid ? */ hdr->u_len = *size; hdr->u_version = IZO_UPC_VERSION; hdr->u_opc = opcode; hdr->u_pid = current->pid; hdr->u_uid = current->fsuid; if (path) { /*XXX Robert: please review what len to pass in for NUL terminated strings */ hdr->u_pathlen = strlen(path); LOGL0(path, hdr->u_pathlen, ptr); } if (fsetname) { hdr->u_fsetlen = strlen(fsetname); LOGL0(fsetname, strlen(fsetname), ptr); } if (rec) { hdr->u_reclen = reclen; LOGL(rec, reclen, ptr); } EXIT; return hdr; }
/* talk to Lento about the permit */ static int presto_permit_upcall(struct dentry *dentry) { int rc; char *path, *buffer; int pathlen; int minor; int fsetnamelen; struct presto_file_set *fset = NULL; ENTRY; if ( (minor = presto_i2m(dentry->d_inode)) < 0) { EXIT; return -EINVAL; } fset = presto_fset(dentry); if (!fset) { EXIT; return -ENOTCONN; } if ( !presto_lento_up(minor) ) { if ( fset->fset_flags & FSET_STEAL_PERMIT ) { EXIT; return 0; } else { EXIT; return -ENOTCONN; } } PRESTO_ALLOC(buffer, PAGE_SIZE); if ( !buffer ) { CERROR("PRESTO: out of memory!\n"); EXIT; return -ENOMEM; } path = presto_path(dentry, fset->fset_dentry, buffer, PAGE_SIZE); pathlen = MYPATHLEN(buffer, path); fsetnamelen = strlen(fset->fset_name); rc = izo_upc_permit(minor, dentry, pathlen, path, fset->fset_name); PRESTO_FREE(buffer, PAGE_SIZE); EXIT; return rc; }
static void opt_set_default(char **dst, char *defval) { if (!dst) CERROR("intermezzo: store_opt, error dst == NULL\n"); if (*dst) PRESTO_FREE(*dst, strlen(*dst) + 1); if (defval) { char *def_alloced; PRESTO_ALLOC(def_alloced, strlen(defval)+1); if (!def_alloced) { CERROR("InterMezzo: Out of memory!\n"); return ; } strcpy(def_alloced, defval); *dst = def_alloced; } }
/* returns an allocated string, copied out from data if opt is found */ static char *opt_read(const char *opt, char *data) { char *value; char *retval; CDEBUG(D_SUPER, "option: %s, data %s\n", opt, data); if ( strncmp(opt, data, strlen(opt)) ) return NULL; if ( (value = strchr(data, '=')) == NULL ) return NULL; value++; PRESTO_ALLOC(retval, strlen(value) + 1); if ( !retval ) { CERROR("InterMezzo: Out of memory!\n"); return NULL; } strcpy(retval, value); CDEBUG(D_SUPER, "Assigned option: %s, value %s\n", opt, retval); return retval; }
/* allocate the tables for the presto devices. We need * sizeof(proto_channel_table)/sizeof(proto_channel_table[0]) * entries for each dev */ int /* __init */ init_intermezzo_sysctl(void) { int i; int total_dev = MAX_CHANNEL; int entries_per_dev = sizeof(proto_psdev_table) / sizeof(proto_psdev_table[0]); int total_entries = entries_per_dev * total_dev; ctl_table *dev_ctl_table; PRESTO_ALLOC(dev_ctl_table, sizeof(ctl_table) * total_entries); if (! dev_ctl_table) { CERROR("WARNING: presto couldn't allocate dev_ctl_table\n"); EXIT; return -ENOMEM; } /* now fill in the entries ... we put the individual presto<x> * entries at the end of the table, and the per-presto stuff * starting at the front. We assume that the compiler makes * this code more efficient, but really, who cares ... it * happens once per reboot. */ for(i = 0; i < total_dev; i++) { void *p; /* entry for this /proc/sys/intermezzo/intermezzo"i" */ ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT]; /* entries for the individual "files" in this "directory" */ ctl_table *psdev_entries = &dev_ctl_table[i * entries_per_dev]; /* init the psdev and psdev_entries with the prototypes */ *psdev = proto_channel_entry; memcpy(psdev_entries, proto_psdev_table, sizeof(proto_psdev_table)); /* now specialize them ... */ /* the psdev has to point to psdev_entries, and fix the number */ psdev->ctl_name = psdev->ctl_name + i + 1; /* sorry */ PRESTO_ALLOC(p, PROCNAME_SIZE); psdev->procname = p; if (!psdev->procname) { PRESTO_FREE(dev_ctl_table, sizeof(ctl_table) * total_entries); return -ENOMEM; } sprintf((char *) psdev->procname, "intermezzo%d", i); /* hook presto into */ psdev->child = psdev_entries; /* now for each psdev entry ... */ psdev_entries[0].data = &(izo_channels[i].uc_hard); psdev_entries[1].data = &(izo_channels[i].uc_no_filter); psdev_entries[2].data = &(izo_channels[i].uc_no_journal); psdev_entries[3].data = &(izo_channels[i].uc_no_upcall); psdev_entries[4].data = &(izo_channels[i].uc_timeout); #ifdef PRESTO_DEBUG psdev_entries[5].data = &(izo_channels[i].uc_errorval); #endif } #ifdef CONFIG_SYSCTL if ( !intermezzo_table_header ) intermezzo_table_header = register_sysctl_table(intermezzo_table, 0); #endif #ifdef CONFIG_PROC_FS proc_fs_intermezzo = proc_mkdir("intermezzo", proc_root_fs); proc_fs_intermezzo->owner = THIS_MODULE; create_proc_info_entry("mounts", 0, proc_fs_intermezzo, intermezzo_mount_get_info); #endif return 0; }
/* 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; }
/* XXX! Fixme test for user defined attributes */ int presto_set_ext_attr(struct inode *inode, const char *name, void *buffer, size_t buffer_len, int flags) { int error; struct presto_cache *cache; struct presto_file_set *fset; struct lento_vfs_context info; struct dentry *dentry; int minor = presto_i2m(inode); char *buf = NULL; ENTRY; if (minor < 0) { EXIT; return -1; } if ( ISLENTO(minor) ) { EXIT; return -EINVAL; } /* BAD...vfs should really pass down the dentry to use, especially * since every other operation in iops does. But for now * we do a reverse mapping from inode to the first dentry */ if (list_empty(&inode->i_dentry)) { CERROR("No alias for inode %d\n", (int) inode->i_ino); EXIT; return -EINVAL; } dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias); error = presto_prep(dentry, &cache, &fset); if ( error ) { EXIT; return error; } if ((buffer != NULL) && (buffer_len != 0)) { /* If buffer is a user space pointer copy it to kernel space * and reset the flag. We do this since the journal functions need * access to the contents of the buffer, and the file system * does not care. When we actually invoke the function, we remove * the EXT_ATTR_FLAG_USER flag. * * XXX:Check if the "fs does not care" assertion is always true -SHP * (works for ext3) */ if (flags & EXT_ATTR_FLAG_USER) { PRESTO_ALLOC(buf, buffer_len); if (!buf) { CERROR("InterMezzo: out of memory!!!\n"); return -ENOMEM; } error = copy_from_user(buf, buffer, buffer_len); if (error) return -EFAULT; } else buf = buffer; } else buf = buffer; if ( presto_get_permit(inode) < 0 ) { EXIT; if (buffer_len && (flags & EXT_ATTR_FLAG_USER)) PRESTO_FREE(buf, buffer_len); return -EROFS; } /* Simulate presto_setup_info */ memset(&info, 0, sizeof(info)); /* For now redundant..but we keep it around just in case */ info.flags = LENTO_FL_IGNORE_TIME; if (!ISLENTO(cache->cache_psdev->uc_minor)) info.flags |= LENTO_FL_KML; /* We pass in the kernel space pointer and reset the * EXT_ATTR_FLAG_USER flag. * See comments above. */ /* Note that mode is already set by VFS so we send in a NULL */ error = presto_do_set_ext_attr(fset, dentry, name, buf, buffer_len, flags & ~EXT_ATTR_FLAG_USER, NULL, &info); presto_put_permit(inode); if (buffer_len && (flags & EXT_ATTR_FLAG_USER)) PRESTO_FREE(buf, buffer_len); EXIT; return error; }