/* ** looks up the dentry of the parent directory for child. ** taken from ext2_get_parent */ struct dentry *reiserfs_get_parent(struct dentry *child) { int retval; struct inode * inode = NULL; struct reiserfs_dir_entry de; INITIALIZE_PATH (path_to_entry); struct dentry *parent; struct inode *dir = child->d_inode ; if (dir->i_nlink == 0) { return ERR_PTR(-ENOENT); } de.de_gen_number_bit_string = NULL; reiserfs_write_lock(dir->i_sb); retval = reiserfs_find_entry (dir, "..", 2, &path_to_entry, &de); pathrelse (&path_to_entry); if (retval != NAME_FOUND) { reiserfs_write_unlock(dir->i_sb); return ERR_PTR(-ENOENT); } inode = reiserfs_iget (dir->i_sb, (struct cpu_key *)&(de.de_dir_id)); reiserfs_write_unlock(dir->i_sb); if (!inode || IS_ERR(inode)) { return ERR_PTR(-EACCES); } parent = d_alloc_anon(inode); if (!parent) { iput(inode); parent = ERR_PTR(-ENOMEM); } return parent; }
static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj) { struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_inum_host *inum = inum_obj; struct inode *inode; struct dentry *dentry; inode = gfs2_ilookup(sb, inum->no_addr); if (inode) { if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) { iput(inode); return ERR_PTR(-ESTALE); } } else { inode = gfs2_lookup_by_inum(sdp, inum->no_addr, &inum->no_formal_ino, GFS2_BLKST_DINODE); if (inode == ERR_PTR(-ENOENT)) inode = gfs2_ilookup(sb, inum->no_addr); } if (IS_ERR(inode)) return ERR_CAST(inode); dentry = d_alloc_anon(inode); if (!dentry) { iput(inode); return ERR_PTR(-ENOMEM); } dentry->d_op = &gfs2_dops; return dentry; }
struct dentry *jfs_get_parent(struct dentry *dentry) { struct super_block *sb = dentry->d_inode->i_sb; struct dentry *parent = ERR_PTR(-ENOENT); struct inode *inode; unsigned long parent_ino; parent_ino = le32_to_cpu(JFS_IP(dentry->d_inode)->i_dtroot.header.idotdot); inode = iget(sb, parent_ino); if (inode) { if (is_bad_inode(inode)) { iput(inode); parent = ERR_PTR(-EACCES); } else { parent = d_alloc_anon(inode); if (!parent) { parent = ERR_PTR(-ENOMEM); iput(inode); } } } return parent; }
STATIC struct dentry * xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fileid_type) { struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid; struct inode *inode = NULL; struct dentry *result; switch (fileid_type) { case FILEID_INO32_GEN_PARENT: inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino, fid->i32.parent_gen); break; case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG: inode = xfs_nfs_get_inode(sb, fid64->parent_ino, fid64->parent_gen); break; } if (!inode) return NULL; if (IS_ERR(inode)) return ERR_PTR(PTR_ERR(inode)); result = d_alloc_anon(inode); if (!result) { iput(inode); return ERR_PTR(-ENOMEM); } return result; }
static struct dentry *ocfs2_get_dentry(struct super_block *sb, struct ocfs2_inode_handle *handle) { struct inode *inode; struct dentry *result; mlog_entry("(0x%p, 0x%p)\n", sb, handle); if (handle->ih_blkno == 0) { mlog_errno(-ESTALE); return ERR_PTR(-ESTALE); } inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0, 0); if (IS_ERR(inode)) return (void *)inode; if (handle->ih_generation != inode->i_generation) { iput(inode); return ERR_PTR(-ESTALE); } result = d_alloc_anon(inode); if (!result) { iput(inode); mlog_errno(-ENOMEM); return ERR_PTR(-ENOMEM); } result->d_op = &ocfs2_dentry_ops; mlog_exit_ptr(result); return result; }
struct dentry *efs_get_parent(struct dentry *child) { struct dentry *parent; struct inode *inode; efs_ino_t ino; int error; lock_kernel(); error = -ENOENT; ino = efs_find_entry(child->d_inode, "..", 2); if (!ino) goto fail; error = -EACCES; inode = iget(child->d_inode->i_sb, ino); if (!inode) goto fail; error = -ENOMEM; parent = d_alloc_anon(inode); if (!parent) goto fail_iput; unlock_kernel(); return parent; fail_iput: iput(inode); fail: unlock_kernel(); return ERR_PTR(error); }
static struct dentry * isofs_export_iget(struct super_block *sb, unsigned long block, unsigned long offset, __u32 generation) { struct inode *inode; struct dentry *result; if (block == 0) return ERR_PTR(-ESTALE); inode = isofs_iget(sb, block, offset); if (inode == NULL) return ERR_PTR(-ENOMEM); if (is_bad_inode(inode) || (generation && inode->i_generation != generation)) { iput(inode); return ERR_PTR(-ESTALE); } result = d_alloc_anon(inode); if (!result) { iput(inode); return ERR_PTR(-ENOMEM); } return result; }
static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp) { __u32 *objp = vobjp; unsigned long nodeid = objp[0]; __u32 generation = objp[1]; struct inode *inode; struct dentry *entry; if (nodeid == 0) return ERR_PTR(-ESTALE); inode = ilookup5(sb, nodeid, fuse_inode_eq, &nodeid); if (!inode) return ERR_PTR(-ESTALE); if (inode->i_generation != generation) { iput(inode); return ERR_PTR(-ESTALE); } entry = d_alloc_anon(inode); if (!entry) { iput(inode); return ERR_PTR(-ENOMEM); } return entry; }
/** * ntfs_get_dentry - find a dentry for the inode from a file handle sub-fragment * @sb: super block identifying the mounted ntfs volume * @fh: the file handle sub-fragment * * Find a dentry for the inode given a file handle sub-fragment. This function * is called from fs/exportfs/expfs.c::find_exported_dentry() which in turn is * called from the default ->decode_fh() which is export_decode_fh() in the * same file. The code is closely based on the default ->get_dentry() helper * fs/exportfs/expfs.c::get_object(). * * The @fh contains two 32-bit unsigned values, the first one is the inode * number and the second one is the inode generation. * * Return the dentry on success or the error code on error (IS_ERR() is true). */ static struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh) { struct inode *vi; struct dentry *dent; unsigned long ino = ((u32 *)fh)[0]; u32 gen = ((u32 *)fh)[1]; ntfs_debug("Entering for inode 0x%lx, generation 0x%x.", ino, gen); vi = ntfs_iget(sb, ino); if (IS_ERR(vi)) { ntfs_error(sb, "Failed to get inode 0x%lx.", ino); return (struct dentry *)vi; } if (unlikely(is_bad_inode(vi) || vi->i_generation != gen)) { /* We didn't find the right inode. */ ntfs_error(sb, "Inode 0x%lx, bad count: %d %d or version 0x%x " "0x%x.", vi->i_ino, vi->i_nlink, atomic_read(&vi->i_count), vi->i_generation, gen); iput(vi); return ERR_PTR(-ESTALE); } /* Now find a dentry. If possible, get a well-connected one. */ dent = d_alloc_anon(vi); if (unlikely(!dent)) { iput(vi); return ERR_PTR(-ENOMEM); } ntfs_debug("Done for inode 0x%lx, generation 0x%x.", ino, gen); return dent; }
STATIC struct dentry * linvfs_get_dentry( struct super_block *sb, void *data) { vnode_t *vp; struct inode *inode; struct dentry *result; xfs_fid2_t xfid; vfs_t *vfsp = LINVFS_GET_VFS(sb); int error; xfid.fid_len = sizeof(xfs_fid2_t) - sizeof(xfid.fid_len); xfid.fid_pad = 0; xfid.fid_gen = ((__u32 *)data)[1]; xfid.fid_ino = ((__u32 *)data)[0]; VFS_VGET(vfsp, &vp, (fid_t *)&xfid, error); if (error || vp == NULL) return ERR_PTR(-ESTALE) ; inode = LINVFS_GET_IP(vp); result = d_alloc_anon(inode); if (!result) { iput(inode); return ERR_PTR(-ENOMEM); } return result; }
STATIC struct dentry * linvfs_get_parent( struct dentry *child) { int error; vnode_t *vp, *cvp; struct dentry *parent; struct inode *ip = NULL; struct dentry dotdot; dotdot.d_name.name = ".."; dotdot.d_name.len = 2; dotdot.d_inode = 0; cvp = NULL; vp = LINVFS_GET_VP(child->d_inode); VOP_LOOKUP(vp, &dotdot, &cvp, 0, NULL, NULL, error); if (!error) { ASSERT(cvp); ip = LINVFS_GET_IP(cvp); if (!ip) { VN_RELE(cvp); return ERR_PTR(-EACCES); } } if (error) return ERR_PTR(-error); parent = d_alloc_anon(ip); if (!parent) { VN_RELE(cvp); parent = ERR_PTR(-ENOMEM); } return parent; }
static struct dentry *gfs2_get_parent(struct dentry *child) { struct qstr dotdot; struct inode *inode; struct dentry *dentry; gfs2_str2qstr(&dotdot, ".."); inode = gfs2_lookupi(child->d_inode, &dotdot, 1, NULL); if (!inode) return ERR_PTR(-ENOENT); /* * In case of an error, @inode carries the error value, and we * have to return that as a(n invalid) pointer to dentry. */ if (IS_ERR(inode)) return ERR_PTR(PTR_ERR(inode)); dentry = d_alloc_anon(inode); if (!dentry) { iput(inode); return ERR_PTR(-ENOMEM); } dentry->d_op = &gfs2_dops; return dentry; }
static struct dentry *ocfs2_get_parent(struct dentry *child) { int status; u64 blkno; struct dentry *parent; struct inode *inode; struct inode *dir = child->d_inode; struct buffer_head *dirent_bh = NULL; struct ocfs2_dir_entry *dirent; mlog_entry("(0x%p, '%.*s')\n", child, child->d_name.len, child->d_name.name); mlog(0, "find parent of directory %llu\n", (unsigned long long)OCFS2_I(dir)->ip_blkno); status = ocfs2_meta_lock(dir, NULL, 0); if (status < 0) { if (status != -ENOENT) mlog_errno(status); parent = ERR_PTR(status); goto bail; } status = ocfs2_find_files_on_disk("..", 2, &blkno, dir, &dirent_bh, &dirent); if (status < 0) { parent = ERR_PTR(-ENOENT); goto bail_unlock; } inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0); if (IS_ERR(inode)) { mlog(ML_ERROR, "Unable to create inode %llu\n", (unsigned long long)blkno); parent = ERR_PTR(-EACCES); goto bail_unlock; } parent = d_alloc_anon(inode); if (!parent) { iput(inode); parent = ERR_PTR(-ENOMEM); } parent->d_op = &ocfs2_dentry_ops; bail_unlock: ocfs2_meta_unlock(dir, 0); if (dirent_bh) brelse(dirent_bh); bail: mlog_exit_ptr(parent); return parent; }
static struct dentry * zpl_dentry_obtain_alias(struct inode *ip) { struct dentry *result; #ifdef HAVE_D_OBTAIN_ALIAS result = d_obtain_alias(ip); #else result = d_alloc_anon(ip); if (result == NULL) { iput(ip); result = ERR_PTR(-ENOMEM); } #endif /* HAVE_D_OBTAIN_ALIAS */ return result; }
static struct dentry *export_iget(struct super_block *sb, unsigned long ino, __u32 generation) { /* iget isn't really right if the inode is currently unallocated!! * This should really all be done inside each filesystem * * ext2fs' read_inode has been strengthed to return a bad_inode if * the inode had been deleted. * * Currently we don't know the generation for parent directory, so * a generation of 0 means "accept any" */ struct inode *inode; struct dentry *result; if (ino == 0) return ERR_PTR(-ESTALE); inode = iget(sb, ino); if (inode == NULL) return ERR_PTR(-ENOMEM); if (is_bad_inode(inode) || (generation && inode->i_generation != generation) ) { /* we didn't find the right inode.. */ dprintk("fh_verify: Inode %lu, Bad count: %d %d or version %u %u\n", inode->i_ino, inode->i_nlink, atomic_read(&inode->i_count), inode->i_generation, generation); iput(inode); return ERR_PTR(-ESTALE); } /* now to find a dentry. * If possible, get a well-connected one */ result = d_alloc_anon(inode); if (!result) { iput(inode); return ERR_PTR(-ENOMEM); } return result; }
STATIC struct dentry * xfs_fs_get_parent( struct dentry *child) { int error; bhv_vnode_t *cvp; struct dentry *parent; cvp = NULL; error = xfs_lookup(XFS_I(child->d_inode), &dotdot, &cvp); if (unlikely(error)) return ERR_PTR(-error); parent = d_alloc_anon(vn_to_inode(cvp)); if (unlikely(!parent)) { VN_RELE(cvp); return ERR_PTR(-ENOMEM); } return parent; }
static struct dentry *ext2_get_dentry(struct super_block *sb, void *vobjp) { __u32 *objp = vobjp; unsigned long ino = objp[0]; __u32 generation = objp[1]; struct inode *inode; struct dentry *result; if (ino < EXT2_FIRST_INO(sb) && ino != EXT2_ROOT_INO) return ERR_PTR(-ESTALE); if (ino > le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count)) return ERR_PTR(-ESTALE); /* iget isn't really right if the inode is currently unallocated!! * ext2_read_inode currently does appropriate checks, but * it might be "neater" to call ext2_get_inode first and check * if the inode is valid..... */ inode = iget(sb, ino); if (inode == NULL) return ERR_PTR(-ENOMEM); if (is_bad_inode(inode) || (generation && inode->i_generation != generation)) { /* we didn't find the right inode.. */ iput(inode); return ERR_PTR(-ESTALE); } /* now to find a dentry. * If possible, get a well-connected one */ result = d_alloc_anon(inode); if (!result) { iput(inode); return ERR_PTR(-ENOMEM); } return result; }
struct dentry *ext2_get_parent(struct dentry *child) { unsigned long ino; struct dentry *parent; struct inode *inode; struct dentry dotdot; dotdot.d_name.name = ".."; dotdot.d_name.len = 2; ino = ext2_inode_by_name(child->d_inode, &dotdot); if (!ino) return ERR_PTR(-ENOENT); inode = iget(child->d_inode->i_sb, ino); if (!inode) return ERR_PTR(-EACCES); parent = d_alloc_anon(inode); if (!parent) { iput(inode); parent = ERR_PTR(-ENOMEM); } return parent; }
STATIC int xfs_open_by_handle( xfs_mount_t *mp, unsigned long arg, struct file *parfilp, struct inode *parinode) { int error; int new_fd; int permflag; struct file *filp; struct inode *inode; struct dentry *dentry; vnode_t *vp; xfs_fsop_handlereq_t hreq; error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg, sizeof(xfs_fsop_handlereq_t), &hreq, &vp, &inode); if (error) return -error; /* Restrict xfs_open_by_handle to directories & regular files. */ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { iput(inode); return -XFS_ERROR(EINVAL); } #if BITS_PER_LONG != 32 hreq.oflags |= O_LARGEFILE; #endif /* Put open permission in namei format. */ permflag = hreq.oflags; if ((permflag+1) & O_ACCMODE) permflag++; if (permflag & O_TRUNC) permflag |= 2; if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) && (permflag & FMODE_WRITE) && IS_APPEND(inode)) { iput(inode); return -XFS_ERROR(EPERM); } if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode)) { iput(inode); return -XFS_ERROR(EACCES); } /* Can't write directories. */ if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) { iput(inode); return -XFS_ERROR(EISDIR); } if ((new_fd = get_unused_fd()) < 0) { iput(inode); return new_fd; } dentry = d_alloc_anon(inode); if (dentry == NULL) { iput(inode); put_unused_fd(new_fd); return -XFS_ERROR(ENOMEM); } /* Ensure umount returns EBUSY on umounts while this file is open. */ mntget(parfilp->f_vfsmnt); /* Create file pointer. */ filp = dentry_open(dentry, parfilp->f_vfsmnt, hreq.oflags); if (IS_ERR(filp)) { put_unused_fd(new_fd); return -XFS_ERROR(-PTR_ERR(filp)); } if (inode->i_mode & S_IFREG) filp->f_op = &linvfs_invis_file_operations; fd_install(new_fd, filp); return new_fd; }
/* * get an NFS2/NFS3 root dentry from the root filehandle */ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) { struct nfs_server *server = NFS_SB(sb); struct nfs_fsinfo fsinfo; struct nfs_fattr fattr; struct dentry *mntroot; struct inode *inode; int error; /* create a dummy root dentry with dummy inode for this superblock */ if (!sb->s_root) { struct nfs_fh dummyfh; struct dentry *root; struct inode *iroot; memset(&dummyfh, 0, sizeof(dummyfh)); memset(&fattr, 0, sizeof(fattr)); nfs_fattr_init(&fattr); fattr.valid = NFS_ATTR_FATTR; fattr.type = NFDIR; fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; fattr.nlink = 2; iroot = nfs_fhget(sb, &dummyfh, &fattr); if (IS_ERR(iroot)) return ERR_PTR(PTR_ERR(iroot)); root = d_alloc_root(iroot); if (!root) { iput(iroot); return ERR_PTR(-ENOMEM); } sb->s_root = root; } /* get the actual root for this mount */ fsinfo.fattr = &fattr; error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); if (error < 0) { dprintk("nfs_get_root: getattr error = %d\n", -error); return ERR_PTR(error); } inode = nfs_fhget(sb, mntfh, fsinfo.fattr); if (IS_ERR(inode)) { dprintk("nfs_get_root: get root inode failed\n"); return ERR_PTR(PTR_ERR(inode)); } /* root dentries normally start off anonymous and get spliced in later * if the dentry tree reaches them; however if the dentry already * exists, we'll pick it up at this point and use it as the root */ mntroot = d_alloc_anon(inode); if (!mntroot) { iput(inode); dprintk("nfs_get_root: get root dentry failed\n"); return ERR_PTR(-ENOMEM); } security_d_instantiate(mntroot, inode); if (!mntroot->d_op) mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; return mntroot; }
static int #ifdef HAVE_ENCODE_FH_WITH_INODE zpl_encode_fh(struct inode *ip, __u32 *fh, int *max_len, struct inode *parent) { #else zpl_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, int connectable) { struct inode *ip = dentry->d_inode; #endif /* HAVE_ENCODE_FH_WITH_INODE */ fid_t *fid = (fid_t *)fh; int len_bytes, rc; len_bytes = *max_len * sizeof (__u32); if (len_bytes < offsetof(fid_t, fid_data)) return (255); fid->fid_len = len_bytes - offsetof(fid_t, fid_data); if (zfsctl_is_node(ip)) rc = zfsctl_fid(ip, fid); else rc = zfs_fid(ip, fid); len_bytes = offsetof(fid_t, fid_data) + fid->fid_len; *max_len = roundup(len_bytes, sizeof (__u32)) / sizeof (__u32); return (rc == 0 ? FILEID_INO32_GEN : 255); } static struct dentry * zpl_dentry_obtain_alias(struct inode *ip) { struct dentry *result; #ifdef HAVE_D_OBTAIN_ALIAS result = d_obtain_alias(ip); #else result = d_alloc_anon(ip); if (result == NULL) { VN_RELE(ip); result = ERR_PTR(-ENOMEM); } #endif /* HAVE_D_OBTAIN_ALIAS */ return (result); } static struct dentry * zpl_fh_to_dentry(struct super_block *sb, struct fid *fh, int fh_len, int fh_type) { fid_t *fid = (fid_t *)fh; struct inode *ip; int len_bytes, rc; len_bytes = fh_len * sizeof (__u32); if (fh_type != FILEID_INO32_GEN || len_bytes < offsetof(fid_t, fid_data) || len_bytes < offsetof(fid_t, fid_data) + fid->fid_len) return (ERR_PTR(-EINVAL)); rc = zfs_vget(sb, &ip, fid); if (rc != 0) return (ERR_PTR(-rc)); ASSERT((ip != NULL) && !IS_ERR(ip)); return (zpl_dentry_obtain_alias(ip)); }
static struct dentry *gfs2_get_dentry(struct super_block *sb, struct gfs2_inum_host *inum) { struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_fh_obj *fh_obj = (struct gfs2_fh_obj *)inum_obj; struct gfs2_holder i_gh, ri_gh, rgd_gh; struct gfs2_rgrpd *rgd; struct inode *inode; struct dentry *dentry; int error; /* System files? */ inode = gfs2_ilookup(sb, inum); if (inode) { if (GFS2_I(inode)->i_num.no_formal_ino != inum->no_formal_ino) { iput(inode); return ERR_PTR(-ESTALE); } goto out_inode; } error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) return ERR_PTR(error); error = gfs2_rindex_hold(sdp, &ri_gh); if (error) goto fail; error = -EINVAL; rgd = gfs2_blk2rgrpd(sdp, inum->no_addr); if (!rgd) goto fail_rindex; error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh); if (error) goto fail_rindex; error = -ESTALE; if (gfs2_get_block_type(rgd, inum->no_addr) != GFS2_BLKST_DINODE) goto fail_rgd; gfs2_glock_dq_uninit(&rgd_gh); gfs2_glock_dq_uninit(&ri_gh); inode = gfs2_inode_lookup(sb, inum, fh_obj->imode); if (!inode) goto fail; if (IS_ERR(inode)) { error = PTR_ERR(inode); goto fail; } error = gfs2_inode_refresh(GFS2_I(inode)); if (error) { iput(inode); goto fail; } error = -EIO; if (GFS2_I(inode)->i_di.di_flags & GFS2_DIF_SYSTEM) { iput(inode); goto fail; } gfs2_glock_dq_uninit(&i_gh); out_inode: dentry = d_alloc_anon(inode); if (!dentry) { iput(inode); return ERR_PTR(-ENOMEM); } dentry->d_op = &gfs2_dops; return dentry; fail_rgd: gfs2_glock_dq_uninit(&rgd_gh); fail_rindex: gfs2_glock_dq_uninit(&ri_gh); fail: gfs2_glock_dq_uninit(&i_gh); return ERR_PTR(error); }
static int #ifdef HAVE_ENCODE_FH_WITH_INODE zpl_encode_fh(struct inode *ip, __u32 *fh, int *max_len, struct inode *parent) { #else zpl_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, int connectable) { struct inode *ip = dentry->d_inode; #endif /* HAVE_ENCODE_FH_WITH_INODE */ fstrans_cookie_t cookie; fid_t *fid = (fid_t *)fh; int len_bytes, rc; len_bytes = *max_len * sizeof (__u32); if (len_bytes < offsetof(fid_t, fid_data)) return (255); fid->fid_len = len_bytes - offsetof(fid_t, fid_data); cookie = spl_fstrans_mark(); if (zfsctl_is_node(ip)) rc = zfsctl_fid(ip, fid); else rc = zfs_fid(ip, fid); spl_fstrans_unmark(cookie); len_bytes = offsetof(fid_t, fid_data) + fid->fid_len; *max_len = roundup(len_bytes, sizeof (__u32)) / sizeof (__u32); return (rc == 0 ? FILEID_INO32_GEN : 255); } static struct dentry * zpl_dentry_obtain_alias(struct inode *ip) { struct dentry *result; #ifdef HAVE_D_OBTAIN_ALIAS result = d_obtain_alias(ip); #else result = d_alloc_anon(ip); if (result == NULL) { VN_RELE(ip); result = ERR_PTR(-ENOMEM); } #endif /* HAVE_D_OBTAIN_ALIAS */ return (result); } static struct dentry * zpl_fh_to_dentry(struct super_block *sb, struct fid *fh, int fh_len, int fh_type) { fid_t *fid = (fid_t *)fh; fstrans_cookie_t cookie; struct inode *ip; int len_bytes, rc; len_bytes = fh_len * sizeof (__u32); if (fh_type != FILEID_INO32_GEN || len_bytes < offsetof(fid_t, fid_data) || len_bytes < offsetof(fid_t, fid_data) + fid->fid_len) return (ERR_PTR(-EINVAL)); cookie = spl_fstrans_mark(); rc = zfs_vget(sb, &ip, fid); spl_fstrans_unmark(cookie); if (rc) { /* * If we see ENOENT it might mean that an NFSv4 * client * is using a cached inode value in a file handle and * that the sought after file has had its inode changed * by a third party. So change the error to ESTALE * which will trigger a full lookup by the client and * will find the new filename/inode pair if it still * exists. */ if (rc == ENOENT) rc = ESTALE; return (ERR_PTR(-rc)); } ASSERT((ip != NULL) && !IS_ERR(ip)); return (zpl_dentry_obtain_alias(ip)); }
osi_UFSOpen(afs_int32 ainode) #endif { register struct osi_file *afile = NULL; extern int cacheDiskType; struct inode *tip = NULL; struct dentry *dp = NULL; struct file *filp = NULL; #if !defined(HAVE_IGET) || defined(LINUX_USE_FH) struct fid fid; #endif AFS_STATCNT(osi_UFSOpen); if (cacheDiskType != AFS_FCACHE_TYPE_UFS) { osi_Panic("UFSOpen called for non-UFS cache\n"); } if (!afs_osicred_initialized) { /* valid for alpha_osf, SunOS, Ultrix */ memset((char *)&afs_osi_cred, 0, sizeof(struct AFS_UCRED)); crhold(&afs_osi_cred); /* don't let it evaporate, since it is static */ afs_osicred_initialized = 1; } afile = (struct osi_file *)osi_AllocLargeSpace(sizeof(struct osi_file)); AFS_GUNLOCK(); if (!afile) { osi_Panic("osi_UFSOpen: Failed to allocate %d bytes for osi_file.\n", sizeof(struct osi_file)); } memset(afile, 0, sizeof(struct osi_file)); #if defined(HAVE_IGET) tip = iget(afs_cacheSBp, (u_long) ainode); if (!tip) osi_Panic("Can't get inode %d\n", ainode); dp = d_alloc_anon(tip); #else #if defined(LINUX_USE_FH) dp = afs_cacheSBp->s_export_op->fh_to_dentry(afs_cacheSBp, fh, sizeof(struct fid), fh_type); #else fid.i32.ino = ainode; fid.i32.gen = 0; dp = afs_cacheSBp->s_export_op->fh_to_dentry(afs_cacheSBp, &fid, sizeof(fid), FILEID_INO32_GEN); #endif if (!dp) osi_Panic("Can't get dentry\n"); tip = dp->d_inode; #endif tip->i_flags |= MS_NOATIME; /* Disable updating access times. */ #if defined(STRUCT_TASK_HAS_CRED) filp = dentry_open(dp, mntget(afs_cacheMnt), O_RDWR, current_cred()); #else filp = dentry_open(dp, mntget(afs_cacheMnt), O_RDWR); #endif if (IS_ERR(filp)) #if defined(LINUX_USE_FH) osi_Panic("Can't open file\n"); #else osi_Panic("Can't open inode %d\n", ainode); #endif afile->filp = filp; afile->size = i_size_read(FILE_INODE(filp)); AFS_GLOCK(); afile->offset = 0; afile->proc = (int (*)())0; #if defined(LINUX_USE_FH) afile->inum = tip->i_ino; /* for hint validity checking */ #else afile->inum = ainode; /* for hint validity checking */ #endif return (void *)afile; }
/* This function is surprisingly simple. The trick is understanding * that "child" is always a directory. So, to find its parent, you * simply need to find its ".." entry, normalize its block and offset, * and return the underlying inode. See the comments for * isofs_normalize_block_and_offset(). */ static struct dentry *isofs_export_get_parent(struct dentry *child) { unsigned long parent_block = 0; unsigned long parent_offset = 0; struct inode *child_inode = child->d_inode; struct iso_inode_info *e_child_inode = ISOFS_I(child_inode); struct inode *parent_inode = NULL; struct iso_directory_record *de = NULL; struct buffer_head * bh = NULL; struct dentry *rv = NULL; /* "child" must always be a directory. */ if (!S_ISDIR(child_inode->i_mode)) { printk(KERN_ERR "isofs: isofs_export_get_parent(): " "child is not a directory!\n"); rv = ERR_PTR(-EACCES); goto out; } /* It is an invariant that the directory offset is zero. If * it is not zero, it means the directory failed to be * normalized for some reason. */ if (e_child_inode->i_iget5_offset != 0) { printk(KERN_ERR "isofs: isofs_export_get_parent(): " "child directory not normalized!\n"); rv = ERR_PTR(-EACCES); goto out; } /* The child inode has been normalized such that its * i_iget5_block value points to the "." entry. Fortunately, * the ".." entry is located in the same block. */ parent_block = e_child_inode->i_iget5_block; /* Get the block in question. */ bh = sb_bread(child_inode->i_sb, parent_block); if (bh == NULL) { rv = ERR_PTR(-EACCES); goto out; } /* This is the "." entry. */ de = (struct iso_directory_record*)bh->b_data; /* The ".." entry is always the second entry. */ parent_offset = (unsigned long)isonum_711(de->length); de = (struct iso_directory_record*)(bh->b_data + parent_offset); /* Verify it is in fact the ".." entry. */ if ((isonum_711(de->name_len) != 1) || (de->name[0] != 1)) { printk(KERN_ERR "isofs: Unable to find the \"..\" " "directory for NFS.\n"); rv = ERR_PTR(-EACCES); goto out; } /* Normalize */ isofs_normalize_block_and_offset(de, &parent_block, &parent_offset); /* Get the inode. */ parent_inode = isofs_iget(child_inode->i_sb, parent_block, parent_offset); if (IS_ERR(parent_inode)) { rv = ERR_CAST(parent_inode); if (rv != ERR_PTR(-ENOMEM)) rv = ERR_PTR(-EACCES); goto out; } /* Allocate the dentry. */ rv = d_alloc_anon(parent_inode); if (rv == NULL) { rv = ERR_PTR(-ENOMEM); goto out; } out: if (bh) { brelse(bh); } return rv; }
/* * Given a FID, obtain or construct a dentry, or return an error. * This should be called with the BKL and AFS_GLOCK held. */ static struct dentry *get_dentry_from_fid(cred_t *credp, struct VenusFid *afid) { struct vrequest treq; struct vcache *vcp; struct vattr vattr; struct inode *ip; struct dentry *dp; afs_int32 code; code = afs_InitReq(&treq, credp); if (code) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): afs_InitReq: %d\n", afid->Cell, afid->Fid.Volume, afid->Fid.Vnode, afid->Fid.Unique, code); #endif return ERR_PTR(-afs_CheckCode(code, &treq, 101)); } vcp = afs_GetVCache(afid, &treq, NULL, NULL); if (vcp == NULL) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): no vcache\n", afid->Cell, afid->Fid.Volume, afid->Fid.Vnode, afid->Fid.Unique); #endif return NULL; } /* * Now, it might be that we just caused a directory vnode to * spring into existence, in which case its parent FID is unset. * We need to do something about that, but only because we care * in our own get_parent(), below -- the common code never looks * at parentVnode on directories, except for VIOCGETVCXSTATUS. * So, if this fails, we don't really care very much. */ if (vType(vcp) == VDIR && vcp->mvstat != 2 && !vcp->f.parent.vnode) update_dir_parent(&treq, vcp); /* * If this is a volume root directory and fakestat is enabled, * we might need to replace the directory by a mount point. */ code = UnEvalFakeStat(&treq, &vcp); if (code) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): UnEvalFakeStat: %d\n", afid->Cell, afid->Fid.Volume, afid->Fid.Vnode, afid->Fid.Unique, code); #endif afs_PutVCache(vcp); return ERR_PTR(-afs_CheckCode(code, &treq, 101)); } ip = AFSTOV(vcp); afs_getattr(vcp, &vattr, credp); afs_fill_inode(ip, &vattr); /* d_alloc_anon might block, so we shouldn't hold the glock */ AFS_GUNLOCK(); dp = d_alloc_anon(ip); AFS_GLOCK(); if (!dp) { iput(ip); #ifdef OSI_EXPORT_DEBUG printk("afs: get_dentry_from_fid(0x%08x/%d/%d.%d): out of memory\n", afid->Cell, afid->Fid.Volume, afid->Fid.Vnode, afid->Fid.Unique); #endif return ERR_PTR(-ENOMEM); } dp->d_op = &afs_dentry_operations; return dp; }
/** * ntfs_get_parent - find the dentry of the parent of a given directory dentry * @child_dent: dentry of the directory whose parent directory to find * * Find the dentry for the parent directory of the directory specified by the * dentry @child_dent. This function is called from * fs/exportfs/expfs.c::find_exported_dentry() which in turn is called from the * default ->decode_fh() which is export_decode_fh() in the same file. * * The code is based on the ext3 ->get_parent() implementation found in * fs/ext3/namei.c::ext3_get_parent(). * * Note: ntfs_get_parent() is called with @child_dent->d_inode->i_mutex down. * * Return the dentry of the parent directory on success or the error code on * error (IS_ERR() is true). */ static struct dentry *ntfs_get_parent(struct dentry *child_dent) { struct inode *vi = child_dent->d_inode; ntfs_inode *ni = NTFS_I(vi); MFT_RECORD *mrec; ntfs_attr_search_ctx *ctx; ATTR_RECORD *attr; FILE_NAME_ATTR *fn; struct inode *parent_vi; struct dentry *parent_dent; unsigned long parent_ino; int err; ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); /* Get the mft record of the inode belonging to the child dentry. */ mrec = map_mft_record(ni); if (IS_ERR(mrec)) return (struct dentry *)mrec; /* Find the first file name attribute in the mft record. */ ctx = ntfs_attr_get_search_ctx(ni, mrec); if (unlikely(!ctx)) { unmap_mft_record(ni); return ERR_PTR(-ENOMEM); } try_next: err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx); if (unlikely(err)) { ntfs_attr_put_search_ctx(ctx); unmap_mft_record(ni); if (err == -ENOENT) ntfs_error(vi->i_sb, "Inode 0x%lx does not have a " "file name attribute. Run chkdsk.", vi->i_ino); return ERR_PTR(err); } attr = ctx->attr; if (unlikely(attr->non_resident)) goto try_next; fn = (FILE_NAME_ATTR *)((u8 *)attr + le16_to_cpu(attr->data.resident.value_offset)); if (unlikely((u8 *)fn + le32_to_cpu(attr->data.resident.value_length) > (u8*)attr + le32_to_cpu(attr->length))) goto try_next; /* Get the inode number of the parent directory. */ parent_ino = MREF_LE(fn->parent_directory); /* Release the search context and the mft record of the child. */ ntfs_attr_put_search_ctx(ctx); unmap_mft_record(ni); /* Get the inode of the parent directory. */ parent_vi = ntfs_iget(vi->i_sb, parent_ino); if (IS_ERR(parent_vi) || unlikely(is_bad_inode(parent_vi))) { if (!IS_ERR(parent_vi)) iput(parent_vi); ntfs_error(vi->i_sb, "Failed to get parent directory inode " "0x%lx of child inode 0x%lx.", parent_ino, vi->i_ino); return ERR_PTR(-EACCES); } /* Finally get a dentry for the parent directory and return it. */ parent_dent = d_alloc_anon(parent_vi); if (unlikely(!parent_dent)) { iput(parent_vi); return ERR_PTR(-ENOMEM); } ntfs_debug("Done for inode 0x%lx.", vi->i_ino); return parent_dent; }