void unionfs_reinterpose(struct dentry *dentry) { struct dentry *hidden_dentry; struct inode *inode; int bindex, bstart, bend; print_entry_location(); verify_locked(dentry); fist_print_dentry("IN: unionfs_reinterpose: ", dentry); /* This is pre-allocated inode */ inode = dentry->d_inode; bstart = dbstart(dentry); bend = dbend(dentry); for (bindex = bstart; bindex <= bend; bindex++) { hidden_dentry = dtohd_index(dentry, bindex); if (!hidden_dentry) continue; if (!hidden_dentry->d_inode) continue; if (itohi_index(inode, bindex)) continue; set_itohi_index(inode, bindex, IGRAB(hidden_dentry->d_inode)); } ibstart(inode) = dbstart(dentry); ibend(inode) = dbend(dentry); fist_print_dentry("OUT: unionfs_reinterpose: ", dentry); fist_print_inode("OUT: unionfs_reinterpose: ", inode); print_exit_location(); }
/* * we don't really need kdb3fs_d_iput, because dentry_iput will call iput() if * kdb3fs_d_iput is not defined. We left this implemented for ease of * tracing/debugging. */ void kdb3fs_d_iput(dentry_t *dentry, inode_t *inode) { print_entry_location(); iput(inode); print_exit_location(); }
STATIC void base0fs_vm_shared_unmap(vm_area_t *vma, unsigned long start, size_t len) { vm_area_t *lower_vma; file_t *file; file_t *lower_file = NULL; print_entry_location(); lower_vma = VMA_TO_LOWER(vma); file = vma->vm_file; if (FILE_TO_PRIVATE(file) != NULL) lower_file = FILE_TO_LOWER(file); BUG_ON(!lower_file); fist_dprint(6, "VM_S_UNMAP1: file 0x%x, lower_file 0x%x, file->f_count %d, lower_file->f_count %d\n", (int) file, (int) lower_file, (int) atomic_read(&file->f_count), (int) atomic_read(&lower_file->f_count)); /* * call sync (filemap_sync) because the default filemap_unmap * calls it too. */ filemap_sync(vma, start, len, MS_ASYNC); if (lower_vma->vm_ops->unmap) lower_vma->vm_ops->unmap(lower_vma, start, len); fist_dprint(6, "VM_S_UNMAP2: file 0x%x, lower_file 0x%x, file->f_count %d, lower_file->f_count %d\n", (int) file, (int) lower_file, (int) atomic_read(&file->f_count), (int) atomic_read(&lower_file->f_count)); print_exit_location(); }
/* final actions when unmounting a file system */ static void unionfs_put_super(struct super_block *sb) { int bindex, bstart, bend; struct unionfs_sb_info *spd; print_entry_location(); if ((spd = stopd(sb))) { /* XXX: Free persistent inode stuff. */ bstart = sbstart(sb); bend = sbend(sb); for (bindex = bstart; bindex <= bend; bindex++) mntput(stohiddenmnt_index(sb, bindex)); /* Make sure we have no leaks of branchget/branchput. */ for (bindex = bstart; bindex <= bend; bindex++) ASSERT(branch_count(sb, bindex) == 0); KFREE(stohs_ptr(sb)); KFREE(stohiddenmnt_ptr(sb)); KFREE(spd->usi_sbcount_p); KFREE(spd->usi_branchperms_p); KFREE(spd->usi_putmaps); KFREE(spd); stopd_lhs(sb) = NULL; } fist_dprint(6, "unionfs: released super\n"); print_exit_location(); }
void kdb3fs_d_release(dentry_t *dentry) { dentry_t *hidden_dentry; print_entry_location(); #if 0 fist_print_dentry("kdb3fs_d_release IN dentry", dentry); /* this could be a negative dentry, so check first */ if (!dtopd(dentry)) { fist_dprint(6, "dentry without private data: %*s", dentry->d_name.len, dentry->d_name.name); goto out; } hidden_dentry = dtohd(dentry); fist_print_dentry("kdb3fs_d_release IN hidden_dentry", hidden_dentry); if (hidden_dentry->d_inode) fist_dprint(6, "kdb3fs_d_release: hidden_inode->i_count %d, i_num %lu.\n", atomic_read(&hidden_dentry->d_inode->i_count), hidden_dentry->d_inode->i_ino); /* free private data (kdb3fs_dentry_info) here */ KFREE(dtopd(dentry)); dtopd(dentry) = NULL; /* just to be safe */ /* decrement hidden dentry's counter and free its inode */ dput(hidden_dentry); #endif out: print_exit_location(); }
STATIC void base0fs_vm_close(vm_area_t *vma) { vm_area_t *lower_vma; file_t *file; file_t *lower_file = NULL; print_entry_location(); lower_vma = VMA_TO_LOWER(vma); file = vma->vm_file; if (FILE_TO_PRIVATE(file) != NULL) lower_file = FILE_TO_LOWER(file); BUG_ON(!lower_file); fist_dprint(6, "VM_CLOSE1: file 0x%x, lower_file 0x%x, file->f_count %d, lower_file->f_count %d\n", (int) file, (int) lower_file, (int) atomic_read(&file->f_count), (int) atomic_read(&lower_file->f_count)); BUG_ON(!lower_vma); if (lower_vma->vm_ops->close) lower_vma->vm_ops->close(lower_vma); fput(lower_file); KFREE(lower_vma); VMA_TO_LOWER(vma) = NULL; fist_dprint(6, "VM_CLOSE2: file 0x%x, lower_file 0x%x, file->f_count %d, lower_file->f_count %d\n", (int) file, (int) lower_file, (int) atomic_read(&file->f_count), (int) atomic_read(&lower_file->f_count)); print_exit_location(); }
void unionfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) #endif { char *link; print_entry_location(); link = nd_get_link(nd); KFREE(link); print_exit_location(); }
/* * we now define delete_inode, because there are two VFS paths that may * destroy an inode: one of them calls clear inode before doing everything * else that's needed, and the other is fine. This way we truncate the inode * size (and its pages) and then clear our own inode, which will do an iput * on our and the lower inode. */ static void unionfs_delete_inode(struct inode *inode) { print_entry_location(); fist_checkinode(inode, "unionfs_delete_inode IN"); inode->i_size = 0; /* every f/s seems to do that */ clear_inode(inode); print_exit_location(); }
/* buf is allocated here, and freed when VFS calls our put_link method */ err = -ENOMEM; buf = KMALLOC(len, GFP_KERNEL); if (!buf) goto out; old_fs = get_fs(); set_fs(KERNEL_DS); err = dentry->d_inode->i_op->readlink(dentry, buf, len); set_fs(old_fs); if (err < 0) goto out_free; buf[err] = 0; // terminate the buffer -- XXX still needed? err = 0; nd_set_link(nd,buf); goto out; out_free: KFREE(buf); out: #if 0 if (err < 0) { dput(nd->dentry); printk("EZK follow_link() mnt_cnt %d\n", (int) atomic_read(&nd->mnt->mnt_count)); mntput(nd->mnt); } #endif print_exit_status(err); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) return err; #else /* 2.6.13 or newer */ return ERR_PTR(err); #endif /* 2.6.13 or newer */ } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) void base0fs_put_link(struct dentry *dentry, struct nameidata *nd) #else /* 2.6.13 or newer */ void base0fs_put_link(struct dentry *dentry, struct nameidata *nd, void* unused) #endif /* 2.6.13 or newer */ { print_entry_location(); KFREE(nd_get_link(nd)); print_exit_location(); }
/* * we now define delete_inode, because there are two VFS paths that may * destroy an inode: one of them calls clear inode before doing everything * else that's needed, and the other is fine. This way we truncate the inode * size (and its pages) and then clear our own inode, which will do an iput * on our and the lower inode. */ STATIC void mini_fo_delete_inode(inode_t *inode) { print_entry_location(); fist_checkinode(inode, "mini_fo_delete_inode IN"); inode->i_size = 0; /* every f/s seems to do that */ clear_inode(inode); print_exit_location(); }
/* This function replicates the directory structure upto given dentry * in the bindex branch. Can create directory structure recursively to the right * also. */ struct dentry *create_parents(struct inode *dir, struct dentry *dentry, int bindex) { struct dentry *hidden_dentry; print_entry_location(); hidden_dentry = create_parents_named(dir, dentry, dentry->d_name.name, bindex); print_exit_location(); return (hidden_dentry); }
void unionfs_d_release(struct dentry *dentry) { struct dentry *hidden_dentry; int bindex, bstart, bend; print_entry_location(); /* There is no reason to lock the dentry, because we have the only * reference, but the printing functions verify that we have a lock * on the dentry before calling dbstart, etc. */ lock_dentry(dentry); __fist_print_dentry("unionfs_d_release IN dentry", dentry, 0); /* this could be a negative dentry, so check first */ if (!dtopd(dentry)) { fist_dprint(6, "dentry without private data: %*s", dentry->d_name.len, dentry->d_name.name); goto out; } else if (dbstart(dentry) < 0) { /* this is due to a failed lookup */ /* the failed lookup has a dtohd_ptr set to null, but this is a better check */ fist_dprint(6, "dentry without hidden dentries : %*s", dentry->d_name.len, dentry->d_name.name); goto out_free; } /* Release all the hidden dentries */ bstart = dbstart(dentry); bend = dbend(dentry); for (bindex = bstart; bindex <= bend; bindex++) { hidden_dentry = dtohd_index(dentry, bindex); DPUT(hidden_dentry); set_dtohd_index(dentry, bindex, NULL); } /* free private data (unionfs_dentry_info) here */ KFREE(dtohd_ptr(dentry)); dtohd_ptr(dentry) = NULL; out_free: /* No need to unlock it, because it is disappeared. */ #ifdef TRACKLOCK printk("DESTROYLOCK:%p\n", dentry); #endif free_dentry_private_data(dtopd(dentry)); dtopd_lhs(dentry) = NULL; /* just to be safe */ out: print_exit_location(); }
static void unionfs_read_inode(struct inode *inode) { static struct address_space_operations unionfs_empty_aops; print_entry_location(); if (!itopd(inode)) { FISTBUG ("No kernel memory when allocating inode private data!\n"); } PASSERT(inode->i_sb); memset(itopd(inode), 0, sizeof(struct unionfs_inode_info)); itopd(inode)->b_start = -1; itopd(inode)->b_end = -1; atomic_set(&itopd(inode)->uii_generation, atomic_read(&stopd(inode->i_sb)->usi_generation)); itopd(inode)->uii_rdlock = SPIN_LOCK_UNLOCKED; itopd(inode)->uii_rdcount = 1; itopd(inode)->uii_hashsize = -1; INIT_LIST_HEAD(&itopd(inode)->uii_readdircache); if (sbmax(inode->i_sb) > UNIONFS_INLINE_OBJECTS) { int size = (sbmax(inode->i_sb) - UNIONFS_INLINE_OBJECTS) * sizeof(struct inode *); itohi_ptr(inode) = KMALLOC(size, GFP_UNIONFS); if (!itohi_ptr(inode)) { FISTBUG ("No kernel memory when allocating lower-pointer array!\n"); } memset(itohi_ptr(inode), 0, size); } memset(itohi_inline(inode), 0, UNIONFS_INLINE_OBJECTS * sizeof(struct inode *)); inode->i_version++; inode->i_op = &unionfs_main_iops; inode->i_fop = &unionfs_main_fops; /* I don't think ->a_ops is ever allowed to be NULL */ inode->i_mapping->a_ops = &unionfs_empty_aops; fist_dprint(7, "setting inode 0x%p a_ops to empty (0x%p)\n", inode, inode->i_mapping->a_ops); print_exit_location(); }
static void unionfs_put_inode(struct inode *inode) { print_entry_location(); fist_dprint(8, "%s i_count = %d, i_nlink = %d\n", __FUNCTION__, atomic_read(&inode->i_count), inode->i_nlink); /* * This is really funky stuff: * Basically, if i_count == 1, iput will then decrement it and this inode will be destroyed. * It is currently holding a reference to the hidden inode. * Therefore, it needs to release that reference by calling iput on the hidden inode. * iput() _will_ do it for us (by calling our clear_inode), but _only_ if i_nlink == 0. * The problem is, NFS keeps i_nlink == 1 for silly_rename'd files. * So we must for our i_nlink to 0 here to trick iput() into calling our clear_inode. */ if (atomic_read(&inode->i_count) == 1) inode->i_nlink = 0; print_exit_location(); }
STATIC void base0fs_vm_open(vm_area_t *vma) { vm_area_t *lower_vma, *lower_vma2; file_t *file; file_t *lower_file = NULL; print_entry_location(); lower_vma = VMA_TO_LOWER(vma); file = vma->vm_file; if (FILE_TO_PRIVATE(file) != NULL) lower_file = FILE_TO_LOWER(file); BUG_ON(!lower_file); fist_dprint(6, "VM_OPEN: file 0x%x, lower_file 0x%x, file->f_count %d, lower_file->f_count %d\n", (int) file, (int) lower_file, (int) atomic_read(&file->f_count), (int) atomic_read(&lower_file->f_count)); if (lower_vma->vm_ops->open) lower_vma->vm_ops->open(lower_vma); atomic_inc(&lower_file->f_count); /* we need to duplicate the private data */ lower_vma2 = KMALLOC(sizeof(vm_area_t), GFP_KERNEL); if (!lower_vma2) { printk("VM_OPEN: Out of memory\n"); goto out; } memcpy(lower_vma2, lower_vma, sizeof(vm_area_t)); VMA_TO_LOWER(vma) = lower_vma2; out: fist_dprint(6, "VM_OPEN2: file 0x%x, lower_file 0x%x, file->f_count %d, lower_file->f_count %d\n", (int) file, (int) lower_file, (int) atomic_read(&file->f_count), (int) atomic_read(&lower_file->f_count)); print_exit_location(); }
static void fixputmaps(struct super_block *sb) { struct unionfs_sb_info *spd; struct putmap *cur; int gen; int i; print_entry_location(); spd = stopd(sb); cur = spd->usi_putmaps[spd->usi_lastputmap - spd->usi_firstputmap]; for (gen = 0; gen < spd->usi_lastputmap - spd->usi_firstputmap; gen++) { if (!spd->usi_putmaps[gen]) continue; for (i = 0; i <= spd->usi_putmaps[gen]->bend; i++) spd->usi_putmaps[gen]->map[i] = cur->map[spd->usi_putmaps[gen]->map[i]]; } print_exit_location(); }
/* * we don't really need unionfs_d_iput, because dentry_iput will call iput() if * unionfs_d_iput is not defined. We left this implemented for ease of * tracing/debugging. */ void unionfs_d_iput(struct dentry *dentry, struct inode *inode) { print_entry_location(); IPUT(inode); print_exit_location(); }
/* * Parse mount options. See the manual page for usage instructions. * * Returns the dentry object of the lower-level (hidden) directory; * We want to mount our stackable file system on top of that hidden directory. * * Sets default debugging level to N, if any. */ static struct unionfs_dentry_info *unionfs_parse_options(struct super_block *sb, char *options) { struct unionfs_dentry_info *hidden_root_info; char *optname; int err = 0; int bindex; int dirsfound = 0; #ifdef UNIONFS_IMAP int imapfound = 0; #endif print_entry_location(); /* allocate private data area */ err = -ENOMEM; hidden_root_info = KZALLOC(sizeof(struct unionfs_dentry_info), GFP_KERNEL); if (!hidden_root_info) goto out_error; hidden_root_info->udi_bstart = -1; hidden_root_info->udi_bend = -1; hidden_root_info->udi_bopaque = -1; while ((optname = strsep(&options, ",")) != NULL) { char *optarg; char *endptr; int intval; if (!*optname) { continue; } optarg = strchr(optname, '='); if (optarg) { *optarg++ = '\0'; } /* All of our options take an argument now. Insert ones that * don't, above this check. */ if (!optarg) { printk("unionfs: %s requires an argument.\n", optname); err = -EINVAL; goto out_error; } if (!strcmp("dirs", optname)) { if (++dirsfound > 1) { printk(KERN_WARNING "unionfs: multiple dirs specified\n"); err = -EINVAL; goto out_error; } err = parse_dirs_option(sb, hidden_root_info, optarg); if (err) goto out_error; continue; } #ifdef UNIONFS_IMAP if (!strcmp("imap", optname)) { if (++imapfound > 1) { printk(KERN_WARNING "unionfs: multiple imap specified\n"); err = -EINVAL; goto out_error; } err = parse_imap_option(sb, hidden_root_info, optarg); if (err) goto out_error; continue; } #endif if (!strcmp("delete", optname)) { if (!strcmp("whiteout", optarg)) { /* default */ #ifdef UNIONFS_DELETE_ALL } else if (!strcmp("all", optarg)) { MOUNT_FLAG(sb) |= DELETE_ALL; #endif } else { printk(KERN_WARNING "unionfs: invalid delete option '%s'\n", optarg); err = -EINVAL; goto out_error; } continue; } if (!strcmp("copyup", optname)) { if (!strcmp("preserve", optarg)) { /* default */ } else if (!strcmp("currentuser", optarg)) { MOUNT_FLAG(sb) |= COPYUP_CURRENT_USER; } else { printk(KERN_WARNING "unionfs: could not parse copyup option value '%s'\n", optarg); err = -EINVAL; goto out_error; } continue; } /* All of these options require an integer argument. */ intval = simple_strtoul(optarg, &endptr, 0); if (*endptr) { printk(KERN_WARNING "unionfs: invalid %s option '%s'\n", optname, optarg); err = -EINVAL; goto out_error; } if (!strcmp("debug", optname)) { fist_set_debug_value(intval); continue; } err = -EINVAL; printk(KERN_WARNING "unionfs: unrecognized option '%s'\n", optname); goto out_error; } if (dirsfound != 1) { printk(KERN_WARNING "unionfs: dirs option required\n"); err = -EINVAL; goto out_error; } goto out; out_error: if (hidden_root_info && hidden_root_info->udi_dentry) { for (bindex = hidden_root_info->udi_bstart; bindex >= 0 && bindex <= hidden_root_info->udi_bend; bindex++) { struct dentry *d; d = hidden_root_info->udi_dentry[bindex]; DPUT(d); if (stohiddenmnt_index(sb, bindex)) mntput(stohiddenmnt_index(sb, bindex)); } } KFREE(hidden_root_info->udi_dentry); KFREE(hidden_root_info); KFREE(stopd(sb)->usi_data); stopd(sb)->usi_data = NULL; hidden_root_info = ERR_PTR(err); out: print_exit_location(); return hidden_root_info; }
/* * No need to call write_inode() on the lower inode, as it * will have been marked 'dirty' anyway. But we might need * to write some of our own stuff to disk. */ STATIC void mini_fo_write_inode(inode_t *inode, int sync) { print_entry_location(); print_exit_location(); }