From: VMware, Inc <> Date: Thu, 27 Oct 2011 17:57:19 +0000 (-0700) Subject: Implement HgfsGetRootDentry() to get the root dentry. X-Git-Tag: 2011.10.26-514583~52 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fc0cd1018ba8831c78480a2fbc737bd6d49891ef;p=thirdparty%2Fopen-vm-tools.git Implement HgfsGetRootDentry() to get the root dentry. When the user loads vmhgfs modules and mounts a shared folder, kernel crashes. During the intial hgfs mount process, we need a root dentry. We can get the reference to the root dentry by calling d_alloc_root(). But we cannot call d_alloc_root in HgfsReadSuper() since it requires a valid inode which we don't have at that point of time. We implemented a workaround for this issue. The workaround is done in two phases as specified below: - Create a dummy root dentry by calling d_alloc_name(). - Send a getAttr request to the hgfs server and get the root inode. - Populate the content of the dummy root entry with the root inode. This workaround works perfectly fine. But, with the latest kernel version, the semantics of d_alloc_name() is changed. We can no longer pass NULL to the d_alloc_name (which we have been doing till now). Fixed this by implementing a new function HgfsGetRootDentry() that first gets the root inode, fills the properties of the root inode and then uses d_alloc_root() to generate the root dentry. Signed-off-by: Marcelo Vanzin --- diff --git a/open-vm-tools/modules/linux/vmhgfs/filesystem.c b/open-vm-tools/modules/linux/vmhgfs/filesystem.c index 0109833d2..bd1d8b4ce 100644 --- a/open-vm-tools/modules/linux/vmhgfs/filesystem.c +++ b/open-vm-tools/modules/linux/vmhgfs/filesystem.c @@ -83,6 +83,7 @@ HgfsOp hgfsVersionCreateSymlink; static inline unsigned long HgfsComputeBlockBits(unsigned long blockSize); static compat_kmem_cache_ctor HgfsInodeCacheCtor; static HgfsSuperInfo *HgfsInitSuperInfo(HgfsMountInfo *mountInfo); +static struct dentry *HgfsGetRootDentry(struct super_block *sb); static int HgfsReadSuper(struct super_block *sb, void *rawData, int flags); @@ -325,6 +326,82 @@ HgfsInitSuperInfo(HgfsMountInfo *mountInfo) // IN: Passed down from the user } +/* + *---------------------------------------------------------------------------- + * + * HgfsGetRootDentry -- + * + * Gets the root dentry for a given super block. + * + * Results: + * A valid root dentry on success, NULL otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static struct dentry * +HgfsGetRootDentry(struct super_block *sb) // IN: Super block object +{ + struct dentry *rootDentry = NULL; + struct inode *rootInode; + + ASSERT(sb); + + LOG(6, (KERN_DEBUG "VMware hgfs: %s: entered\n", __func__)); + + rootInode = HgfsGetInode(sb, HGFS_ROOT_INO); + if (rootInode) { + HgfsInodeInfo *iinfo; + static const HgfsAttrInfo attr = { + .type = HGFS_FILE_TYPE_DIRECTORY, + .size = 4192, + .specialPerms = 0, + .ownerPerms = HGFS_PERM_READ | HGFS_PERM_EXEC, + .groupPerms = HGFS_PERM_READ | HGFS_PERM_EXEC, + .otherPerms = HGFS_PERM_READ | HGFS_PERM_EXEC, + .mask = HGFS_ATTR_VALID_TYPE | + HGFS_ATTR_VALID_SIZE | + HGFS_ATTR_VALID_SPECIAL_PERMS | + HGFS_ATTR_VALID_OWNER_PERMS | + HGFS_ATTR_VALID_GROUP_PERMS | + HGFS_ATTR_VALID_OTHER_PERMS, + }; + + /* + * On an allocation failure in read_super, the inode will have been + * marked "bad". If it was, we certainly don't want to start playing with + * the HgfsInodeInfo. So quietly put the inode back and fail. + */ + if (is_bad_inode(rootInode)) { + LOG(6, (KERN_DEBUG "VMware hgfs: %s: encountered bad inode\n", + __func__)); + iput(rootInode); + goto exit; + } + + HgfsChangeFileAttributes(rootInode, &attr); + + iinfo = INODE_GET_II_P(rootInode); + iinfo->isFakeInodeNumber = FALSE; + iinfo->isReferencedInode = TRUE; + } + + rootDentry = d_alloc_root(rootInode); + if (rootDentry == NULL) { + LOG(4, (KERN_WARNING "VMware hgfs: %s: Could not get " + "root dentry\n", __func__)); + goto exit; + } + + LOG(6, (KERN_DEBUG "VMware hgfs: %s: finished\n", __func__)); +exit: + return rootDentry; +} + + /* *----------------------------------------------------------------------------- * @@ -354,10 +431,10 @@ HgfsReadSuper(struct super_block *sb, // OUT: Superblock object void *rawData, // IN: Fs-specific mount data int flags) // IN: Mount flags { - int result; + int result = 0; HgfsSuperInfo *si; HgfsMountInfo *mountInfo; - struct dentry *rootDentry; + struct dentry *rootDentry = NULL; ASSERT(sb); @@ -401,26 +478,11 @@ HgfsReadSuper(struct super_block *sb, // OUT: Superblock object sb->s_blocksize_bits = HgfsComputeBlockBits(HGFS_BLOCKSIZE); sb->s_blocksize = 1 << sb->s_blocksize_bits; - /* - * We can't use d_alloc_root() here directly because it requires a valid - * inode, which only HgfsInstantiate will create. So instead, we'll do the - * work in pieces. First we'll allocate the dentry and setup its parent - * and superblock. Then HgfsInstantiate will do the rest, issuing a getattr, - * getting the inode, and instantiating the dentry with it. - */ - rootDentry = compat_d_alloc_name(NULL, "/"); + rootDentry = HgfsGetRootDentry(sb); if (rootDentry == NULL) { - LOG(4, (KERN_WARNING "VMware hgfs: HgfsReadSuper: Could not allocate " - "root dentry\n")); - result = -ENOMEM; - goto exit; - } - rootDentry->d_parent = rootDentry; - rootDentry->d_sb = sb; - result = HgfsInstantiate(rootDentry, HGFS_ROOT_INO, NULL); - if (result) { LOG(4, (KERN_WARNING "VMware hgfs: HgfsReadSuper: Could not instantiate " "root dentry\n")); + result = -ENOMEM; goto exit; } sb->s_root = rootDentry;