]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
[Bug 1526327] make vmhgfs compatible with Linux kernel 4.2
authorDyno Hongjun Fu <hfu@vmware.com>
Tue, 24 Nov 2015 06:10:33 +0000 (22:10 -0800)
committerDyno Hongjun Fu <hfu@vmware.com>
Tue, 24 Nov 2015 06:35:21 +0000 (22:35 -0800)
open-vm-tools/lib/include/hgfsDevLinux.h
open-vm-tools/modules/linux/vmhgfs/file.c
open-vm-tools/modules/linux/vmhgfs/filesystem.c
open-vm-tools/modules/linux/vmhgfs/link.c
open-vm-tools/modules/linux/vmhgfs/module.h
open-vm-tools/modules/linux/vmhgfs/super.c
open-vm-tools/modules/linux/vmhgfs/vmhgfs_version.h

index 04ce3618b19ca9288e19fc7bb15b240df8766057..619d11177aa43b1cad0b8437f9739c4fadb5b67b 100644 (file)
@@ -49,7 +49,8 @@
 #define HGFS_MOUNT_POINT "/mnt/hgfs"    // Type of FS (e.g. vmhgfs-fuse )
 #define HGFS_DEVICE_NAME "dev"          // Name of our device under /proc/fs/HGFS_NAME/
 #define HGFS_SUPER_MAGIC 0xbacbacbc     // Superblock magic number
-#define HGFS_PROTOCOL_VERSION 1         // Incremented when something changes
+#define HGFS_PROTOCOL_VERSION   2       // Version 2 has size and flags field added
+#define HGFS_PROTOCOL_VERSION_1 1       // Version 1
 #define HGFS_DEFAULT_TTL 1              // Default TTL for dentries
 
 /*
@@ -97,4 +98,32 @@ __attribute__((__packed__))
 #endif
 HgfsMountInfo;
 
+/*
+ * Version 1 of the MountInfo object.
+ * This is used so that newer kernel clients can allow mounts using
+ * older versions of the mounter application for backwards compatibility.
+ */
+typedef
+struct HgfsMountInfoV1 {
+   uint32 magicNumber;        // hgfs magic number
+   uint32 version;            // protocol version
+   uint32 fd;                 // file descriptor of client file
+#ifndef sun
+   uid_t uid;                 // desired owner of files
+   Bool uidSet;               // is the owner actually set?
+   gid_t gid;                 // desired group of files
+   Bool gidSet;               // is the group actually set?
+   unsigned short fmask;      // desired file mask
+   unsigned short dmask;      // desired directory mask
+   uint32 ttl;                // number of seconds before revalidating dentries
+#if defined __APPLE__
+   char shareNameHost[MAXPATHLEN]; // must be ".host"
+   char shareNameDir[MAXPATHLEN];  // desired share name for mounting
+#else
+   const char *shareNameHost; // must be ".host"
+   const char *shareNameDir;  // desired share name for mounting
+#endif
+#endif
+} HgfsMountInfoV1;
+
 #endif //ifndef _HGFS_DEV_H_
index 0bc5ee3466d8566370da2753b740ee2ea5dfa1e5..027622f84a074e980685bd423d485eaf37a3f405 100644 (file)
@@ -28,6 +28,9 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/signal.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+#include <linux/uio.h> /* iov_iter_count */
+#endif
 #include "compat_cred.h"
 #include "compat_fs.h"
 #include "compat_kernel.h"
