/* * Post-copyup helper to release all non-directory source objects of a * copied-up file. Regular files should have only one lower object. */ void unionfs_postcopyup_release(struct dentry *dentry) { int bstart, bend; BUG_ON(S_ISDIR(dentry->d_inode->i_mode)); bstart = dbstart(dentry); bend = dbend(dentry); path_put_lowers(dentry, bstart + 1, bend, false); iput_lowers(dentry->d_inode, bstart + 1, bend, false); dbend(dentry) = bstart; ibend(dentry->d_inode) = ibstart(dentry->d_inode) = bstart; }
/* perform a delayed copyup of a read-write file on a read-only branch */ static int do_delayed_copyup(struct file *file, struct dentry *parent) { int bindex, bstart, bend, err = 0; struct dentry *dentry = file->f_path.dentry; struct inode *parent_inode = parent->d_inode; bstart = fbstart(file); bend = fbend(file); BUG_ON(!S_ISREG(dentry->d_inode->i_mode)); unionfs_check_file(file); for (bindex = bstart - 1; bindex >= 0; bindex--) { if (!d_deleted(dentry)) err = copyup_file(parent_inode, file, bstart, bindex, i_size_read(dentry->d_inode)); else err = copyup_deleted_file(file, dentry, parent, bstart, bindex); /* if succeeded, set lower open-file flags and break */ if (!err) { struct file *lower_file; lower_file = unionfs_lower_file_idx(file, bindex); lower_file->f_flags = file->f_flags; break; } } if (err || (bstart <= fbstart(file))) goto out; bend = fbend(file); for (bindex = bstart; bindex <= bend; bindex++) { if (unionfs_lower_file_idx(file, bindex)) { branchput(dentry->d_sb, bindex); fput(unionfs_lower_file_idx(file, bindex)); unionfs_set_lower_file_idx(file, bindex, NULL); } } path_put_lowers(dentry, bstart, bend, false); iput_lowers(dentry->d_inode, bstart, bend, false); /* for reg file, we only open it "once" */ fbend(file) = fbstart(file); dbend(dentry) = dbstart(dentry); ibend(dentry->d_inode) = ibstart(dentry->d_inode); out: unionfs_check_file(file); return err; }