/* common functions to regular file and dir */ struct file *hidden_open(struct dentry *dentry, aufs_bindex_t bindex, int flags) { struct dentry *hidden_dentry; struct inode *hidden_inode; struct super_block *sb; struct vfsmount *hidden_mnt; struct file *hidden_file; struct aufs_branch *br; loff_t old_size; int udba; LKTRTrace("%.*s, b%d, flags 0%o\n", DLNPair(dentry), bindex, flags); DEBUG_ON(!dentry); hidden_dentry = au_h_dptr_i(dentry, bindex); DEBUG_ON(!hidden_dentry); hidden_inode = hidden_dentry->d_inode; DEBUG_ON(!hidden_inode); sb = dentry->d_sb; udba = au_flag_test(sb, AuFlag_UDBA_INOTIFY); if (unlikely(udba)) { // test here? } br = stobr(sb, bindex); br_get(br); /* drop flags for writing */ if (test_ro(sb, bindex, dentry->d_inode)) flags = au_file_roflags(flags); flags &= ~O_CREAT; spin_lock(&hidden_inode->i_lock); old_size = i_size_read(hidden_inode); spin_unlock(&hidden_inode->i_lock); //DbgSleep(3); dget(hidden_dentry); hidden_mnt = mntget(br->br_mnt); hidden_file = dentry_open(hidden_dentry, hidden_mnt, flags); //if (LktrCond) {fput(hidden_file); hidden_file = ERR_PTR(-1);} if (!IS_ERR(hidden_file)) { #if 0 // remove this if (/* old_size && */ (flags & O_TRUNC)) { au_direval_dec(dentry); if (!IS_ROOT(dentry)) au_direval_dec(dentry->d_parent); } #endif return hidden_file; } br_put(br); TraceErrPtr(hidden_file); return hidden_file; }
static struct dentry * lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup, struct dtime *dt) { struct dentry *wh_dentry; int err, need_wh; struct dentry *hidden_parent, *parent; struct inode *dir, *h_dir; struct lkup_args lkup; LKTRTrace("%.*s, isdir %d\n", DLNPair(dentry), isdir); err = need_wh = wr_dir_need_wh(dentry, isdir, bcpup, NULL); //err = -1; wh_dentry = ERR_PTR(err); if (unlikely(err < 0)) goto out; parent = dentry->d_parent; dir = parent->d_inode; hidden_parent = au_h_dptr_i(parent, *bcpup); h_dir = hidden_parent->d_inode; hdir_lock(h_dir, dir, *bcpup); dtime_store(dt, parent, hidden_parent); if (!need_wh) return NULL; /* success, no need to create whiteout */ lkup.nfsmnt = au_nfsmnt(dentry->d_sb, *bcpup); lkup.dlgt = need_dlgt(dentry->d_sb); wh_dentry = simple_create_wh(dentry, *bcpup, hidden_parent, &lkup); //wh_dentry = ERR_PTR(-1); if (!IS_ERR(wh_dentry)) goto out; /* success */ /* returns with the parent is locked and wh_dentry is DGETed */ hdir_unlock(h_dir, dir, *bcpup); out: TraceErrPtr(wh_dentry); return wh_dentry; }
static struct dentry *lkup_hash(const char *name, struct dentry *parent, int len, struct lkup_args *lkup) { struct dentry *dentry; char *p; unsigned long hash; struct qstr this; unsigned int c; struct nameidata tmp_nd; dentry = ERR_PTR(-EACCES); this.name = name; this.len = len; if (unlikely(!len)) goto out; p = (void*)name; hash = init_name_hash(); while (len--) { c = *p++; if (unlikely(c == '/' || c == '\0')) goto out; hash = partial_name_hash(c, hash); } this.hash = end_name_hash(hash); memset(&tmp_nd, 0, sizeof(tmp_nd)); tmp_nd.dentry = dget(parent); tmp_nd.mnt = mntget(lkup->nfsmnt); #ifndef CONFIG_AUFS_DLGT dentry = __lookup_hash(&this, parent, &tmp_nd); #else if (!lkup->dlgt) dentry = __lookup_hash(&this, parent, &tmp_nd); else { int wkq_err; struct lookup_hash_args args = { .errp = &dentry, .name = &this, .base = parent, .nd = &tmp_nd }; wkq_err = au_wkq_wait(call_lookup_hash, &args, /*dlgt*/1); if (unlikely(wkq_err)) dentry = ERR_PTR(wkq_err); } #endif path_release(&tmp_nd); out: TraceErrPtr(dentry); return dentry; } #elif defined(CONFIG_AUFS_DLGT) static struct dentry *lkup_hash(const char *name, struct dentry *parent, int len, struct lkup_args *lkup) { return ERR_PTR(-ENOSYS); } #endif #ifdef CONFIG_AUFS_DLGT struct lookup_one_len_args { struct dentry **errp; const char *name; struct dentry *parent; int len; }; static void call_lookup_one_len(void *args) { struct lookup_one_len_args *a = args; *a->errp = lookup_one_len(a->name, a->parent, a->len); } #endif /* CONFIG_AUFS_DLGT */ #if defined(CONFIG_AUFS_LHASH_PATCH) || defined(CONFIG_AUFS_DLGT) /* cf. lookup_one_len() in linux/fs/namei.c */ struct dentry *lkup_one(const char *name, struct dentry *parent, int len, struct lkup_args *lkup) { struct dentry *dentry; LKTRTrace("%.*s/%.*s, lkup{%p, %d}\n", DLNPair(parent), len, name, lkup->nfsmnt, lkup->dlgt); if (!lkup->nfsmnt) { #ifndef CONFIG_AUFS_DLGT dentry = lookup_one_len(name, parent, len); #else if (!lkup->dlgt) dentry = lookup_one_len(name, parent, len); else { int wkq_err; struct lookup_one_len_args args = { .errp = &dentry, .name = name, .parent = parent, .len = len }; wkq_err = au_wkq_wait(call_lookup_one_len, &args, /*dlgt*/1); if (unlikely(wkq_err)) dentry = ERR_PTR(wkq_err); } #endif } else