}
 
        /* if there is an existing lease, reuse it */
+
+       /*
+        * note: files with hardlinks cause unexpected behaviour. As per MS-SMB2,
+        * lease keys are associated with the filepath. We are maintaining lease keys
+        * with the inode on the client. If the file has hardlinks, it is possible
+        * that the lease for a file be reused for an operation on its hardlink or
+        * vice versa.
+        * As a workaround, send request using an existing lease key and if the server
+        * returns STATUS_INVALID_PARAMETER, which maps to EINVAL, send the request
+        * again without the lease.
+        */
        if (dentry) {
                inode = d_inode(dentry);
                if (CIFS_I(inode)->lease_granted && server->ops->get_lease_key) {
 smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
            struct cifs_sb_info *cifs_sb, struct dentry *dentry)
 {
-       return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
+       int rc = smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
                                CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
                                ACL_NO_MODE, NULL,
                                &(int){SMB2_OP_DELETE}, 1,
                                NULL, NULL, NULL, dentry);
+       if (rc == -EINVAL) {
+               cifs_dbg(FYI, "invalid lease key, resending request without lease");
+               rc = smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
+                               CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
+                               ACL_NO_MODE, NULL,
+                               &(int){SMB2_OP_DELETE}, 1,
+                               NULL, NULL, NULL, NULL);
+       }
+       return rc;
 }
 
 static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
        drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
        cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
 
-       return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
+       int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
                                  co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
+       if (rc == -EINVAL) {
+               cifs_dbg(FYI, "invalid lease key, resending request without lease");
+               rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
+                                 co, DELETE, SMB2_OP_RENAME, cfile, NULL);
+       }
+       return rc;
 }
 
 int smb2_create_hardlink(const unsigned int xid,
        in_iov.iov_base = &eof;
        in_iov.iov_len = sizeof(eof);
        cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
-       return smb2_compound_op(xid, tcon, cifs_sb, full_path,
+       int rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
                                FILE_WRITE_DATA, FILE_OPEN,
                                0, ACL_NO_MODE, &in_iov,
                                &(int){SMB2_OP_SET_EOF}, 1,
                                cfile, NULL, NULL, dentry);
+       if (rc == -EINVAL) {
+               cifs_dbg(FYI, "invalid lease key, resending request without lease");
+               rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
+                               FILE_WRITE_DATA, FILE_OPEN,
+                               0, ACL_NO_MODE, &in_iov,
+                               &(int){SMB2_OP_SET_EOF}, 1,
+                               cfile, NULL, NULL, NULL);
+       }
+       return rc;
 }
 
 int