/* bring it to the same state as an unlinked file */
hidden_dentry = unionfs_lower_dentry_idx(dentry, dbstart(dentry));
+ if (!unionfs_lower_inode_idx(dentry->d_inode, bindex)) {
+ atomic_inc(&hidden_dentry->d_inode->i_count);
+ unionfs_set_lower_inode_idx(dentry->d_inode, bindex,
+ hidden_dentry->d_inode);
+ }
hidden_dir_dentry = lock_parent(hidden_dentry);
err = vfs_unlink(hidden_dir_dentry->d_inode, hidden_dentry);
unlock_dir(hidden_dir_dentry);
out:
+ if (!err)
+ unionfs_check_dentry(dentry);
return err;
}
BUG_ON(!S_ISREG(file->f_dentry->d_inode->i_mode));
+ unionfs_check_file(file);
+ unionfs_check_dentry(dentry);
for (bindex = bstart - 1; bindex >= 0; bindex--) {
if (!d_deleted(file->f_dentry))
err = copyup_file(parent_inode, file, bstart,
fput(unionfs_lower_file_idx(file, bindex));
unionfs_set_lower_file_idx(file, bindex, NULL);
}
+ if (unionfs_lower_mnt_idx(dentry, bindex)) {
+ unionfs_mntput(dentry, bindex);
+ unionfs_set_lower_mnt_idx(dentry, bindex, NULL);
+ }
+ if (unionfs_lower_dentry_idx(dentry, bindex)) {
+ BUG_ON(!dentry->d_inode);
+ iput(unionfs_lower_inode_idx(dentry->d_inode, bindex));
+ unionfs_set_lower_inode_idx(dentry->d_inode, bindex, NULL);
+ dput(unionfs_lower_dentry_idx(dentry, bindex));
+ unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
+ }
}
- fbend(file) = bend;
+ /* for reg file, we only open it "once" */
+ fbend(file) = fbstart(file);
+ set_dbend(dentry, dbstart(dentry));
+ ibend(dentry->d_inode) = ibstart(dentry->d_inode);
}
+ unionfs_check_file(file);
+ unionfs_check_dentry(dentry);
return err;
}
kfree(UNIONFS_F(file)->saved_branch_ids);
}
out_nofree:
+ if (!err)
+ unionfs_check_file(file);
unionfs_unlock_dentry(dentry);
return err;
}
}
out_nofree:
unionfs_read_unlock(inode->i_sb);
+ unionfs_check_inode(inode);
+ unionfs_check_file(file);
return err;
}
struct file *hidden_file = NULL;
struct unionfs_file_info *fileinfo = UNIONFS_F(file);
struct unionfs_inode_info *inodeinfo = UNIONFS_I(inode);
+ struct super_block *sb = inode->i_sb;
int bindex, bstart, bend;
- int fgen;
+ int fgen, err = 0;
- unionfs_read_lock(inode->i_sb);
+ unionfs_check_file(file);
+ unionfs_read_lock(sb);
+ /*
+ * Yes, we have to revalidate this file even if it's being released.
+ * This is important for open-but-unlinked files, as well as mmap
+ * support.
+ */
+ if ((err = unionfs_file_revalidate(file, 1)))
+ goto out;
/* fput all the hidden files */
fgen = atomic_read(&fileinfo->generation);
bstart = fbstart(file);
if (hidden_file) {
fput(hidden_file);
- unionfs_read_lock(inode->i_sb);
- branchput(inode->i_sb, bindex);
- unionfs_read_unlock(inode->i_sb);
+ unionfs_read_lock(sb);
+ branchput(sb, bindex);
+ unionfs_read_unlock(sb);
}
}
kfree(fileinfo->lower_files);
fileinfo->rdstate = NULL;
}
kfree(fileinfo);
- unionfs_read_unlock(inode->i_sb);
- return 0;
+
+out:
+ unionfs_read_unlock(sb);
+ return err;
}
/* pass the ioctl to the lower fs */
}
out:
+ unionfs_check_file(file);
return err;
}
if ((err = unionfs_file_revalidate(file, 1)))
goto out;
+ unionfs_check_file(file);
if (!atomic_dec_and_test(&UNIONFS_I(dentry->d_inode)->totalopens))
goto out;
unionfs_unlock_dentry(dentry);
out:
unionfs_read_unlock(file->f_dentry->d_sb);
+ unionfs_check_file(file);
return err;
}
dput(old_hidden_dentry);
kfree(symbuf);
+ if (err)
+ goto out;
+ if (!S_ISDIR(dentry->d_inode->i_mode)) {
+ unionfs_purge_extras(dentry);
+ if (!unionfs_lower_inode(dentry->d_inode)) {
+ /*
+ * If we got here, then we copied up to an
+ * unlinked-open file, whose name is .unionfsXXXXX.
+ */
+ struct inode *inode = new_hidden_dentry->d_inode;
+ atomic_inc(&inode->i_count);
+ unionfs_set_lower_inode_idx(dentry->d_inode,
+ ibstart(dentry->d_inode),
+ inode);
+ }
+ }
+ unionfs_inherit_mnt(dentry);
+ unionfs_check_inode(dir);
+ unionfs_check_dentry(dentry);
out:
return err;
}
{
int err;
+ unionfs_check_dentry(dentry);
unionfs_lock_dentry(dentry);
err = __unionfs_d_revalidate_chain(dentry, nd);
unionfs_unlock_dentry(dentry);
+ unionfs_check_dentry(dentry);
return err;
}
{
int bindex, bstart, bend;
+ unionfs_check_dentry(dentry);
/* this could be a negative dentry, so check first */
if (!UNIONFS_D(dentry)) {
printk(KERN_DEBUG "unionfs: dentry without private data: %.*s",
}
out:
unionfs_read_unlock(file->f_dentry->d_sb);
+ unionfs_check_file(file);
return err;
}
out:
unionfs_read_unlock(file->f_dentry->d_sb);
+ unionfs_check_file(file);
return err;
}
inode->i_size = pos;
out:
unionfs_read_unlock(file->f_dentry->d_sb);
+ unionfs_check_file(file);
return err;
}
out:
unionfs_read_unlock(file->f_dentry->d_sb);
+ unionfs_check_file(file);
return mask;
}
out:
unionfs_read_unlock(file->f_dentry->d_sb);
+ unionfs_check_file(file);
return err;
}
out:
unionfs_read_unlock(file->f_dentry->d_sb);
+ unionfs_check_file(file);
return err;
}
out:
unionfs_read_unlock(file->f_dentry->d_sb);
+ unionfs_check_file(file);
return err;
}
dput(wh_dentry);
kfree(name);
+ if (!err)
+ unionfs_inherit_mnt(dentry);
unionfs_unlock_dentry(dentry);
unionfs_read_unlock(dentry->d_sb);
+
+ unionfs_check_inode(parent);
+ unionfs_check_dentry(dentry->d_parent);
+ unionfs_check_dentry(dentry);
return err;
}
nd->dentry = path_save.dentry;
nd->mnt = path_save.mnt;
}
+ if (!IS_ERR(ret))
+ unionfs_inherit_mnt(dentry);
+ unionfs_check_inode(parent);
+ unionfs_check_dentry(dentry);
return ret;
}
d_drop(new_dentry);
kfree(name);
+ if (!err)
+ unionfs_inherit_mnt(new_dentry);
unionfs_unlock_dentry(new_dentry);
unionfs_unlock_dentry(old_dentry);
+ unionfs_check_inode(dir);
+ unionfs_check_dentry(new_dentry);
+ unionfs_check_dentry(old_dentry);
return err;
}
d_drop(dentry);
kfree(name);
+ if (!err)
+ unionfs_inherit_mnt(dentry);
unionfs_unlock_dentry(dentry);
+
+ unionfs_check_inode(dir);
+ unionfs_check_dentry(dentry);
return err;
}
kfree(name);
unionfs_unlock_dentry(dentry);
+ unionfs_check_inode(parent);
+ unionfs_check_dentry(dentry);
return err;
}
kfree(name);
+ if (!err)
+ unionfs_inherit_mnt(dentry);
unionfs_unlock_dentry(dentry);
+
+ unionfs_check_inode(dir);
+ unionfs_check_dentry(dentry);
return err;
}
out:
unionfs_unlock_dentry(dentry);
+ unionfs_check_dentry(dentry);
return err;
}
err = 0;
out:
+ unionfs_check_dentry(dentry);
return ERR_PTR(err);
}
static void unionfs_put_link(struct dentry *dentry, struct nameidata *nd,
void *cookie)
{
+ unionfs_check_dentry(dentry);
kfree(nd_get_link(nd));
}
out:
unionfs_read_unlock(inode->i_sb);
+ unionfs_check_inode(inode);
return err;
}
hidden_inode = unionfs_lower_inode(dentry->d_inode);
fsstack_copy_attr_all(inode, hidden_inode, unionfs_get_nlinks);
fsstack_copy_inode_size(inode, hidden_inode);
-
out:
unionfs_unlock_dentry(dentry);
+ unionfs_check_dentry(dentry);
return err;
}
}
}
err = do_unionfs_rename(old_dir, old_dentry, new_dir, new_dentry);
-
out:
if (err)
/* clear the new_dentry stuff created */
d_drop(new_dentry);
- else
+ else {
/*
* force re-lookup since the dir on ro branch is not renamed,
* and hidden dentries still indicate the un-renamed ones.
*/
if (S_ISDIR(old_dentry->d_inode->i_mode))
atomic_dec(&UNIONFS_D(old_dentry)->generation);
+ else
+ unionfs_purge_extras(old_dentry);
+ if (new_dentry->d_inode &&
+ !S_ISDIR(new_dentry->d_inode->i_mode)) {
+ unionfs_purge_extras(new_dentry);
+ unionfs_inherit_mnt(new_dentry);
+ if (!unionfs_lower_inode(new_dentry->d_inode)) {
+ /*
+ * If we get here, it means that no copyup
+ * was needed, and that a file by the old
+ * name already existing on the destination
+ * branch; that file got renamed earlier in
+ * this function, so all we need to do here
+ * is set the lower inode.
+ */
+ struct inode *inode;
+ inode = unionfs_lower_inode(old_dentry->d_inode);
+ atomic_inc(&inode->i_count);
+ unionfs_set_lower_inode_idx(
+ new_dentry->d_inode,
+ dbstart(new_dentry), inode);
+ }
+
+ }
+ unionfs_check_inode(old_dir);
+ unionfs_check_inode(new_dir);
+ unionfs_check_dentry(old_dentry);
+ unionfs_check_dentry(new_dentry);
+ }
unionfs_unlock_dentry(new_dentry);
unionfs_unlock_dentry(old_dentry);
BUG_ON(!is_valid_dentry(dentry));
+ unionfs_check_dentry(dentry);
unionfs_lock_dentry(dentry);
err = unionfs_unlink_whiteout(dir, dentry);
/* call d_drop so the system "forgets" about us */
- if (!err)
+ if (!err) {
+ if (!S_ISDIR(dentry->d_inode->i_mode))
+ unionfs_purge_extras(dentry);
+ unionfs_check_dentry(dentry);
d_drop(dentry);
+ }
unionfs_unlock_dentry(dentry);
return err;
BUG_ON(!is_valid_dentry(dentry));
+ unionfs_check_dentry(dentry);
unionfs_lock_dentry(dentry);
/* check if this unionfs directory is empty or not */
err = vfs_getxattr(hidden_dentry, (char*) name, value, size);
unionfs_unlock_dentry(dentry);
+ unionfs_check_dentry(dentry);
return err;
}
size, flags);
unionfs_unlock_dentry(dentry);
+ unionfs_check_dentry(dentry);
return err;
}
err = vfs_removexattr(hidden_dentry, (char*) name);
unionfs_unlock_dentry(dentry);
+ unionfs_check_dentry(dentry);
return err;
}
err = vfs_listxattr(hidden_dentry, encoded_list, size);
unionfs_unlock_dentry(dentry);
+ unionfs_check_dentry(dentry);
return err;
}