void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) { AuDebugOn(d1 == d2 || d1->d_inode == d2->d_inode || d1->d_sb != d2->d_sb); if (isdir && au_test_subdir(d1, d2)) { di_write_lock_child(d1); di_write_lock_child2(d2); } else { /* there should be no races */ di_write_lock_child(d2); di_write_lock_child2(d1); } }
int au_reval_dpath(struct dentry *dentry, unsigned int sigen) { int err; struct dentry *d, *parent; struct inode *inode; if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR)) return simple_reval_dpath(dentry, sigen); /* slow loop, keep it simple and stupid */ /* cf: au_cpup_dirs() */ err = 0; parent = NULL; while (au_digen_test(dentry, sigen)) { d = dentry; while (1) { dput(parent); parent = dget_parent(d); if (!au_digen_test(parent, sigen)) break; d = parent; } inode = d->d_inode; if (d != dentry) di_write_lock_child2(d); /* someone might update our dentry while we were sleeping */ if (au_digen_test(d, sigen)) { /* * todo: consolidate with simple_reval_dpath(), * do_refresh() and au_reval_for_attr(). */ di_read_lock_parent(parent, AuLock_IR); err = au_refresh_dentry(d, parent); di_read_unlock(parent, AuLock_IR); } if (d != dentry) di_write_unlock(d); dput(parent); if (unlikely(err)) break; } return err; }