/* todo: remove this */ static int h_d_revalidate(struct dentry *dentry, struct inode *inode, struct nameidata *nd, int do_udba) { int err; umode_t mode, h_mode; aufs_bindex_t bindex, btail, bstart, ibs, ibe; unsigned char plus, unhashed, is_root, h_plus; struct inode *h_inode, *h_cached_inode; struct dentry *h_dentry; struct qstr *name, *h_name; err = 0; plus = 0; mode = 0; ibs = -1; ibe = -1; unhashed = !!d_unhashed(dentry); is_root = !!IS_ROOT(dentry); name = &dentry->d_name; /* * Theoretically, REVAL test should be unnecessary in case of INOTIFY. * But inotify doesn't fire some necessary events, * IN_ATTRIB for atime/nlink/pageio * IN_DELETE for NFS dentry * Let's do REVAL test too. */ if (do_udba && inode) { mode = (inode->i_mode & S_IFMT); plus = (inode->i_nlink > 0); ibs = au_ibstart(inode); ibe = au_ibend(inode); } bstart = au_dbstart(dentry); btail = bstart; if (inode && S_ISDIR(inode->i_mode)) btail = au_dbtaildir(dentry); for (bindex = bstart; bindex <= btail; bindex++) { h_dentry = au_h_dptr(dentry, bindex); if (!h_dentry) continue; AuDbg("b%d, %.*s\n", bindex, AuDLNPair(h_dentry)); h_name = &h_dentry->d_name; if (unlikely(do_udba && !is_root && (unhashed != !!d_unhashed(h_dentry) || name->len != h_name->len || memcmp(name->name, h_name->name, name->len)) )) { AuDbg("unhash 0x%x 0x%x, %.*s %.*s\n", unhashed, d_unhashed(h_dentry), AuDLNPair(dentry), AuDLNPair(h_dentry)); goto err; } err = au_do_h_d_reval(h_dentry, nd, dentry, bindex); if (unlikely(err)) /* do not goto err, to keep the errno */ break; /* todo: plink too? */ if (!do_udba) continue; /* UDBA tests */ h_inode = h_dentry->d_inode; if (unlikely(!!inode != !!h_inode)) goto err; h_plus = plus; h_mode = mode; h_cached_inode = h_inode; if (h_inode) { h_mode = (h_inode->i_mode & S_IFMT); h_plus = (h_inode->i_nlink > 0); } if (inode && ibs <= bindex && bindex <= ibe) h_cached_inode = au_h_iptr(inode, bindex); if (unlikely(plus != h_plus || mode != h_mode || h_cached_inode != h_inode)) goto err; continue; err: err = -EINVAL; break; } return err; }
/* todo: remove this */ static int h_d_revalidate(struct dentry *dentry, struct inode *inode, unsigned int flags, int do_udba) { int err; umode_t mode, h_mode; aufs_bindex_t bindex, btail, bstart, ibs, ibe; unsigned char plus, unhashed, is_root, h_plus, h_nfs, tmpfile; struct inode *h_inode, *h_cached_inode; struct dentry *h_dentry; struct qstr *name, *h_name; err = 0; plus = 0; mode = 0; ibs = -1; ibe = -1; unhashed = !!d_unhashed(dentry); is_root = !!IS_ROOT(dentry); name = &dentry->d_name; tmpfile = au_di(dentry)->di_tmpfile; /* * Theoretically, REVAL test should be unnecessary in case of * {FS,I}NOTIFY. * But {fs,i}notify doesn't fire some necessary events, * IN_ATTRIB for atime/nlink/pageio * Let's do REVAL test too. */ if (do_udba && inode) { mode = (inode->i_mode & S_IFMT); plus = (inode->i_nlink > 0); ibs = au_ibstart(inode); ibe = au_ibend(inode); } bstart = au_dbstart(dentry); btail = bstart; if (inode && S_ISDIR(inode->i_mode)) btail = au_dbtaildir(dentry); for (bindex = bstart; bindex <= btail; bindex++) { h_dentry = au_h_dptr(dentry, bindex); if (!h_dentry) continue; AuDbg("b%d, %pd\n", bindex, h_dentry); h_nfs = !!au_test_nfs(h_dentry->d_sb); spin_lock(&h_dentry->d_lock); h_name = &h_dentry->d_name; if (unlikely(do_udba && !is_root && ((!h_nfs && (unhashed != !!d_unhashed(h_dentry) || (!tmpfile && !au_qstreq(name, h_name)) )) || (h_nfs && !(flags & LOOKUP_OPEN) && (h_dentry->d_flags & DCACHE_NFSFS_RENAMED))) )) { int h_unhashed; h_unhashed = d_unhashed(h_dentry); spin_unlock(&h_dentry->d_lock); AuDbg("unhash 0x%x 0x%x, %pd %pd\n", unhashed, h_unhashed, dentry, h_dentry); goto err; } spin_unlock(&h_dentry->d_lock); err = au_do_h_d_reval(h_dentry, flags, dentry, bindex); if (unlikely(err)) /* do not goto err, to keep the errno */ break; /* todo: plink too? */ if (!do_udba) continue; /* UDBA tests */ if (unlikely(!!inode != d_is_positive(h_dentry))) goto err; h_inode = NULL; if (d_is_positive(h_dentry)) h_inode = d_inode(h_dentry); h_plus = plus; h_mode = mode; h_cached_inode = h_inode; if (h_inode) { h_mode = (h_inode->i_mode & S_IFMT); h_plus = (h_inode->i_nlink > 0); } if (inode && ibs <= bindex && bindex <= ibe) h_cached_inode = au_h_iptr(inode, bindex); if (!h_nfs) { if (unlikely(plus != h_plus && !tmpfile)) goto err; } else { if (unlikely(!(h_dentry->d_flags & DCACHE_NFSFS_RENAMED) && !is_root && !IS_ROOT(h_dentry) && unhashed != d_unhashed(h_dentry))) goto err; } if (unlikely(mode != h_mode || h_cached_inode != h_inode)) goto err; continue; err: err = -EINVAL; break; } AuTraceErr(err); return err; }