struct dentry *wrapfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct dentry *ret, *parent; struct path lower_parent_path; int err = 0; BUG_ON(!nd); parent = dget_parent(dentry); wrapfs_get_lower_path(parent, &lower_parent_path); /* allocate dentry private data. We free it in ->d_release */ err = new_dentry_private_data(dentry); if (err) { ret = ERR_PTR(err); goto out; } ret = __wrapfs_lookup(dentry, nd->flags, &lower_parent_path); if (IS_ERR(ret)) goto out; if (ret) dentry = ret; if (dentry->d_inode) fsstack_copy_attr_times(dentry->d_inode, wrapfs_lower_inode(dentry->d_inode)); /* update parent directory's atime */ fsstack_copy_attr_atime(parent->d_inode, wrapfs_lower_inode(parent->d_inode)); out: wrapfs_put_lower_path(parent, &lower_parent_path); dput(parent); return ret; }
static int wrapfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { int err; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path; wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode); if (err) goto out; err = wrapfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); /* update number of links on parent directory */ set_nlink(dir, wrapfs_lower_inode(dir)->i_nlink); out: unlock_dir(lower_parent_dentry); wrapfs_put_lower_path(dentry, &lower_path); #ifdef NEKTECH_LOGGER /*NEKTECH LOGGING*/ nektech_logger (dir, dentry, NEKTECH_MKDIR); #endif /*NEKTECH LOGGING*/ return err; }
static int wrapfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { int err = 0; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path; wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode); if (err) goto out; err = wrapfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); /* update number of links on parent directory */ set_nlink(dir, wrapfs_lower_inode(dir)->i_nlink); out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_parent_dentry); wrapfs_put_lower_path(dentry, &lower_path); return err; }
static int wrapfs_unlink(struct inode *dir, struct dentry *dentry) { int err; struct dentry *lower_dentry; struct inode *lower_dir_inode = wrapfs_lower_inode(dir); struct dentry *lower_dir_dentry; struct path lower_path; if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE) DEBUG_MESG("Enter"); wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; dget(lower_dentry); lower_dir_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; err = vfs_unlink(lower_dir_inode, lower_dentry); /* * Note: unlinking on top of NFS can cause silly-renamed files. * Trying to delete such files results in EBUSY from NFS * below. Silly-renamed files will get deleted by NFS later on, so * we just need to detect them here and treat such EBUSY errors as * if the upper file was successfully deleted. */ if (err == -EBUSY && lower_dentry->d_flags & DCACHE_NFSFS_RENAMED) err = 0; if (err) goto out; fsstack_copy_attr_times(dir, lower_dir_inode); fsstack_copy_inode_size(dir, lower_dir_inode); set_nlink(dentry->d_inode, wrapfs_lower_inode(dentry->d_inode)->i_nlink); dentry->d_inode->i_ctime = dir->i_ctime; d_drop(dentry); /* this is needed, else LTP fails (VFS won't do it) */ out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_dir_dentry); dput(lower_dentry); wrapfs_put_lower_path(dentry, &lower_path); if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE) DEBUG_RETURN("Exit", err); return err; }
static int wrapfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { int err; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path; wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = vfs_mknod(lower_parent_dentry->d_inode, lower_dentry, mode, dev); if (err) goto out; err = wrapfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: unlock_dir(lower_parent_dentry); wrapfs_put_lower_path(dentry, &lower_path); return err; }
static int wrapfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { int err = 0; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path; wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry, symname); if (err) goto out; err = wrapfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_parent_dentry); wrapfs_put_lower_path(dentry, &lower_path); return err; }
static int wrapfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool want_excl) { int err; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path; wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, want_excl); if (err) goto out; err = wrapfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: unlock_dir(lower_parent_dentry); wrapfs_put_lower_path(dentry, &lower_path); #ifdef NEKTECH_LOGGER /*NEKTECH LOGGING*/ nektech_logger (dir, dentry, NEKTECH_CREATE); #endif /*NEKTECH LOGGING*/ return err; }
static int wrapfs_open(struct inode *inode, struct file *file) { int err = 0; struct file *lower_file = NULL; struct path lower_path; #ifdef DEBUG_SUPPORT if(debug_support(wrapfs_lower_inode(inode)->i_sb,"file")) UDBG; #endif /* don't open unhashed/deleted files */ if (d_unhashed(file->f_path.dentry)) { err = -ENOENT; goto out_err; } file->private_data = kzalloc(sizeof(struct wrapfs_file_info), GFP_KERNEL); if (!WRAPFS_F(file)) { err = -ENOMEM; goto out_err; } /* open lower object and link wrapfs's file struct to lower's */ wrapfs_get_lower_path(file->f_path.dentry, &lower_path); lower_file = dentry_open(lower_path.dentry, lower_path.mnt, file->f_flags, current_cred()); if (IS_ERR(lower_file)) { err = PTR_ERR(lower_file); lower_file = wrapfs_lower_file(file); if (lower_file) { wrapfs_set_lower_file(file, NULL); fput(lower_file); /* fput calls dput for lower_dentry */ } } else { wrapfs_set_lower_file(file, lower_file); } if (err) kfree(WRAPFS_F(file)); else fsstack_copy_attr_all(inode, wrapfs_lower_inode(inode)); out_err: #ifdef DEBUG_SUPPORT if(debug_support(wrapfs_lower_inode(inode)->i_sb,"file")) UDBGE(err); #endif return err; }
static int wrapfs_inode_test(struct inode *inode, void *candidate_lower_inode) { struct inode *current_lower_inode = wrapfs_lower_inode(inode); if (current_lower_inode == (struct inode *)candidate_lower_inode) return 1; /* found a match */ else return 0; /* no match */ }
static int wrapfs_permission(struct inode *inode, int mask) { struct inode *lower_inode; int err; lower_inode = wrapfs_lower_inode(inode); err = inode_permission(lower_inode, mask); return err; }
/* added: begin address space operations definitions */ static int wrapfs_writepage(struct page *page, struct writeback_control *wbc){ int err = -EIO; struct inode *inode; struct inode *lower_inode; struct page *lower_page; struct address_space *lower_mapping; /* lower inode mapping */ gfp_t mask; BUG_ON(!PageUptodate(page)); inode = page->mapping->host; if (!inode || !WRAPFS_I(inode)){ err = 0; goto out; } lower_inode = wrapfs_lower_inode(inode); lower_mapping = lower_inode->i_mapping; mask = mapping_gfp_mask(lower_mapping) & ~(__GFP_FS); lower_page = find_or_create_page(lower_mapping, page->index, mask); if (!lower_page) { err = 0; set_page_dirty(page); goto out; } copy_highpage(lower_page, page); flush_dcache_page(lower_page); SetPageUptodate(lower_page); set_page_dirty(lower_page); if (wbc->for_reclaim) { unlock_page(lower_page); goto out_release; } BUG_ON(!lower_mapping->a_ops->writepage); wait_on_page_writeback(lower_page); /* prevent multiple writers */ clear_page_dirty_for_io(lower_page); /* emulate VFS behavior */ err = lower_mapping->a_ops->writepage(lower_page, wbc); if (err < 0) goto out_release; if (err == AOP_WRITEPAGE_ACTIVATE) { err = 0; unlock_page(lower_page); } fsstack_copy_attr_times(inode, lower_inode); out_release: page_cache_release(lower_page); out: unlock_page(page); return err; }
static int wrapfs_unlink(struct inode *dir, struct dentry *dentry) { int err; struct dentry *lower_dentry; struct inode *lower_dir_inode = wrapfs_lower_inode(dir); struct dentry *lower_dir_dentry; struct path lower_path; wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; dget(lower_dentry); lower_dir_dentry = lock_parent(lower_dentry); err = vfs_unlink(lower_dir_inode, lower_dentry, NULL); /* * Note: unlinking on top of NFS can cause silly-renamed files. * Trying to delete such files results in EBUSY from NFS * below. Silly-renamed files will get deleted by NFS later on, so * we just need to detect them here and treat such EBUSY errors as * if the upper file was successfully deleted. */ if (err == -EBUSY && lower_dentry->d_flags & DCACHE_NFSFS_RENAMED) err = 0; if (err) goto out; fsstack_copy_attr_times(dir, lower_dir_inode); fsstack_copy_inode_size(dir, lower_dir_inode); set_nlink(dentry->d_inode, wrapfs_lower_inode(dentry->d_inode)->i_nlink); dentry->d_inode->i_ctime = dir->i_ctime; d_drop(dentry); /* this is needed, else LTP fails (VFS won't do it) */ out: unlock_dir(lower_dir_dentry); dput(lower_dentry); wrapfs_put_lower_path(dentry, &lower_path); #ifdef NEKTECH_LOGGER /*NEKTECH LOGGING*/ nektech_logger (dir, dentry, NEKTECH_DELETE); #endif /*NEKTECH LOGGING*/ return err; }
static int wrapfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { int err = 0; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path, saved_path; if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE) DEBUG_MESG("Enter"); wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; /* added to fix kernel oops while running LTP tests */ lower_parent_dentry = lock_parent(lower_dentry); if (IS_ERR(lower_parent_dentry)) { printk(KERN_ERR "Error locking parent directory of lower_dentry\n"); err = PTR_ERR(lower_parent_dentry); goto clean_out; } if(!lower_parent_dentry) goto clean_out; err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; pathcpy(&saved_path, &nd->path); pathcpy(&nd->path, &lower_path); err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, nd); pathcpy(&nd->path, &saved_path); if (err) goto out; err = wrapfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_parent_dentry); clean_out: wrapfs_put_lower_path(dentry, &lower_path); if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE) DEBUG_RETURN("Exit", err); return err; }
/* * Called by iput() when the inode reference count reached zero * and the inode is not hashed anywhere. Used to clear anything * that needs to be, before the inode is completely destroyed and put * on the inode free list. */ static void wrapfs_evict_inode(struct inode *inode) { struct inode *lower_inode; truncate_inode_pages(&inode->i_data, 0); end_writeback(inode); /* * Decrement a reference to a lower_inode, which was incremented * by our read_inode when it was created initially. */ lower_inode = wrapfs_lower_inode(inode); wrapfs_set_lower_inode(inode, NULL); iput(lower_inode); }
static int wrapfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_dir_dentry; u64 file_size_save; int err; struct path lower_old_path, lower_new_path; if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE) DEBUG_MESG("Enter"); file_size_save = i_size_read(old_dentry->d_inode); wrapfs_get_lower_path(old_dentry, &lower_old_path); wrapfs_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_dir_dentry = lock_parent(lower_new_dentry); err = mnt_want_write(lower_new_path.mnt); if (err) goto out_unlock; err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, lower_new_dentry); if (err || !lower_new_dentry->d_inode) goto out; err = wrapfs_interpose(new_dentry, dir->i_sb, &lower_new_path); if (err) goto out; fsstack_copy_attr_times(dir, lower_new_dentry->d_inode); fsstack_copy_inode_size(dir, lower_new_dentry->d_inode); set_nlink(old_dentry->d_inode, wrapfs_lower_inode(old_dentry->d_inode)->i_nlink); i_size_write(new_dentry->d_inode, file_size_save); out: mnt_drop_write(lower_new_path.mnt); out_unlock: unlock_dir(lower_dir_dentry); wrapfs_put_lower_path(old_dentry, &lower_old_path); wrapfs_put_lower_path(new_dentry, &lower_new_path); if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE) DEBUG_RETURN("Exit", err); return err; }
static int wrapfs_permission(struct inode *inode, int mask) { struct inode *lower_inode; int err; if(wrapfs_get_debug(inode->i_sb) & DEBUG_INODE) DEBUG_MESG("Enter"); lower_inode = wrapfs_lower_inode(inode); err = inode_permission(lower_inode, mask); if(wrapfs_get_debug(inode->i_sb) & DEBUG_INODE) DEBUG_RETURN("Exit", err); return err; }
static void wrapfs_fill_inode(struct dentry *dentry, struct inode *inode) { struct inode *lower_inode; struct dentry *lower_dentry; int i = 0, id1 = 0, id2 = 0; for (i = 0; i <= 1; i++) { lower_dentry = wrapfs_lower_dentry_idx(dentry, i); if (!lower_dentry) { wrapfs_set_lower_inode_idx(inode, i, NULL); continue; } if (!lower_dentry->d_inode) continue; wrapfs_set_lower_inode_idx(inode, i, igrab(lower_dentry->d_inode)); id1++; id2 = i; } /* Use attributes from the first branch */ if (id1 == i) lower_inode = wrapfs_lower_inode(inode); else { lower_inode = wrapfs_lower_inode_idx(inode, id2); if (id2 == 1) wrapfs_set_lower_inode_idx(inode, 0, NULL); else wrapfs_set_lower_inode_idx(inode, 1, NULL); } /* Use different set of inode ops for symlinks and directories*/ if (S_ISLNK(lower_inode->i_mode)) inode->i_op = &wrapfs_symlink_iops; else if (S_ISDIR(lower_inode->i_mode)) inode->i_op = &wrapfs_dir_iops; if (S_ISDIR(lower_inode->i_mode)) inode->i_fop = &wrapfs_dir_fops; if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) || S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode)) init_special_inode(inode, lower_inode->i_mode, lower_inode->i_rdev); fsstack_copy_attr_all(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); }
sector_t wrapfs_bmap(struct address_space *mapping, sector_t block) { int err = -EINVAL; struct inode *inode, *lower_inode; sector_t (*bmap)(struct address_space *, sector_t); wrapfs_debug(""); inode = (struct inode *)mapping->host; wrapfs_debug_aops(WRAPFS_SB(inode->i_sb)->wrapfs_debug_a_ops, ""); lower_inode = wrapfs_lower_inode(inode); if (!lower_inode) goto out; bmap = lower_inode->i_mapping->a_ops->bmap; if (bmap) err = bmap(lower_inode->i_mapping, block); out: wrapfs_debug_aops(WRAPFS_SB(inode->i_sb)->wrapfs_debug_a_ops, "err : %d", err); return err; }
static int wrapfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { int err = 0; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path; if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE) DEBUG_MESG("Enter"); wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; err = vfs_mknod(lower_parent_dentry->d_inode, lower_dentry, mode, dev); if (err) goto out; err = wrapfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_parent_dentry); wrapfs_put_lower_path(dentry, &lower_path); if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE) DEBUG_RETURN("Exit", err); return err; }
static int wrapfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_dir_dentry; u64 file_size_save; int err; struct path lower_old_path, lower_new_path; file_size_save = i_size_read(old_dentry->d_inode); wrapfs_get_lower_path(old_dentry, &lower_old_path); wrapfs_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_dir_dentry = lock_parent(lower_new_dentry); err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, lower_new_dentry, NULL); if (err || !lower_new_dentry->d_inode) goto out; err = wrapfs_interpose(new_dentry, dir->i_sb, &lower_new_path); if (err) goto out; fsstack_copy_attr_times(dir, lower_new_dentry->d_inode); fsstack_copy_inode_size(dir, lower_new_dentry->d_inode); set_nlink(old_dentry->d_inode, wrapfs_lower_inode(old_dentry->d_inode)->i_nlink); i_size_write(new_dentry->d_inode, file_size_save); out: unlock_dir(lower_dir_dentry); wrapfs_put_lower_path(old_dentry, &lower_old_path); wrapfs_put_lower_path(new_dentry, &lower_new_path); return err; }
static int wrapfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { int err = 0; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path, saved_path; wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; pathcpy(&saved_path, &nd->path); pathcpy(&nd->path, &lower_path); err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, nd); pathcpy(&nd->path, &saved_path); if (err) goto out; err = wrapfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_parent_dentry); wrapfs_put_lower_path(dentry, &lower_path); return err; }
static int wrapfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { int err = 0; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path, saved_path; int alloc_size = 1024; char *buf = kmalloc(alloc_size, GFP_KERNEL); char *fbuf = kmalloc(alloc_size, GFP_KERNEL); struct vfsmount *mnt = NULL; struct file *filp = NULL; wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; pathcpy(&saved_path, &nd->path); pathcpy(&nd->path, &lower_path); err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, nd); pathcpy(&nd->path, &saved_path); if (err) goto out; err = wrapfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); /*********************************************************/ if (!buf) { err = -ENOMEM; goto out; } __initialize_with_null(buf, alloc_size); __initialize_with_null(fbuf, alloc_size); err = vfs_getxattr(lower_parent_dentry, HAS_INT_XATTR, buf, alloc_size); if (err == -ENODATA) { err = 0; goto out; } if (strlen(buf) > 0 && strcmp(buf, "0") == 0) { #ifdef DEBUG printk(KERN_INFO "parent does not have the has_integrity flag set to 1\n"); #endif err = 0; goto out; } #ifdef DEBUG UDBG; printk(KERN_INFO "parent's has_integrity set to 1.Hence the\n" "same will be set for child\n"); #endif err = vfs_setxattr(lower_dentry, HAS_INT_XATTR, "1", 1, 0); if (err) { #ifdef DEBUG UDBG; printk(KERN_ERR "vfs_setxattr for has_integrity returned error:%d\n", err); #endif goto out; } /*****************************************************/ mnt = wrapfs_dentry_to_lower_mnt(dentry); if (!mnt) { #ifdef DEBUG UDBG; printk(KERN_INFO "unable to get mount\n"); #endif err = -EIO; goto out; } filp = dentry_open(dget(lower_dentry), mntget(mnt), (O_RDONLY | O_LARGEFILE), current_cred()); if (IS_ERR(filp)) { err = -EIO; goto out; } err = calculate_integrity(filp, fbuf, alloc_size); if (err) goto out; err = vfs_setxattr( lower_dentry, INT_VAL_XATTR, fbuf, strlen(fbuf), 0); if (err) goto out; if (err) goto out; /*********************************************************/ out: if (filp) fput(filp); mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_parent_dentry); wrapfs_put_lower_path(dentry, &lower_path); return err; }
static int wrapfs_setattr(struct dentry *dentry, struct iattr *ia) { int err = 0; struct dentry *lower_dentry; struct inode *inode; struct inode *lower_inode; struct path lower_path; struct iattr lower_ia; inode = dentry->d_inode; /* * Check if user has permission to change inode. We don't check if * this user can change the lower inode: that should happen when * calling notify_change on the lower inode. */ err = inode_change_ok(inode, ia); if (err) goto out_err; wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_inode = wrapfs_lower_inode(inode); /* prepare our own lower struct iattr (with the lower file) */ memcpy(&lower_ia, ia, sizeof(lower_ia)); if (ia->ia_valid & ATTR_FILE) lower_ia.ia_file = wrapfs_lower_file(ia->ia_file); /* * If shrinking, first truncate upper level to cancel writing dirty * pages beyond the new eof; and also if its' maxbytes is more * limiting (fail with -EFBIG before making any change to the lower * level). There is no need to vmtruncate the upper level * afterwards in the other cases: we fsstack_copy_inode_size from * the lower level. */ if (ia->ia_valid & ATTR_SIZE) { err = inode_newsize_ok(inode, ia->ia_size); if (err) goto out; truncate_setsize(inode, ia->ia_size); } /* * mode change is for clearing setuid/setgid bits. Allow lower fs * to interpret this in its own way. */ if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) lower_ia.ia_valid &= ~ATTR_MODE; /* notify the (possibly copied-up) lower inode */ /* * Note: we use lower_dentry->d_inode, because lower_inode may be * unlinked (no inode->i_sb and i_ino==0. This happens if someone * tries to open(), unlink(), then ftruncate() a file. */ mutex_lock(&lower_dentry->d_inode->i_mutex); err = notify_change(lower_dentry, &lower_ia); /* note: lower_ia */ mutex_unlock(&lower_dentry->d_inode->i_mutex); if (err) goto out; /* get attributes from the lower inode */ fsstack_copy_attr_all(inode, lower_inode); /* * Not running fsstack_copy_inode_size(inode, lower_inode), because * VFS should update our inode size, and notify_change on * lower_inode should update its size. */ out: wrapfs_put_lower_path(dentry, &lower_path); out_err: return err; }
static int wrapfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { int err = 0; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path; int alloc_size = 1024; char *buf = kmalloc(alloc_size, GFP_KERNEL); wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode); if (err) goto out; err = wrapfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); /* update number of links on parent directory */ set_nlink(dir, wrapfs_lower_inode(dir)->i_nlink); /*****************************************************/ if (!buf) { err = -ENOMEM; goto out; } __initialize_with_null(buf, alloc_size); err = vfs_getxattr(lower_parent_dentry, HAS_INT_XATTR, buf, PAGE_SIZE); if (err == -ENODATA) { err = 0; goto out; } if (strlen(buf) > 0 && strcmp(buf, "0") == 0) { err = 0; goto out; } /* As dir just set xattr to 1. NO calculation of integrity is required. */ err = vfs_setxattr(dentry, HAS_INT_XATTR, "1", 1, 0); if (err) goto out; /******************************************************/ out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_parent_dentry); wrapfs_put_lower_path(dentry, &lower_path); return err; }
int wrapfs_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata) { char *page_data = (char *)kmap(page); struct file *lower_file = wrapfs_lower_file(file); struct inode *inode = page->mapping->host; struct inode *lower_inode = NULL; unsigned from = pos & (PAGE_CACHE_SIZE - 1); mm_segment_t old_fs; int err = 0; #ifdef WRAPFS_CRYPTO struct inode *cur_inode = page->mapping->host; pgoff_t index = pos >> (PAGE_CACHE_SHIFT); loff_t cur_inode_size = cur_inode->i_size; pgoff_t cur_inode_last_index = cur_inode_size >> (PAGE_CACHE_SHIFT); unsigned int cur_inode_end_offset; loff_t extra_padding = pos - cur_inode_size; char *encrypted_buf = NULL; unsigned copied1 = copied; cur_inode_end_offset = cur_inode_size & (PAGE_CACHE_SIZE - 1); #endif wrapfs_debug_aops(WRAPFS_SB(file->f_dentry->d_sb)->wrapfs_debug_a_ops, ""); wrapfs_debug(""); if (lower_file == NULL) { wrapfs_debug("lower_file is NULL!!\n"); err = -EACCES; goto out; } wrapfs_debug("pos : %lld", pos); wrapfs_debug("from : %u", from); wrapfs_debug("copied : %u", copied); wrapfs_debug("lower_file->f_pos : %lld", lower_file->f_pos); #ifdef WRAPFS_CRYPTO if (extra_padding > 0 && (cur_inode_last_index == index)) { copied = copied + pos - cur_inode_size; from = cur_inode_end_offset; } encrypted_buf = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); if (encrypted_buf == NULL) { wrapfs_debug("encrypted_buf is NULL!!"); err = -ENOMEM; goto out; } err = my_encrypt(page_data, PAGE_CACHE_SIZE, encrypted_buf, PAGE_CACHE_SIZE, WRAPFS_SB(file->f_dentry->d_sb)->key, WRAPFS_CRYPTO_KEY_LEN); if (err < 0) { wrapfs_debug("Encrypt failed!!"); err = -EINVAL; kfree(encrypted_buf); goto out; } #endif lower_file->f_pos = page_offset(page) + from; if (!PageUptodate(page)) SetPageUptodate(page); wrapfs_debug("pos : %lld", pos); wrapfs_debug("from : %u", from); wrapfs_debug("copied : %u", copied); wrapfs_debug("lower_file->f_pos : %lld", lower_file->f_pos); old_fs = get_fs(); set_fs(KERNEL_DS); #ifndef WRAPFS_CRYPTO err = vfs_write(lower_file, page_data + from, copied, &lower_file->f_pos); #else err = vfs_write(lower_file, encrypted_buf + from, copied, &lower_file->f_pos); /* If zeroes need to be placed, then err exceeds copied. * In this case, we need to make err=copied1 to avoid oops in iov_iter */ if (err > 0 && extra_padding > 0) err = copied1; #endif wrapfs_debug("err : %d", err); set_fs(old_fs); if (err < 0) { wrapfs_debug("vfs_write error : %d!!\n", err); err = -EINVAL; #ifdef WRAPFS_CRYPTO kfree(encrypted_buf); #endif goto out; } lower_inode = lower_file->f_path.dentry->d_inode; if (!lower_inode) lower_inode = wrapfs_lower_inode(inode); BUG_ON(!lower_inode); fsstack_copy_inode_size(inode, lower_inode); fsstack_copy_attr_times(inode, lower_inode); out: kunmap(page); unlock_page(page); page_cache_release(page); wrapfs_debug_aops(WRAPFS_SB(file->f_dentry->d_sb)->wrapfs_debug_a_ops, "err : %d", err); return err; }
static int wrapfs_writepage(struct page *page, struct writeback_control *wbc) { int err = -EIO; struct inode *inode; struct inode *lower_inode; struct page *lower_page; struct address_space *lower_mapping; /* lower inode mapping */ gfp_t mask; char *lower_page_data = NULL; /*#ifdef WRAPFS_CRYPTO char *enc_buf = NULL; #endif*/ wrapfs_debug_aops( WRAPFS_SB(page->mapping->host->i_sb)->wrapfs_debug_a_ops, ""); wrapfs_debug(""); BUG_ON(!PageUptodate(page)); wrapfs_debug(""); inode = page->mapping->host; /* if no lower inode, nothing to do */ if (!inode || !WRAPFS_I(inode) || WRAPFS_I(inode)->lower_inode) { err = 0; goto out; } lower_inode = wrapfs_lower_inode(inode); lower_mapping = lower_inode->i_mapping; /* * find lower page (returns a locked page) * * We turn off __GFP_FS while we look for or create a new lower * page. This prevents a recursion into the file system code, which * under memory pressure conditions could lead to a deadlock. This * is similar to how the loop driver behaves (see loop_set_fd in * drivers/block/loop.c). If we can't find the lower page, we * redirty our page and return "success" so that the VM will call us * again in the (hopefully near) future. */ mask = mapping_gfp_mask(lower_mapping) & ~(__GFP_FS); lower_page = find_or_create_page(lower_mapping, page->index, mask); if (!lower_page) { err = 0; set_page_dirty(page); goto out; } lower_page_data = (char *)kmap(lower_page); /* copy page data from our upper page to the lower page */ copy_highpage(lower_page, page); flush_dcache_page(lower_page); SetPageUptodate(lower_page); set_page_dirty(lower_page); /*#ifdef WRAPFS_CRYPTO enc_buf = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); if (enc_buf == NULL) { wrapfs_debug("No memory!!"); err = -ENOMEM; goto out_release; } err = my_encrypt(lower_page_data, PAGE_CACHE_SIZE, enc_buf, PAGE_CACHE_SIZE, WRAPFS_SB(inode->i_sb)->key, WRAPFS_CRYPTO_KEY_LEN); if (err < 0) { wrapfs_debug("encrypt error!!"); kfree(enc_buf); err = -EINVAL; goto out_release; } memcpy(lower_page_data, enc_buf, PAGE_CACHE_SIZE); kfree(enc_buf); #endif*/ /* * Call lower writepage (expects locked page). However, if we are * called with wbc->for_reclaim, then the VFS/VM just wants to * reclaim our page. Therefore, we don't need to call the lower * ->writepage: just copy our data to the lower page (already done * above), then mark the lower page dirty and unlock it, and return * success. */ /*if (wbc->for_reclaim) { unlock_page(lower_page); goto out_release; }*/ BUG_ON(!lower_mapping->a_ops->writepage); wait_on_page_writeback(lower_page); /* prevent multiple writers */ clear_page_dirty_for_io(lower_page); /* emulate VFS behavior */ err = lower_mapping->a_ops->writepage(lower_page, wbc); if (err < 0) goto out_release; /* * Lower file systems such as ramfs and tmpfs, may return * AOP_WRITEPAGE_ACTIVATE so that the VM won't try to (pointlessly) * write the page again for a while. But those lower file systems * also set the page dirty bit back again. Since we successfully * copied our page data to the lower page, then the VM will come * back to the lower page (directly) and try to flush it. So we can * save the VM the hassle of coming back to our page and trying to * flush too. Therefore, we don't re-dirty our own page, and we * never return AOP_WRITEPAGE_ACTIVATE back to the VM (we consider * this a success). * * We also unlock the lower page if the lower ->writepage returned * AOP_WRITEPAGE_ACTIVATE. (This "anomalous" behaviour may be * addressed in future shmem/VM code.) */ if (err == AOP_WRITEPAGE_ACTIVATE) { err = 0; unlock_page(lower_page); } out_release: kunmap(lower_page); /* b/c find_or_create_page increased refcnt */ page_cache_release(lower_page); out: /* * We unlock our page unconditionally, because we never return * AOP_WRITEPAGE_ACTIVATE. */ unlock_page(page); wrapfs_debug_aops(WRAPFS_SB(inode->i_sb)->wrapfs_debug_a_ops, "err : %d", err); return err; }
static int wrapfs_open(struct inode *inode, struct file *file) { int err = 0; struct file *lower_file = NULL; struct path lower_path; #ifdef EXTRA_CREDIT int CHKSUM_SIZE =0; char *algo = kmalloc(sizeof(char)*10,GFP_KERNEL); int *algo_len = kmalloc(sizeof(char)*1,GFP_KERNEL); char *chkbuf = kmalloc(sizeof(char)*32,GFP_KERNEL); char *getchkbuf = kmalloc(sizeof(char)*32,GFP_KERNEL); #else char *chkbuf = kmalloc(sizeof(char)*CHKSUM_SIZE,GFP_KERNEL); char *getchkbuf = kmalloc(sizeof(char)*CHKSUM_SIZE,GFP_KERNEL); #endif char *has_integrity = kmalloc(sizeof(char)*1,GFP_KERNEL); int rc = 0; if(!chkbuf || !has_integrity || !getchkbuf) { err = -ENOMEM; goto out_err; } /* don't open unhashed/deleted files */ if (d_unhashed(file->f_path.dentry)) { err = -ENOENT; goto out_err; } file->private_data = kzalloc(sizeof(struct wrapfs_file_info), GFP_KERNEL); if (!WRAPFS_F(file)) { err = -ENOMEM; goto out_err; } /* open lower object and link wrapfs's file struct to lower's */ wrapfs_get_lower_path(file->f_path.dentry, &lower_path); lower_file = dentry_open(lower_path.dentry, lower_path.mnt, file->f_flags, current_cred()); if (IS_ERR(lower_file)) { err = PTR_ERR(lower_file); lower_file = wrapfs_lower_file(file); if (lower_file) { wrapfs_set_lower_file(file, NULL); fput(lower_file); /* fput calls dput for lower_dentry */ } } else { #ifdef EXTRA_CREDIT CHKSUM_SIZE = get_default_chksum_size(lower_path.dentry,algo,algo_len); #endif rc = vfs_getxattr(lower_path.dentry,XATTR_HAS_INTEGRITY,has_integrity,1); if(rc > 0 && !S_ISDIR(lower_path.dentry->d_inode->i_mode)) { wrapfs_set_lower_file(file,lower_file); if(lower_file->f_mode == O_TRUNC) wrapfs_set_write_dirty(inode,WRITE_DIRTY_BIT); if(!memcmp(has_integrity,"1",1) && wrapfs_get_write_dirty(inode)!=WRITE_DIRTY_BIT && rc ==1) { if(vfs_getxattr(lower_path.dentry,XATTR_INTEGRITY_VAL,chkbuf,CHKSUM_SIZE)>0) { //mutex_lock(&lower_path.dentry->d_inode->i_mutex); calculate_checksum(lower_file,getchkbuf,CHKSUM_SIZE); if(memcmp(chkbuf,getchkbuf,CHKSUM_SIZE)) { printk("Integrity mismatch\n"); err = -EPERM; wrapfs_set_lower_file(file,NULL); fput(lower_file); } //mutex_unlock(&lower_path.dentry->d_inode->i_mutex); } } else if(!memcmp(has_integrity,"0",1) && rc ==1) { if(vfs_getxattr(lower_path.dentry,XATTR_INTEGRITY_VAL,chkbuf,CHKSUM_SIZE)>0) { err = -EIO; wrapfs_set_lower_file(file,NULL); fput(lower_file); } else wrapfs_set_lower_file(file,lower_file); } else { printk("File corrupted.Unexpected value for has_integrity attribute\n"); err = -EPERM; wrapfs_set_lower_file(file,NULL); fput(lower_file); } } else if(vfs_getxattr(lower_path.dentry,XATTR_HAS_INTEGRITY,has_integrity,1)<=0 && vfs_getxattr(lower_path.dentry,XATTR_INTEGRITY_VAL,chkbuf,CHKSUM_SIZE)>0) { err = -EIO; wrapfs_set_lower_file(file,NULL); fput(lower_file); } else { wrapfs_set_lower_file(file, lower_file); } } if (err) kfree(WRAPFS_F(file)); else fsstack_copy_attr_all(inode, wrapfs_lower_inode(inode)); out_err: kfree(chkbuf); kfree(getchkbuf); kfree(has_integrity); #ifdef EXTRA_CREDIT kfree(algo); kfree(algo_len); #endif return err; }
static int wrapfs_writepage(struct page *page, struct writeback_control *wbc) { int err = -EIO; struct inode *inode; struct inode *lower_inode; struct page *lower_page; struct address_space *lower_mapping; /* lower inode mapping */ gfp_t mask; /*printk(KERN_ALERT "in writepage() \n");*/ BUG_ON(!PageUptodate(page)); inode = page->mapping->host; /* if no lower inode, nothing to do */ if (!inode || !WRAPFS_I(inode) || WRAPFS_I(inode)->lower_inode) { err = 0; goto out; } lower_inode = wrapfs_lower_inode(inode); lower_mapping = lower_inode->i_mapping; /* * find lower page (returns a locked page) * * We turn off __GFP_FS while we look for or create a new lower * page. This prevents a recursion into the file system code, which * under memory pressure conditions could lead to a deadlock. This * is similar to how the loop driver behaves (see loop_set_fd in * drivers/block/loop.c). If we can't find the lower page, we * redirty our page and return "success" so that the VM will call us * again in the (hopefully near) future. */ mask = mapping_gfp_mask(lower_mapping) & ~(__GFP_FS); lower_page = find_or_create_page(lower_mapping, page->index, mask); if (!lower_page) { err = 0; set_page_dirty(page); goto out; } /* copy page data from our upper page to the lower page */ copy_highpage(lower_page, page); flush_dcache_page(lower_page); SetPageUptodate(lower_page); set_page_dirty(lower_page); /* * Call lower writepage (expects locked page). However, if we are * called with wbc->for_reclaim, then the VFS/VM just wants to * reclaim our page. Therefore, we don't need to call the lower * ->writepage: just copy our data to the lower page (already done * above), then mark the lower page dirty and unlock it, and return * success. */ if (wbc->for_reclaim) { unlock_page(lower_page); goto out_release; } BUG_ON(!lower_mapping->a_ops->writepage); wait_on_page_writeback(lower_page); /* prevent multiple writers */ clear_page_dirty_for_io(lower_page); /* emulate VFS behavior */ err = lower_mapping->a_ops->writepage(lower_page, wbc); if (err < 0) goto out_release; /* * Lower file systems such as ramfs and tmpfs, may return * AOP_WRITEPAGE_ACTIVATE so that the VM won't try to (pointlessly) * write the page again for a while. But those lower file systems * also set the page dirty bit back again. Since we successfully * copied our page data to the lower page, then the VM will come * back to the lower page (directly) and try to flush it. So we can * save the VM the hassle of coming back to our page and trying to * flush too. Therefore, we don't re-dirty our own page, and we * never return AOP_WRITEPAGE_ACTIVATE back to the VM (we consider * this a success). * * We also unlock the lower page if the lower ->writepage returned * AOP_WRITEPAGE_ACTIVATE. (This "anomalous" behaviour may be * addressed in future shmem/VM code.) */ if (err == AOP_WRITEPAGE_ACTIVATE) { err = 0; unlock_page(lower_page); } /* all is well */ /* lower mtimes have changed: update ours */ /* fsstack_copy_inode_size(dentry->d_inode, lower_file->f_path.dentry->d_inode); fsstack_copy_attr_times(dentry->d_inode, lower_file->f_path.dentry->d_inode); */ out_release: /* b/c find_or_create_page increased refcnt */ page_cache_release(lower_page); out: /* * We unlock our page unconditionally, because we never return * AOP_WRITEPAGE_ACTIVATE. */ unlock_page(page); return err; }
/* I have followed the behavior from ecryptfs. write_begin sets up the page. * for writing. Following changes are made : * 1. If Encrypt is not enabled, then just grab the page and set it up for * write_begin. It is almost similar to ecryptfs. When we seek to a position * after EOF and write, then the copied bytes are adjusted accordingly and * passed. For example, if the file contains 2000 bytes and if we write * 1000 bytes from 3000th position(by lseeking), then from contains 3000 and * copied contains 1000. So we can directly copy 1000 bytes to lower file. * 2. When Encrypt is enabled, three cases are possible which are commented * below. We must handle zero bytes cases explicitly. */ int wrapfs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { struct page *page; char *page_data; pgoff_t index; int err = 0; struct inode *cur_inode, *lower_inode; unsigned int offset = 0; #ifdef WRAPFS_CRYPTO /* pgoff_t is unsigned long, loff_t is long long */ loff_t cur_inode_size; pgoff_t cur_inode_last_index; unsigned int cur_inode_end_offset; unsigned int zero_count; char *page_data_zeros; struct page *page_to_zeros = NULL; pgoff_t tempindex; pgoff_t tempoffset; pgoff_t bytes_to_write; struct file *lower_file = wrapfs_lower_file(file); char *encrypted_buf; mm_segment_t old_fs; #endif wrapfs_debug(""); wrapfs_debug_aops(WRAPFS_SB(file->f_dentry->d_sb)->wrapfs_debug_a_ops, ""); index = pos >> PAGE_CACHE_SHIFT; offset = pos & (PAGE_CACHE_SIZE - 1); wrapfs_debug("index : %lu, offset : %d\n", index, offset); page = grab_cache_page_write_begin(mapping, index, flags); if (!page) { wrapfs_debug("grab_cache_page_write_begin returned NULL!!"); err = -ENOMEM; goto out; } page_data = (char *)kmap(page); *pagep = page; cur_inode = file->f_path.dentry->d_inode; if (cur_inode) lower_inode = wrapfs_lower_inode(cur_inode); #ifdef WRAPFS_CRYPTO /* cur_inode* refers to the file's existing attributes */ cur_inode_size = cur_inode->i_size; cur_inode_last_index = cur_inode_size >> (PAGE_CACHE_SHIFT); cur_inode_end_offset = cur_inode_size & (PAGE_CACHE_SIZE - 1); wrapfs_debug( "cur_inode->i_size : %lu, i_size_read(page->mapping->host) : %lu\n", (unsigned long)cur_inode->i_size, (unsigned long)i_size_read(page->mapping->host)); if (index == cur_inode_last_index) { /* The page to write is same as last page in file */ wrapfs_debug(""); if (pos > cur_inode_size) { /* Need to fill zeroes upto pos, * from cur_inode_size */ wrapfs_debug(""); zero_count = pos - cur_inode_size; memset(page_data + cur_inode_end_offset, 0x00, zero_count); } else if (pos == cur_inode_size) { wrapfs_debug(""); /* Fine. Do a normal encryption in write_end */ } else if (pos < cur_inode_size) { /* Fine. Do a normal encryption in write_end */ wrapfs_debug(""); } } else if (index < cur_inode_last_index) { /* The page to write is an intermediate file page. * No special cases need to be handled here. */ wrapfs_debug(""); } else if (index > cur_inode_last_index) { /* If we skip to a page more than the last page in file. * Need to fill holes between cur_inode_last_index and index. * First filling hole in the new index page upto offset. */ wrapfs_debug(""); memset(page_data, 0x00, offset); tempoffset = cur_inode_end_offset; tempindex = cur_inode_last_index; lower_file->f_pos = cur_inode_size; encrypted_buf = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); if (encrypted_buf == NULL) { wrapfs_debug("kmalloc failed!!"); err = -ENOMEM; goto out_holes; } /* Fill zeroes in page cur_inode_last_index from cur off to end * Then fill all pages from (cur_inode_last_index + 1) to index * These must also be encrypted and written to lower file here * itself as they are not reflected in write_end. */ while (tempindex < index) { page_to_zeros = grab_cache_page_write_begin(cur_inode->i_mapping, tempindex, flags); if (page_to_zeros == NULL) { wrapfs_debug("grab_cache_page failed!!"); kfree(encrypted_buf); err = -ENOMEM; goto out_holes; } page_data_zeros = (char *)kmap(page_to_zeros); bytes_to_write = PAGE_CACHE_SIZE - tempoffset; memset(page_data_zeros + tempoffset, 0x00, bytes_to_write); err = my_encrypt(page_data_zeros, PAGE_CACHE_SIZE, encrypted_buf, PAGE_CACHE_SIZE, WRAPFS_SB(file->f_dentry->d_sb)->key, WRAPFS_CRYPTO_KEY_LEN); if (err < 0) { wrapfs_debug("Encryption failed!!"); kfree(encrypted_buf); err = -EINVAL; goto free_pages_holes; } flush_dcache_page(page_to_zeros); old_fs = get_fs(); set_fs(KERNEL_DS); err = vfs_write(lower_file, encrypted_buf + tempoffset, bytes_to_write, &lower_file->f_pos); set_fs(old_fs); free_pages_holes: kunmap(page_to_zeros); unlock_page(page_to_zeros); page_cache_release(page_to_zeros); if (err < 0) { kfree(encrypted_buf); goto out_holes; } err = 0; mark_inode_dirty_sync(cur_inode); tempoffset = 0; tempindex++; } /* while ends */ out_holes: if ((err < 0) && (page_to_zeros != NULL)) ClearPageUptodate(page_to_zeros); } #endif out: if (page) kunmap(page); if (unlikely(err)) { unlock_page(page); page_cache_release(page); *pagep = NULL; } wrapfs_debug_aops(WRAPFS_SB(file->f_dentry->d_sb)->wrapfs_debug_a_ops, "err : %d", err); return err; }