static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent, struct au_branch *br) { int err; struct au_iattr ia; struct inode *h_inode; struct dentry *h_d; struct super_block *h_sb; err = 0; memset(&ia, -1, sizeof(ia)); h_sb = h_dentry->d_sb; h_inode = NULL; if (d_is_positive(h_dentry)) { h_inode = d_inode(h_dentry); au_iattr_save(&ia, h_inode); } else if (au_test_nfs(h_sb) || au_test_fuse(h_sb)) /* nfs d_revalidate may return 0 for negative dentry */ /* fuse d_revalidate always return 0 for negative dentry */ goto out; /* main purpose is namei.c:cached_lookup() and d_revalidate */ h_d = vfsub_lkup_one(&h_dentry->d_name, h_parent); err = PTR_ERR(h_d); if (IS_ERR(h_d)) goto out; err = 0; if (unlikely(h_d != h_dentry || d_inode(h_d) != h_inode || (h_inode && au_iattr_test(&ia, h_inode)))) err = au_busy_or_stale(); dput(h_d); out: AuTraceErr(err); return err; }
/* * simple tests for the adding inode operations. * following the checks in vfs, plus the parent-child relationship. */ int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, struct dentry *h_parent, int isdir, struct au_ndx *ndx) { int err, exist; struct dentry *h_dentry; struct inode *h_inode; umode_t h_mode; LKTRTrace("%.*s/%.*s, b%d, dir %d\n", AuDLNPair(h_parent), AuDLNPair(dentry), bindex, isdir); exist = !!dentry->d_inode; h_dentry = au_h_dptr(dentry, bindex); h_inode = h_dentry->d_inode; if (!exist) { err = -EEXIST; if (unlikely(h_inode)) goto out; } else { /* rename(2) case */ err = -EIO; if (unlikely(!h_inode || !h_inode->i_nlink)) goto out; h_mode = h_inode->i_mode; if (!isdir) { err = -EISDIR; if (unlikely(S_ISDIR(h_mode))) goto out; } else if (unlikely(!S_ISDIR(h_mode))) { err = -ENOTDIR; goto out; } } err = -EIO; /* expected parent dir is locked */ if (unlikely(h_parent != h_dentry->d_parent)) goto out; err = 0; if (au_opt_test(au_mntflags(dentry->d_sb), UDBA_INOTIFY)) { struct dentry *h_latest; struct qstr *qstr = &dentry->d_name; err = -EACCES; if (unlikely(au_test_h_perm (h_parent->d_inode, MAY_EXEC | MAY_WRITE, au_ftest_ndx(ndx->flags, DLGT)))) goto out; h_latest = au_sio_lkup_one(qstr->name, h_parent, qstr->len, ndx); err = PTR_ERR(h_latest); if (IS_ERR(h_latest)) goto out; err = -EIO; dput(h_latest); /* fuse d_revalidate always return 0 for negative dentries */ if (h_latest == h_dentry || au_test_fuse(h_dentry->d_sb)) err = 0; } out: AuTraceErr(err); return err; }