static /* noinline_for_stack */ struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, ino_t dir_ino, struct au_nfsd_si_lock *nsi_lock) { struct dentry *dentry, *parent; struct path path; LKTRTrace("i%lu, diri%lu\n", (unsigned long)ino, (unsigned long)dir_ino); parent = sb->s_root; if (dir_ino != AUFS_ROOT_INO) { parent = decode_by_ino(sb, dir_ino, 0); dentry = parent; if (!parent) goto out; if (IS_ERR(parent)) goto out; AuDebugOn(au_test_anon(parent)); } else dget(parent); path.dentry = parent; path.mnt = au_sbi(sb)->si_mnt; dentry = au_lkup_by_ino(&path, ino, nsi_lock); dput(parent); out: AuTraceErrPtr(dentry); return dentry; }
static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, ino_t dir_ino, struct au_nfsd_si_lock *nsi_lock) { struct dentry *dentry; struct path path; if (dir_ino != AUFS_ROOT_INO) { path.dentry = decode_by_ino(sb, dir_ino, 0); dentry = path.dentry; if (!path.dentry || IS_ERR(path.dentry)) goto out; AuDebugOn(au_test_anon(path.dentry)); } else path.dentry = dget(sb->s_root); path.mnt = au_mnt_get(sb); dentry = au_lkup_by_ino(&path, ino, nsi_lock); path_put(&path); out: AuTraceErrPtr(dentry); return dentry; }
static struct dentry *decode_by_path(struct super_block *sb, aufs_bindex_t bindex, ino_t ino, __u32 *fh, int fh_len, struct au_nfsd_si_lock *nsi_lock) { struct dentry *dentry, *h_parent, *root; struct super_block *h_sb; char *pathname, *p; struct vfsmount *h_mnt; struct au_branch *br; int err; struct path path; br = au_sbr(sb, bindex); /* au_br_get(br); */ h_mnt = br->br_mnt; h_sb = h_mnt->mnt_sb; /* todo: call lower fh_to_dentry()? fh_to_parent()? */ h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), fh_len - Fh_tail, fh[Fh_h_type], h_acceptable, /*context*/NULL); dentry = h_parent; if (unlikely(!h_parent || IS_ERR(h_parent))) { AuWarn1("%s decode_fh failed, %ld\n", au_sbtype(h_sb), PTR_ERR(h_parent)); goto out; } dentry = NULL; if (unlikely(au_test_anon(h_parent))) { AuWarn1("%s decode_fh returned a disconnected dentry\n", au_sbtype(h_sb)); goto out_h_parent; } dentry = ERR_PTR(-ENOMEM); pathname = (void *)__get_free_page(GFP_NOFS); if (unlikely(!pathname)) goto out_h_parent; root = sb->s_root; path.mnt = h_mnt; di_read_lock_parent(root, !AuLock_IR); path.dentry = au_h_dptr(root, bindex); di_read_unlock(root, !AuLock_IR); p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb); dentry = (void *)p; if (IS_ERR(p)) goto out_pathname; si_read_unlock(sb); err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); dentry = ERR_PTR(err); if (unlikely(err)) goto out_relock; dentry = ERR_PTR(-ENOENT); AuDebugOn(au_test_anon(path.dentry)); if (unlikely(!path.dentry->d_inode)) goto out_path; if (ino != path.dentry->d_inode->i_ino) dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL); else dentry = dget(path.dentry); out_path: path_put(&path); out_relock: if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0)) if (!IS_ERR(dentry)) { dput(dentry); dentry = ERR_PTR(-ESTALE); } out_pathname: free_page((unsigned long)pathname); out_h_parent: dput(h_parent); out: /* au_br_put(br); */ AuTraceErrPtr(dentry); return dentry; }