static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a) { if (!a->rename_lock) { mutex_unlock(&a->mvd_h_src_dir->i_mutex); au_unpin(&a->pin); } else vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, a->mvd_h_dst_parent, a->mvd_hdir_dst); }
/* * 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)) mnt_drop_write(a->br->br_mnt); vfsub_unlock_rename(a->src_h_parent, a->src_hdir, a->dst_h_parent, a->dst_hdir); }
static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a) { if (!a->rename_lock) au_unpin(&a->mvd_pin_src); else { vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, a->mvd_h_dst_parent, a->mvd_hdir_dst); au_pin_hdir_lock(&a->mvd_pin_src); au_unpin(&a->mvd_pin_src); au_pin_hdir_lock(&a->mvd_pin_dst); } au_unpin(&a->mvd_pin_dst); }
/* lock them all */ static int au_do_lock(const unsigned char dmsg, struct au_mvd_args *a) { int err; struct dentry *h_trap; a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc); a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst); err = au_pin(&a->mvd_pin_dst, a->dentry, a->mvd_bdst, au_opt_udba(a->sb), AuPin_MNT_WRITE | AuPin_DI_LOCKED); AuTraceErr(err); if (unlikely(err)) { AU_MVD_PR(dmsg, "pin_dst failed\n"); goto out; } if (a->mvd_h_src_sb != a->mvd_h_dst_sb) { a->rename_lock = 0; au_pin_init(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, AuLsc_DI_PARENT, AuLsc_I_PARENT3, au_opt_udba(a->sb), AuPin_MNT_WRITE | AuPin_DI_LOCKED); err = au_do_pin(&a->mvd_pin_src); AuTraceErr(err); a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); if (unlikely(err)) { AU_MVD_PR(dmsg, "pin_src failed\n"); goto out_dst; } goto out; /* success */ } a->rename_lock = 1; au_pin_hdir_unlock(&a->mvd_pin_dst); err = au_pin(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, au_opt_udba(a->sb), AuPin_MNT_WRITE | AuPin_DI_LOCKED); AuTraceErr(err); a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); if (unlikely(err)) { AU_MVD_PR(dmsg, "pin_src failed\n"); au_pin_hdir_lock(&a->mvd_pin_dst); goto out_dst; } au_pin_hdir_unlock(&a->mvd_pin_src); h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, a->mvd_h_dst_parent, a->mvd_hdir_dst); if (h_trap) { err = (h_trap != a->mvd_h_src_parent); if (err) err = (h_trap != a->mvd_h_dst_parent); } BUG_ON(err); /* it should never happen */ if (unlikely(a->mvd_h_src_dir != au_pinned_h_dir(&a->mvd_pin_src))) { err = -EBUSY; AuTraceErr(err); vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, a->mvd_h_dst_parent, a->mvd_hdir_dst); au_pin_hdir_lock(&a->mvd_pin_src); au_unpin(&a->mvd_pin_src); au_pin_hdir_lock(&a->mvd_pin_dst); goto out_dst; } goto out; /* success */ out_dst: au_unpin(&a->mvd_pin_dst); out: AuTraceErr(err); return err; }