/* * returns positive/negative dentry, NULL or an error. * NULL means whiteout-ed or not-found. */ static struct dentry* au_do_lookup(struct dentry *h_parent, struct dentry *dentry, aufs_bindex_t bindex, struct qstr *wh_name, struct au_do_lookup_args *args) { struct dentry *h_dentry; struct inode *h_inode, *inode; struct au_branch *br; int wh_found, opq; unsigned char wh_able; const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); wh_found = 0; br = au_sbr(dentry->d_sb, bindex); wh_able = !!au_br_whable(br->br_perm); if (wh_able) wh_found = au_wh_test(h_parent, wh_name, br, /*try_sio*/0); h_dentry = ERR_PTR(wh_found); if (!wh_found) goto real_lookup; if (unlikely(wh_found < 0)) goto out; /* We found a whiteout */ /* au_set_dbend(dentry, bindex); */ au_set_dbwh(dentry, bindex); if (!allow_neg) return NULL; /* success */ real_lookup: h_dentry = au_lkup_one(&dentry->d_name, h_parent, br, args->nd); if (IS_ERR(h_dentry)) goto out; h_inode = h_dentry->d_inode; if (!h_inode) { if (!allow_neg) goto out_neg; } else if (wh_found || (args->type && args->type != (h_inode->i_mode & S_IFMT))) goto out_neg; if (au_dbend(dentry) <= bindex) au_set_dbend(dentry, bindex); if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) au_set_dbstart(dentry, bindex); au_set_h_dptr(dentry, bindex, h_dentry); inode = dentry->d_inode; if (!h_inode || !S_ISDIR(h_inode->i_mode) || !wh_able || (inode && !S_ISDIR(inode->i_mode))) goto out; /* success */ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); opq = au_diropq_test(h_dentry, br); mutex_unlock(&h_inode->i_mutex); if (opq > 0) au_set_dbdiropq(dentry, bindex); else if (unlikely(opq < 0)) { au_set_h_dptr(dentry, bindex, NULL); h_dentry = ERR_PTR(opq); } goto out; out_neg: dput(h_dentry); h_dentry = NULL; out: return h_dentry; }
static int do_need_sigen_inc(int a, int b) { return au_br_whable(a) && !au_br_whable(b); }