From eb47321942fccebe76344ade5b52d8f95bcbbbbf Mon Sep 17 00:00:00 2001 From: Dyno Hongjun Fu Date: Mon, 23 Nov 2015 22:10:33 -0800 Subject: [PATCH] [Bug 1526327] make vmhgfs compatible with Linux kernel 4.2 --- open-vm-tools/lib/include/hgfsDevLinux.h | 31 +- open-vm-tools/modules/linux/vmhgfs/file.c | 11 +- .../modules/linux/vmhgfs/filesystem.c | 377 ++++++++++++++++-- open-vm-tools/modules/linux/vmhgfs/link.c | 47 ++- open-vm-tools/modules/linux/vmhgfs/module.h | 8 +- open-vm-tools/modules/linux/vmhgfs/super.c | 4 +- .../modules/linux/vmhgfs/vmhgfs_version.h | 6 +- 7 files changed, 426 insertions(+), 58 deletions(-) diff --git a/open-vm-tools/lib/include/hgfsDevLinux.h b/open-vm-tools/lib/include/hgfsDevLinux.h index 04ce3618b..619d11177 100644 --- a/open-vm-tools/lib/include/hgfsDevLinux.h +++ b/open-vm-tools/lib/include/hgfsDevLinux.h @@ -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_ diff --git a/open-vm-tools/modules/linux/vmhgfs/file.c b/open-vm-tools/modules/linux/vmhgfs/file.c index 0bc5ee346..027622f84 100644 --- a/open-vm-tools/modules/linux/vmhgfs/file.c +++ b/open-vm-tools/modules/linux/vmhgfs/file.c @@ -28,6 +28,9 @@ #include #include #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) +#include /* 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, diff --git a/open-vm-tools/modules/linux/vmhgfs/filesystem.c b/open-vm-tools/modules/linux/vmhgfs/filesystem.c index 10dd8ab98..6d7a64b2e 100644 --- a/open-vm-tools/modules/linux/vmhgfs/filesystem.c +++ b/open-vm-tools/modules/linux/vmhgfs/filesystem.c @@ -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); } diff --git a/open-vm-tools/modules/linux/vmhgfs/link.c b/open-vm-tools/modules/linux/vmhgfs/link.c index 06f693b99..30a66d8ab 100644 --- a/open-vm-tools/modules/linux/vmhgfs/link.c +++ b/open-vm-tools/modules/linux/vmhgfs/link.c @@ -35,7 +35,10 @@ #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 } } diff --git a/open-vm-tools/modules/linux/vmhgfs/module.h b/open-vm-tools/modules/linux/vmhgfs/module.h index b673dc17d..d30184ec0 100644 --- a/open-vm-tools/modules/linux/vmhgfs/module.h +++ b/open-vm-tools/modules/linux/vmhgfs/module.h @@ -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 +#endif #include #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. */ diff --git a/open-vm-tools/modules/linux/vmhgfs/super.c b/open-vm-tools/modules/linux/vmhgfs/super.c index 04a21920e..359bf39e4 100644 --- a/open-vm-tools/modules/linux/vmhgfs/super.c +++ b/open-vm-tools/modules/linux/vmhgfs/super.c @@ -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); } diff --git a/open-vm-tools/modules/linux/vmhgfs/vmhgfs_version.h b/open-vm-tools/modules/linux/vmhgfs/vmhgfs_version.h index a29530052..b8569b51e 100644 --- a/open-vm-tools/modules/linux/vmhgfs/vmhgfs_version.h +++ b/open-vm-tools/modules/linux/vmhgfs/vmhgfs_version.h @@ -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_ */ -- 2.47.3