@@ -168,7 +171,13 @@ struct file_operations HgfsFileFileOperations = {
    .llseek     = HgfsSeek,
    .flush      = HgfsFlush,
 #if defined VMW_USE_AIO
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
+   /* Fallback to async counterpart, check kernel source read_write.c */
+   .read       = NULL,
+   .write      = NULL,
+   .read_iter  = HgfsFileRead,
+   .write_iter = HgfsFileWrite,
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
    .read       = new_sync_read,
    .write      = new_sync_write,
    .read_iter  = HgfsFileRead,
index 10dd8ab98bf2e525bb0e78eeb281dcea4b8d8122..6d7a64b2eabc6530e8028e06be03355d5ead3161 100644 (file)
@@ -82,7 +82,8 @@ HgfsOp hgfsVersionCreateSymlink;
 /* Private functions. */
 static inline unsigned long HgfsComputeBlockBits(unsigned long blockSize);
 static compat_kmem_cache_ctor HgfsInodeCacheCtor;
-static HgfsSuperInfo *HgfsInitSuperInfo(HgfsMountInfo *mountInfo);
+static HgfsSuperInfo *HgfsInitSuperInfo(void *rawData,
+                                        uint32 mountInfoVersion);
 static int HgfsReadSuper(struct super_block *sb,
                          void *rawData,
                          int flags);
@@ -188,6 +189,262 @@ HgfsInodeCacheCtor(COMPAT_KMEM_CACHE_CTOR_ARGS(slabElem)) // IN: slab item to in
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsValidateMountInfo --
+ *
+ *    Validate the the user mode mounter information.
+ *
+ * Results:
+ *    Zero on success or -EINVAL if we pass in an unknown version.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+HgfsValidateMountInfo(void *rawData,             // IN: Fs-specific mount data
+                      uint32 *mountInfoVersion)  // OUT: Mount flags
+{
+   HgfsMountInfoV1 *infoV1;
+   HgfsMountInfo *info;
+   uint32 *magicNumber;
+   int retVal = -EINVAL;
+
+   ASSERT(mountInfoVersion);
+
+   /* Sanity check the incoming user data. */
+   if (rawData == NULL) {
+      LOG(4, (KERN_CRIT LGPFX "%s: error: no user supplied mount data\n",
+              __func__));
+      goto exit;
+   }
+
+   /* Magic number is always first 4 bytes of the header. */
+   magicNumber = rawData;
+   if (*magicNumber != HGFS_SUPER_MAGIC) {
+      LOG(4, (KERN_CRIT LGPFX "%s: error: user supplied mount data is not valid!\n",
+              __func__));
+      goto exit;
+   }
+
+   /*
+    * Looks like HGFS data, now validate the version so that we can
+    * proceed and extract the required settings from the user.
+    */
+   info = rawData;
+   infoV1 = rawData;
+   if ((info->version == HGFS_PROTOCOL_VERSION_1 ||
+        info->version == HGFS_PROTOCOL_VERSION) &&
+        info->infoSize == sizeof *info) {
+      /*
+       * The current version is validated with the size and magic number.
+       * Note the version can be either 1 or 2 as it was not bumped initially.
+       * Furthermore, return the version as HGFS_PROTOCOL_VERSION (2) only since
+       * the objects are the same and it simplifies field extractions.
+       */
+      LOG(4, (KERN_DEBUG LGPFX "%s: mount data version %d passed\n",
+              __func__, info->version));
+      *mountInfoVersion = HGFS_PROTOCOL_VERSION;
+      retVal = 0;
+   } else if (infoV1->version == HGFS_PROTOCOL_VERSION_1) {
+      /*
+       * The version 1 is validated with the version and magic number.
+       * Note the version can be only be 1 and if so does not collide with version 2 of
+       * the header (which would be the info size field).
+       */
+      LOG(4, (KERN_DEBUG LGPFX "%s: mount data version %d passed\n",
+              __func__, info->version));
+      *mountInfoVersion = infoV1->version;
+      retVal = 0;
+   } else {
+      /*
+       * The version and info size fields could not be validated
+       * for the known structure. It is probably a newer version.
+       */
+      LOG(4, (KERN_DEBUG LGPFX "%s: error: user supplied mount data version %d\n",
+              __func__, infoV1->version));
+   }
+
+exit:
+   return retVal;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsGetMountInfoV1 --
+ *
+ *    Gets the fields of interest from the user mode mounter version 1.
+ *
+ * Results:
+ *    None
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+HgfsGetMountInfoV1(HgfsMountInfoV1 *mountInfo, // IN: version 1 mount data
+                   uint32 *mntFlags,           // OUT: Mount flags
+                   uint32 *ttl,                // OUT: seconds until revalidate
+                   uid_t *uid,                 // OUT: owner
+                   gid_t *gid,                 // OUT: group
+                   mode_t *fmask,              // OUT: file mask
+                   mode_t *dmask,              // OUT: directory mask
+                   const char **shareHost,     // OUT: share host name
+                   const char **shareDir)      // OUT: share directory
+{
+   ASSERT(mountInfo);
+
+   *mntFlags = 0;
+   /*
+    * If the mounter specified a uid or gid, we will prefer them over any uid
+    * or gid given to us by the server.
+    */
+   if (mountInfo->uidSet) {
+      *mntFlags |= HGFS_MNT_SET_UID;
+      *uid = mountInfo->uid;
+   }
+
+   if (mountInfo->gidSet) {
+      *mntFlags |= HGFS_MNT_SET_GID;
+      *gid = mountInfo->gid;
+   }
+
+   *fmask = mountInfo->fmask;
+   *dmask = mountInfo->dmask;
+   *ttl = mountInfo->ttl;
+   *shareHost = mountInfo->shareNameHost;
+   *shareDir = mountInfo->shareNameDir;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsGetMountInfoV2 --
+ *
+ *    Gets the fields of interest from the user mode mounter version 2.
+ *
+ * Results:
+ *    None
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+HgfsGetMountInfoV2(HgfsMountInfo *mountInfo,   // IN: version 2 mount data
+                   uint32 *mntFlags,           // OUT: Mount flags
+                   uint32 *ttl,                // OUT: seconds until revalidate
+                   uid_t *uid,                 // OUT: owner
+                   gid_t *gid,                 // OUT: group
+                   mode_t *fmask,              // OUT: file mask
+                   mode_t *dmask,              // OUT: directory mask
+                   const char **shareHost,     // OUT: share host name
+                   const char **shareDir)      // OUT: share directory
+{
+   ASSERT(mountInfo);
+
+   *mntFlags = 0;
+
+   if ((mountInfo->flags & HGFS_MNTINFO_SERVER_INO) != 0) {
+      *mntFlags |= HGFS_MNT_SERVER_INUM;
+   }
+
+   /*
+    * If the mounter specified a uid or gid, we will prefer them over any uid
+    * or gid given to us by the server.
+    */
+   if (mountInfo->uidSet) {
+      *mntFlags |= HGFS_MNT_SET_UID;
+      *uid = mountInfo->uid;
+   }
+
+   if (mountInfo->gidSet) {
+      *mntFlags |= HGFS_MNT_SET_GID;
+      *gid = mountInfo->gid;
+   }
+
+   *fmask = mountInfo->fmask;
+   *dmask = mountInfo->dmask;
+   *ttl = mountInfo->ttl;
+   *shareHost = mountInfo->shareNameHost;
+   *shareDir = mountInfo->shareNameDir;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsGetMountInfo --
+ *
+ *    Gets the fields of interest from the user mode mounter.
+ *
+ * Results:
+ *    Zero on success or -EINVAL if we pass in an unknown version.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+HgfsGetMountInfo(void *rawData,            // IN: Fs-specific mount data
+                 uint32 mountInfoVersion,  // IN: mount information version
+                 uint32 *mntFlags,         // OUT: Mount flags
+                 uint32 *ttl,             // OUT: seconds until revalidate
+                 uid_t *uid,              // OUT: owner
+                 gid_t *gid,              // OUT: group
+                 mode_t *fmask,           // OUT: file mask
+                 mode_t *dmask,           // OUT: directory mask
+                 const char **shareHost,  // OUT: share host name
+                 const char **shareDir)   // OUT: share path
+{
+   int result = 0;
+
+   switch (mountInfoVersion) {
+   case HGFS_PROTOCOL_VERSION_1:
+      HgfsGetMountInfoV1(rawData,
+                         mntFlags,
+                         ttl,
+                         uid,
+                         gid,
+                         fmask,
+                         dmask,
+                         shareHost,
+                         shareDir);
+      break;
+   case HGFS_PROTOCOL_VERSION:
+      HgfsGetMountInfoV2(rawData,
+                         mntFlags,
+                         ttl,
+                         uid,
+                         gid,
+                         fmask,
+                         dmask,
+                         shareHost,
+                         shareDir);
+      break;
+   default:
+      ASSERT(FALSE);
+      result = -EINVAL;
+   }
+
+   return result;
+}
+
+
 /*
  *----------------------------------------------------------------------
  *
@@ -206,58 +463,79 @@ HgfsInodeCacheCtor(COMPAT_KMEM_CACHE_CTOR_ARGS(slabElem)) // IN: slab item to in
  */
 
 static HgfsSuperInfo *
-HgfsInitSuperInfo(HgfsMountInfo *mountInfo) // IN: Passed down from the user
+HgfsInitSuperInfo(void *rawData,            // IN: Passed down from the user
+                  uint32 mountInfoVersion)  // IN: version
 {
    HgfsSuperInfo *si = NULL;
    int result = 0;
    int len;
-   char *tmpName;
+   char *tmpName = NULL;
    Bool hostValid;
+   uint32 mntFlags = 0;
+   uint32 ttl = 0;
+   uid_t uid = 0;
+   gid_t gid = 0;
+   mode_t fmask = 0;
+   mode_t dmask = 0;
+   const char *shareHost;
+   const char *shareDir;
 
    si = kmalloc(sizeof *si, GFP_KERNEL);
    if (!si) {
       result = -ENOMEM;
-      goto out2;
+      goto out_error_si;
    }
+   memset(si, 0, sizeof *si);
 
-   /*
-    * Initialize with the default flags.
-    */
-   si->mntFlags = 0;
-   if ((mountInfo->flags & HGFS_MNTINFO_SERVER_INO) != 0) {
-      si->mntFlags |= HGFS_MNT_SERVER_INUM;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+   result = bdi_setup_and_register(&si->bdi, HGFS_NAME);
+   if (result) {
+      LOG(6, (KERN_DEBUG "VMware hgfs: %s: initialize backing device info"
+              "failed. (%d)\n", __func__, result));
+      goto out_error_si;
+   }
+#endif
+
+   result = HgfsGetMountInfo(rawData,
+                             mountInfoVersion,
+                             &mntFlags,
+                             &ttl,
+                             &uid,
+                             &gid,
+                             &fmask,
+                             &dmask,
+                             &shareHost,
+                             &shareDir);
+   if (result < 0) {
+      LOG(6, (KERN_DEBUG LGPFX "%s: error: get mount info %d\n", __func__, result));
+      goto out_error_last;
    }
 
    /*
-    * If the mounter specified a uid or gid, we will prefer them over any uid
-    * or gid given to us by the server.
+    * Initialize with the default flags.
     */
-   if (mountInfo->uidSet) {
-      si->mntFlags |= HGFS_MNT_SET_UID;
-   }
+   si->mntFlags = mntFlags;
+
    si->uid = current_uid();
    if ((si->mntFlags & HGFS_MNT_SET_UID) != 0) {
-      kuid_t mntUid = make_kuid(current_user_ns(), mountInfo->uid);
+      kuid_t mntUid = make_kuid(current_user_ns(), uid);
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
       if (uid_valid(mntUid))
 #endif
          si->uid = mntUid;
    }
 
-   if (mountInfo->gidSet) {
-      si->mntFlags |= HGFS_MNT_SET_GID;
-   }
    si->gid = current_gid();
    if ((si->mntFlags & HGFS_MNT_SET_GID) != 0) {
-      kgid_t mntGid = make_kgid(current_user_ns(), mountInfo->gid);
+      kgid_t mntGid = make_kgid(current_user_ns(), gid);
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
       if (gid_valid(mntGid))
 #endif
          si->gid = mntGid;
    }
-   si->fmask = mountInfo->fmask;
-   si->dmask = mountInfo->dmask;
-   si->ttl = mountInfo->ttl * HZ; // in ticks
+   si->fmask = fmask;
+   si->dmask = dmask;
+   si->ttl = ttl * HZ; // in ticks
 
    /*
     * We don't actually care about this field (though we may care in the
@@ -273,15 +551,15 @@ HgfsInitSuperInfo(HgfsMountInfo *mountInfo) // IN: Passed down from the user
       LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: could not obtain "
               "memory for filename\n"));
       result = -ENOMEM;
-      goto out2;
+      goto out_error_last;
    }
 
-   len = strncpy_from_user(tmpName, mountInfo->shareNameHost, PATH_MAX);
+   len = strncpy_from_user(tmpName, shareHost, PATH_MAX);
    if (len < 0 || len >= PATH_MAX) {
       LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: strncpy_from_user "
               "on host string failed\n"));
       result = len < 0 ? len : -ENAMETOOLONG;
-      goto out;
+      goto out_error_last;
    }
 
    hostValid = strcmp(tmpName, ".host") == 0;
@@ -289,26 +567,26 @@ HgfsInitSuperInfo(HgfsMountInfo *mountInfo) // IN: Passed down from the user
       LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: host string is "
               "invalid\n"));
       result = -EINVAL;
-      goto out;
+      goto out_error_last;
    }
 
    /*
     * Perform a simple sanity check on the directory portion: it must begin
     * with forward slash.
     */
-   len = strncpy_from_user(tmpName, mountInfo->shareNameDir, PATH_MAX);
+   len = strncpy_from_user(tmpName, shareDir, PATH_MAX);
    if (len < 0 || len >= PATH_MAX) {
       LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: strncpy_from_user "
               "on dir string failed\n"));
       result = len < 0 ? len : -ENAMETOOLONG;
-      goto out;
+      goto out_error_last;
    }
 
    if (*tmpName != '/') {
       LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: dir string is "
               "invalid\n"));
       result = -EINVAL;
-      goto out;
+      goto out_error_last;
    }
 
    /*
@@ -326,18 +604,25 @@ HgfsInitSuperInfo(HgfsMountInfo *mountInfo) // IN: Passed down from the user
       LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: kstrdup on "
               "dir string failed\n"));
       result = -ENOMEM;
-      goto out;
+      goto out_error_last;
    }
    si->shareNameLen = strlen(si->shareName);
 
-  out:
-   compat___putname(tmpName);
-  out2:
+out_error_last:
+   if (tmpName) {
+      compat___putname(tmpName);
+   }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+   if (result) {
+      bdi_destroy(&si->bdi);
+   }
+#endif
+out_error_si:
    if (result) {
-      /* If we failed, si->shareName couldn't have been allocated. */
       kfree(si);
       si = ERR_PTR(result);
    }
+
    return si;
 }
 
