static void au_do_dir_ts(void *arg) { struct au_dir_ts_arg *a = arg; struct au_dtime dt; struct path h_path; struct inode *dir, *h_dir; struct super_block *sb; struct au_branch *br; struct au_hinode *hdir; int err; aufs_bindex_t btop, bindex; sb = a->dentry->d_sb; if (d_really_is_negative(a->dentry)) goto out; /* no dir->i_mutex lock */ aufs_read_lock(a->dentry, AuLock_DW); /* noflush */ dir = d_inode(a->dentry); btop = au_ibtop(dir); bindex = au_br_index(sb, a->brid); if (bindex < btop) goto out_unlock; br = au_sbr(sb, bindex); h_path.dentry = au_h_dptr(a->dentry, bindex); if (!h_path.dentry) goto out_unlock; h_path.mnt = au_br_mnt(br); au_dtime_store(&dt, a->dentry, &h_path); br = au_sbr(sb, btop); if (!au_br_writable(br->br_perm)) goto out_unlock; h_path.dentry = au_h_dptr(a->dentry, btop); h_path.mnt = au_br_mnt(br); err = vfsub_mnt_want_write(h_path.mnt); if (err) goto out_unlock; hdir = au_hi(dir, btop); au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); h_dir = au_h_iptr(dir, btop); if (h_dir->i_nlink && timespec_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) { dt.dt_h_path = h_path; au_dtime_revert(&dt); } au_hn_inode_unlock(hdir); vfsub_mnt_drop_write(h_path.mnt); au_cpup_attr_timesizes(dir); out_unlock: aufs_read_unlock(a->dentry, AuLock_DW); out: dput(a->dentry); au_nwt_done(&au_sbi(sb)->si_nowait); kfree(arg); }
/* * locking order * (VFS) * - src_dir and dir by lock_rename() * - inode if exitsts * (aufs) * - lock all * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, * + si_read_lock * + di_write_lock2_child() * + di_write_lock_child() * + ii_write_lock_child() * + di_write_lock_child2() * + ii_write_lock_child2() * + src_parent and parent * + di_write_lock_parent() * + ii_write_lock_parent() * + di_write_lock_parent2() * + ii_write_lock_parent2() * + lower src_dir and dir by vfsub_lock_rename() * + verify the every relationships between child and parent. if any * of them failed, unlock all and return -EBUSY. */ static void au_ren_unlock(struct au_ren_args *a) { struct super_block *sb; sb = a->dst_dentry->d_sb; if (au_ftest_ren(a->flags, MNT_WRITE)) vfsub_mnt_drop_write(a->br->br_mnt); vfsub_unlock_rename(a->src_h_parent, a->src_hdir, a->dst_h_parent, a->dst_hdir); }