an upper object, and then a lower object, in a strict order to avoid
locking problems; in addition, Unionfs, as a fan-out file system, may
have to lock several lower inodes. We are currently looking into Lockdep
- to see how to make it aware of stackable file systems. In the meantime,
- if you get any warnings from Lockdep, you can safely ignore them (or feel
- free to report them to the Unionfs maintainers, just to be sure).
+ to see how to make it aware of stackable file systems. For now, we
+ temporarily disable lockdep when calling vfs methods on lower objects,
+ but only for those places where lockdep complained. While this solution
+ may seem unclean, it is not without precedent: other places in the kernel
+ also do similar temporary disabling, of course after carefully having
+ checked that it is the right thing to do. Anyway, you get any warnings
+ from Lockdep, please report them to the Unionfs maintainers.
For more information, see <http://unionfs.filesystems.org/>.
break;
}
+ /* see Documentation/filesystems/unionfs/issues.txt */
+ lockdep_off();
write_bytes =
output_file->f_op->write(output_file,
(char __user *)buf,
read_bytes,
&output_file->f_pos);
+ lockdep_on();
if ((write_bytes < 0) || (write_bytes < read_bytes)) {
err = write_bytes;
break;
struct dentry *lower_dir_dentry;
lower_dir_dentry = lock_parent(wh_dentry);
+ /* see Documentation/filesystems/unionfs/issues.txt */
+ lockdep_off();
err = vfs_unlink(lower_dir_dentry->d_inode, wh_dentry);
+ lockdep_on();
unlock_dir(lower_dir_dentry);
/*
/* found a .wh.foo entry, unlink it and then call vfs_link() */
lower_dir_dentry = lock_parent(whiteout_dentry);
err = is_robranch_super(new_dentry->d_sb, dbstart(new_dentry));
- if (!err)
+ if (!err) {
+ /* see Documentation/filesystems/unionfs/issues.txt */
+ lockdep_off();
err = vfs_unlink(lower_dir_dentry->d_inode,
whiteout_dentry);
+ lockdep_on();
+ }
fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
dir->i_nlink = unionfs_get_nlinks(dir);
BUG_ON(dbstart(old_dentry) != dbstart(new_dentry));
lower_dir_dentry = lock_parent(lower_new_dentry);
err = is_robranch(old_dentry);
- if (!err)
+ if (!err) {
+ /* see Documentation/filesystems/unionfs/issues.txt */
+ lockdep_off();
err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,
lower_new_dentry);
+ lockdep_on();
+ }
unlock_dir(lower_dir_dentry);
docopyup:
unionfs_lower_dentry(old_dentry);
lower_dir_dentry =
lock_parent(lower_new_dentry);
+ /*
+ * see
+ * Documentation/filesystems/unionfs/issues.txt
+ */
+ lockdep_off();
/* do vfs_link */
err = vfs_link(lower_old_dentry,
lower_dir_dentry->d_inode,
lower_new_dentry);
+ lockdep_on();
unlock_dir(lower_dir_dentry);
goto check_link;
}
dput(lower_wh_dentry);
}
+ err = is_robranch_super(old_dentry->d_sb, bindex);
+ if (err)
+ goto out;
+
dget(lower_old_dentry);
lower_old_dir_dentry = dget_parent(lower_old_dentry);
lower_new_dir_dentry = dget_parent(lower_new_dentry);
- lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
-
- err = is_robranch_super(old_dentry->d_sb, bindex);
- if (err)
- goto out_unlock;
-
/*
* ready to whiteout for old_dentry. caller will create the actual
* whiteout, and must dput(*wh_old)
old_dentry->d_name.len);
err = PTR_ERR(whname);
if (unlikely(IS_ERR(whname)))
- goto out_unlock;
+ goto out_dput;
*wh_old = lookup_one_len(whname, lower_old_dir_dentry,
old_dentry->d_name.len +
UNIONFS_WHLEN);
err = PTR_ERR(*wh_old);
if (IS_ERR(*wh_old)) {
*wh_old = NULL;
- goto out_unlock;
+ goto out_dput;
}
}
+ /* see Documentation/filesystems/unionfs/issues.txt */
+ lockdep_off();
+ lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
lower_new_dir_dentry->d_inode, lower_new_dentry);
-
-out_unlock:
unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
+ lockdep_on();
+out_dput:
dput(lower_old_dir_dentry);
dput(lower_new_dir_dentry);
dput(lower_old_dentry);
lower_inode = unionfs_lower_inode_idx(inode, bindex);
if (!lower_inode)
continue;
+ unionfs_set_lower_inode_idx(inode, bindex, NULL);
+ /* see Documentation/filesystems/unionfs/issues.txt */
+ lockdep_off();
iput(lower_inode);
+ lockdep_on();
}
}
/* avoid destroying the lower inode if the file is in use */
dget(lower_dentry);
err = is_robranch_super(dentry->d_sb, bindex);
- if (!err)
+ if (!err) {
+ /* see Documentation/filesystems/unionfs/issues.txt */
+ lockdep_off();
err = vfs_unlink(lower_dir_dentry->d_inode, lower_dentry);
+ lockdep_on();
+ }
/* if vfs_unlink succeeded, update our inode's times */
if (!err)
unionfs_copy_attr_times(dentry->d_inode);
/* avoid destroying the lower inode if the file is in use */
dget(lower_dentry);
err = is_robranch(dentry);
- if (!err)
+ if (!err) {
+ /* see Documentation/filesystems/unionfs/issues.txt */
+ lockdep_off();
err = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
+ lockdep_on();
+ }
dput(lower_dentry);
fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);