@@ -373,25 +658,21 @@ HgfsReadSuper(struct super_block *sb, // OUT: Superblock object
 {
    int result = 0;
    HgfsSuperInfo *si;
-   HgfsMountInfo *mountInfo;
    struct dentry *rootDentry = NULL;
+   uint32 mountInfoVersion;
 
    ASSERT(sb);
 
    LOG(6, (KERN_DEBUG "VMware hgfs: HgfsReadSuper: entered\n"));
 
    /* Sanity check the incoming user data. */
-   mountInfo = (HgfsMountInfo *)rawData;
-   if (!mountInfo ||
-       mountInfo->magicNumber != HGFS_SUPER_MAGIC ||
-       mountInfo->infoSize != sizeof *mountInfo ||
-       mountInfo->version != HGFS_PROTOCOL_VERSION) {
-      LOG(4, (KERN_CRIT LGPFX "%s: bad mount data passed\n", __func__));
-      return -EINVAL;
+   result = HgfsValidateMountInfo(rawData, &mountInfoVersion);
+   if (result < 0) {
+      return result;
    }
 
    /* Setup both our superblock and the VFS superblock. */
-   si = HgfsInitSuperInfo(mountInfo);
+   si = HgfsInitSuperInfo(rawData, mountInfoVersion);
    if (IS_ERR(si)) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsReadSuper: superinfo "
               "init failed\n"));
@@ -405,6 +686,10 @@ HgfsReadSuper(struct super_block *sb, // OUT: Superblock object
    sb->s_d_op = &HgfsDentryOperations;
 #endif
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+   sb->s_bdi = &si->bdi;
+#endif
+
    /*
     * If s_maxbytes isn't initialized, the generic write path may fail. In
     * most kernels, s_maxbytes is initialized by the kernel's superblock
@@ -439,6 +724,10 @@ HgfsReadSuper(struct super_block *sb, // OUT: Superblock object
   exit:
    if (result) {
       dput(rootDentry);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+      bdi_destroy(&si->bdi);
+      sb->s_bdi = NULL;
+#endif
       kfree(si->shareName);
       kfree(si);
    }
index 06f693b99153f50dabdd6f0b522c128c038d15b7..30a66d8ab1264dadd9eb7c1b77bae6da4764d03d 100644 (file)
 #include "vm_assert.h"
 
 /* HGFS symlink operations. */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+static const char *HgfsFollowlink(struct dentry *dentry,
+                                  void **cookie);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
 static void *HgfsFollowlink(struct dentry *dentry,
                             struct nameidata *nd);
 #else
@@ -45,7 +48,10 @@ static int HgfsFollowlink(struct dentry *dentry,
 static int HgfsReadlink(struct dentry *dentry,
                         char __user *buffer,
                         int buflen);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+static void HgfsPutlink(struct inode *unused,
+                        void *cookie);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
 static void HgfsPutlink(struct dentry *dentry,
                         struct nameidata *nd,
                         void *cookie);
@@ -85,7 +91,11 @@ struct inode_operations HgfsLinkInodeOperations = {
  *----------------------------------------------------------------------
  */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+static const char *
+HgfsFollowlink(struct dentry *dentry,
+               void **cookie)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
 static void *
 HgfsFollowlink(struct dentry *dentry, // IN: Dentry containing link
                struct nameidata *nd)  // OUT: Contains target dentry
@@ -100,7 +110,9 @@ HgfsFollowlink(struct dentry *dentry, // IN: Dentry containing link
    int error;
 
    ASSERT(dentry);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
    ASSERT(nd);
+#endif
 
    if (!dentry) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: null input\n"));
@@ -124,12 +136,22 @@ HgfsFollowlink(struct dentry *dentry, // IN: Dentry containing link
       } else {
          LOG(6, (KERN_DEBUG "VMware hgfs: %s: calling nd_set_link %s\n",
                  __func__, fileName));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+         *cookie = fileName;
+#else
          nd_set_link(nd, fileName);
+#endif
       }
    }
-  out:
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
+out:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+   if (!error) {
+      return *cookie;
+   } else {
+      return ERR_PTR(error);
+   }
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
    return ERR_PTR(error);
 #else
    return error;
@@ -219,7 +241,11 @@ HgfsReadlink(struct dentry *dentry,  // IN:  Dentry containing link
  *----------------------------------------------------------------------
  */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+static void
+HgfsPutlink(struct inode *unused,
+            void *cookie)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
 static void
 HgfsPutlink(struct dentry *dentry, // dentry
             struct nameidata *nd,  // lookup name information
@@ -232,14 +258,21 @@ HgfsPutlink(struct dentry *dentry, // dentry
 {
    char *fileName = NULL;
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+   fileName = cookie;
+   LOG(6, (KERN_DEBUG "VMware hgfs: %s: put for %s\n",
+           __func__, fileName));
+#else
    LOG(6, (KERN_DEBUG "VMware hgfs: %s: put for %s\n",
            __func__, dentry->d_name.name));
-
    fileName = nd_get_link(nd);
+#endif
    if (!IS_ERR(fileName)) {
       LOG(6, (KERN_DEBUG "VMware hgfs: %s: putting %s\n",
               __func__, fileName));
       kfree(fileName);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
       nd_set_link(nd, NULL);
+#endif
    }
 }
index b673dc17df8519389990853ec428271d546439ed..d30184ec06ae3ea9fc7de7d0adb7a4548d3abfb0 100644 (file)
@@ -27,7 +27,9 @@
 
 /* Must come before any kernel header file. */
 #include "driver-config.h"
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+#include <linux/backing-dev.h>
+#endif
 #include <asm/atomic.h>
 #include "compat_fs.h"
 #include "compat_semaphore.h"
@@ -136,6 +138,10 @@ typedef gid_t kgid_t;
 
 /* Data kept in each superblock in sb->u. */
 typedef struct HgfsSuperInfo {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+   struct backing_dev_info bdi;     /* Kernel VFS uses it to check whether our backend
+                                       need to writeback dirty pages among other things. */
+#endif
    kuid_t uid;                      /* UID of user who mounted this fs. */
    kgid_t gid;                      /* GID of user who mounted this fs. */
    mode_t fmask;                    /* File permission mask. */
index 04a21920ed1657b88145fdfc602b200d73f7e6b4..359bf39e42b33f9f77bf188049ab4a39c0521d05 100644 (file)
@@ -151,7 +151,9 @@ HgfsPutSuper(struct super_block *sb) // IN: The superblock
    LOG(6, (KERN_DEBUG "VMware hgfs: HgfsPutSuper: was called\n"));
 
    si = HGFS_SB_TO_COMMON(sb);
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+   bdi_destroy(&si->bdi);
+#endif
    kfree(si->shareName);
    kfree(si);
 }
index a295300528dbfe716dbe8d834c8a2d96403de642..b8569b51ec9b6cf9c6cc60c790e347b2ac4612da 100644 (file)
@@ -25,8 +25,8 @@
 #ifndef _VMHGFS_VERSION_H_
 #define _VMHGFS_VERSION_H_
 
-#define VMHGFS_DRIVER_VERSION          2.0.17.0
-#define VMHGFS_DRIVER_VERSION_COMMAS   2,0,17,0
-#define VMHGFS_DRIVER_VERSION_STRING   "2.0.17.0"
+#define VMHGFS_DRIVER_VERSION          2.0.17.1
+#define VMHGFS_DRIVER_VERSION_COMMAS   2,0,17,1
+#define VMHGFS_DRIVER_VERSION_STRING   "2.0.17.1"
 
 #endif /* _VMHGFS_VERSION_H_ */