]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Implement HgfsGetRootDentry() to get the root dentry.
authorVMware, Inc <>
Thu, 27 Oct 2011 17:57:19 +0000 (10:57 -0700)
committerMarcelo Vanzin <mvanzin@vmware.com>
Thu, 27 Oct 2011 17:57:19 +0000 (10:57 -0700)
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 <mvanzin@vmware.com>
open-vm-tools/modules/linux/vmhgfs/filesystem.c

index 0109833d27071015ef1d28ba605a5edff2f3cf29..bd1d8b4ceefae3995fbb87222898dc7d2ac6bfb4 100644 (file)
@@ -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;