static int orangefs_fill_sb(struct super_block *sb, struct orangefs_fs_mount_response *fs_mount, void *data, int silent) { int ret = -EINVAL; struct inode *root = NULL; struct dentry *root_dentry = NULL; struct orangefs_object_kref root_object; /* alloc and init our private orangefs sb info */ sb->s_fs_info = kzalloc(sizeof(struct orangefs_sb_info_s), GFP_KERNEL); if (!ORANGEFS_SB(sb)) return -ENOMEM; ORANGEFS_SB(sb)->sb = sb; ORANGEFS_SB(sb)->root_khandle = fs_mount->root_khandle; ORANGEFS_SB(sb)->fs_id = fs_mount->fs_id; ORANGEFS_SB(sb)->id = fs_mount->id; if (data) { ret = parse_mount_options(sb, data, silent); if (ret) return ret; } /* Hang the xattr handlers off the superblock */ sb->s_xattr = orangefs_xattr_handlers; sb->s_magic = ORANGEFS_SUPER_MAGIC; sb->s_op = &orangefs_s_ops; sb->s_d_op = &orangefs_dentry_operations; sb->s_blocksize = orangefs_bufmap_size_query(); sb->s_blocksize_bits = orangefs_bufmap_shift_query(); sb->s_maxbytes = MAX_LFS_FILESIZE; root_object.khandle = ORANGEFS_SB(sb)->root_khandle; root_object.fs_id = ORANGEFS_SB(sb)->fs_id; gossip_debug(GOSSIP_SUPER_DEBUG, "get inode %pU, fsid %d\n", &root_object.khandle, root_object.fs_id); root = orangefs_iget(sb, &root_object); if (IS_ERR(root)) return PTR_ERR(root); gossip_debug(GOSSIP_SUPER_DEBUG, "Allocated root inode [%p] with mode %x\n", root, root->i_mode); /* allocates and places root dentry in dcache */ root_dentry = d_make_root(root); if (!root_dentry) return -ENOMEM; sb->s_export_op = &orangefs_export_ops; sb->s_root = root_dentry; return 0; }
static struct dentry *orangefs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) { struct orangefs_object_kref refn; if (fh_len < 5 || fh_type > 2) return NULL; ORANGEFS_khandle_from(&(refn.khandle), fid->raw, 16); refn.fs_id = (u32) fid->raw[4]; gossip_debug(GOSSIP_SUPER_DEBUG, "fh_to_dentry: handle %pU, fs_id %d\n", &refn.khandle, refn.fs_id); return d_obtain_alias(orangefs_iget(sb, &refn)); }
/* * Attempt to resolve an object name (dentry->d_name), parent handle, and * fsid into a handle for the object. */ static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct orangefs_inode_s *parent = ORANGEFS_I(dir); struct orangefs_kernel_op_s *new_op; struct inode *inode; struct dentry *res; int ret = -EINVAL; /* * in theory we could skip a lookup here (if the intent is to * create) in order to avoid a potentially failed lookup, but * leaving it in can skip a valid lookup and try to create a file * that already exists (e.g. the vfs already handles checking for * -EEXIST on O_EXCL opens, which is broken if we skip this lookup * in the create path) */ gossip_debug(GOSSIP_NAME_DEBUG, "%s called on %s\n", __func__, dentry->d_name.name); if (dentry->d_name.len > (ORANGEFS_NAME_MAX - 1)) return ERR_PTR(-ENAMETOOLONG); new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP); if (!new_op) return ERR_PTR(-ENOMEM); new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW; gossip_debug(GOSSIP_NAME_DEBUG, "%s:%s:%d using parent %pU\n", __FILE__, __func__, __LINE__, &parent->refn.khandle); new_op->upcall.req.lookup.parent_refn = parent->refn; strncpy(new_op->upcall.req.lookup.d_name, dentry->d_name.name, ORANGEFS_NAME_MAX); gossip_debug(GOSSIP_NAME_DEBUG, "%s: doing lookup on %s under %pU,%d\n", __func__, new_op->upcall.req.lookup.d_name, &new_op->upcall.req.lookup.parent_refn.khandle, new_op->upcall.req.lookup.parent_refn.fs_id); ret = service_operation(new_op, __func__, get_interruptible_flag(dir)); gossip_debug(GOSSIP_NAME_DEBUG, "Lookup Got %pU, fsid %d (ret=%d)\n", &new_op->downcall.resp.lookup.refn.khandle, new_op->downcall.resp.lookup.refn.fs_id, ret); if (ret < 0) { if (ret == -ENOENT) { /* * if no inode was found, add a negative dentry to * dcache anyway; if we don't, we don't hold expected * lookup semantics and we most noticeably break * during directory renames. * * however, if the operation failed or exited, do not * add the dentry (e.g. in the case that a touch is * issued on a file that already exists that was * interrupted during this lookup -- no need to add * another negative dentry for an existing file) */ gossip_debug(GOSSIP_NAME_DEBUG, "orangefs_lookup: Adding *negative* dentry " "%p for %s\n", dentry, dentry->d_name.name); d_add(dentry, NULL); res = NULL; goto out; } /* must be a non-recoverable error */ res = ERR_PTR(ret); goto out; } dentry->d_time = jiffies + dcache_timeout_msecs*HZ/1000; inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn); if (IS_ERR(inode)) { gossip_debug(GOSSIP_NAME_DEBUG, "error %ld from iget\n", PTR_ERR(inode)); res = ERR_CAST(inode); goto out; } ORANGEFS_I(inode)->getattr_time = jiffies - 1; gossip_debug(GOSSIP_NAME_DEBUG, "%s:%s:%d " "Found good inode [%lu] with count [%d]\n", __FILE__, __func__, __LINE__, inode->i_ino, (int)atomic_read(&inode->i_count)); /* update dentry/inode pair into dcache */ res = d_splice_alias(inode, dentry); gossip_debug(GOSSIP_NAME_DEBUG, "Lookup success (inode ct = %d)\n", (int)atomic_read(&inode->i_count)); out: op_release(new_op); return res; }