Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 26 Mar 2009 22:46:37 +0000 (15:46 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 26 Mar 2009 22:46:37 +0000 (15:46 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  [CIFS] Fix memory overwrite when saving nativeFileSystem field during mount
  [CIFS]  Rename compose_mount_options to cifs_compose_mount_options.
  [CIFS] work around bug in Samba server handling for posix open
  [CIFS] Use posix open on file open when server supports it
  cifs: fix buffer format byte on NT Rename/hardlink
  [CIFS] Add definitions for remoteably fsctl calls
  [CIFS] add extra null attr check
  [CIFS] fix build error
  [CIFS] reopen file via newer posix open protocol operation if available
  [CIFS] Add new nostrictsync cifs mount option to avoid slow SMB flush
  [CIFS] DFS no longer experimental
  [CIFS] Send SMB flush in cifs_fsync

15 files changed:
fs/cifs/CHANGES
fs/cifs/Kconfig
fs/cifs/README
fs/cifs/cifs_debug.c
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/smbfsctl.h [new file with mode: 0644]

index 851388fafc7302dbae9d5b5f7f33da5101eed4cd..65984006192c8b7938acd9d5c7a53b0fc58c9c3e 100644 (file)
@@ -6,7 +6,16 @@ the server to treat subsequent connections, especially those that
 are authenticated as guest, as reconnections, invalidating the earlier
 user's smb session.  This fix allows cifs to mount multiple times to the
 same server with different userids without risking invalidating earlier
-established security contexts.
+established security contexts.  fsync now sends SMB Flush operation
+to better ensure that we wait for server to write all of the data to
+server disk (not just write it over the network).  Add new mount
+parameter to allow user to disable sending the (slow) SMB flush on
+fsync if desired (fsync still flushes all cached write data to the server).
+Posix file open support added (turned off after one attempt if server
+fails to support it properly, as with Samba server versions prior to 3.3.2)
+Fix "redzone overwritten" bug in cifs_put_tcon (CIFSTcon may allocate too
+little memory for the "nativeFileSystem" field returned by the server
+during mount). 
 
 Version 1.56
 ------------
index 341a98965bd0122d2cf3b7348175b4048e66496e..6994a0f54f020510f498641d7d81002ad122c734 100644 (file)
@@ -118,6 +118,18 @@ config CIFS_DEBUG2
           option can be turned off unless you are debugging
           cifs problems.  If unsure, say N.
 
+config CIFS_DFS_UPCALL
+         bool "DFS feature support"
+         depends on CIFS && KEYS
+         help
+           Distributed File System (DFS) support is used to access shares
+           transparently in an enterprise name space, even if the share
+           moves to a different server.  This feature also enables
+           an upcall mechanism for CIFS which contacts userspace helper
+           utilities to provide server name resolution (host names to
+           IP addresses) which is needed for implicit mounts of DFS junction
+           points. If unsure, say N.
+
 config CIFS_EXPERIMENTAL
          bool "CIFS Experimental Features (EXPERIMENTAL)"
          depends on CIFS && EXPERIMENTAL
@@ -131,12 +143,3 @@ config CIFS_EXPERIMENTAL
            (which is disabled by default). See the file fs/cifs/README
            for more details.  If unsure, say N.
 
-config CIFS_DFS_UPCALL
-         bool "DFS feature support (EXPERIMENTAL)"
-         depends on CIFS_EXPERIMENTAL
-         depends on KEYS
-         help
-           Enables an upcall mechanism for CIFS which contacts userspace
-           helper utilities to provide server name resolution (host names to
-           IP addresses) which is needed for implicit mounts of DFS junction
-           points. If unsure, say N.
index da4515e3be20b7d918ed8369b7bcde64d522e034..07434181623bbde6856570827646bb48155d1144 100644 (file)
@@ -472,6 +472,19 @@ A partial list of the supported mount options follows:
                even if the cifs server would support posix advisory locks.
                "forcemand" is accepted as a shorter form of this mount
                option.
+ nostrictsync   If this mount option is set, when an application does an
+               fsync call then the cifs client does not send an SMB Flush
+               to the server (to force the server to write all dirty data
+               for this file immediately to disk), although cifs still sends
+               all dirty (cached) file data to the server and waits for the
+               server to respond to the write.  Since SMB Flush can be
+               very slow, and some servers may be reliable enough (to risk
+               delaying slightly flushing the data to disk on the server),
+               turning on this option may be useful to improve performance for
+               applications that fsync too much, at a small risk of server
+               crash.  If this mount option is not set, by default cifs will
+               send an SMB flush request (and wait for a response) on every
+               fsync call.
  nodfs          Disable DFS (global name space support) even if the
                server claims to support it.  This can help work around
                a problem with parsing of DFS paths with Samba server
@@ -692,13 +705,14 @@ require this helper. Note that NTLMv2 security (which does not require the
 cifs.upcall helper program), instead of using Kerberos, is sufficient for
 some use cases.
 
-Enabling DFS support (used to access shares transparently in an MS-DFS
-global name space) requires that CONFIG_CIFS_EXPERIMENTAL be enabled.  In
-addition, DFS support for target shares which are specified as UNC
+DFS support allows transparent redirection to shares in an MS-DFS name space.
+In addition, DFS support for target shares which are specified as UNC
 names which begin with host names (rather than IP addresses) requires
 a user space helper (such as cifs.upcall) to be present in order to
 translate host names to ip address, and the user space helper must also
-be configured in the file /etc/request-key.conf
+be configured in the file /etc/request-key.conf.  Samba, Windows servers and
+many NAS appliances support DFS as a way of constructing a global name
+space to ease network configuration and improve reliability.
 
 To use cifs Kerberos and DFS support, the Linux keyutils package should be
 installed and something like the following lines should be added to the
index 490e34bbf27a66641c0bad3327e5bb22156a88af..877e4d9a1159d11203170ec463202187dd3a6466 100644 (file)
@@ -340,6 +340,8 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
                                seq_printf(m, "\nWrites: %d Bytes: %lld",
                                        atomic_read(&tcon->num_writes),
                                        (long long)(tcon->bytes_written));
+                               seq_printf(m, "\nFlushes: %d",
+                                       atomic_read(&tcon->num_flushes));
                                seq_printf(m, "\nLocks: %d HardLinks: %d "
                                              "Symlinks: %d",
                                        atomic_read(&tcon->num_locks),
index 85c0a74d034d0c6d7c2a415a83acfd5a585e36f6..5fdbf8a14472af21bbe610d42ab1a92f26ddc31e 100644 (file)
@@ -104,9 +104,9 @@ static char *cifs_get_share_name(const char *node_name)
 
 
 /**
- * compose_mount_options       -       creates mount options for refferral
+ * cifs_compose_mount_options  -       creates mount options for refferral
  * @sb_mountdata:      parent/root DFS mount options (template)
- * @dentry:            point where we are going to mount
+ * @fullpath:          full path in UNC format
  * @ref:               server's referral
  * @devname:           pointer for saving device name
  *
@@ -116,8 +116,8 @@ static char *cifs_get_share_name(const char *node_name)
  * Returns: pointer to new mount options or ERR_PTR.
  * Caller is responcible for freeing retunrned value if it is not error.
  */
-static char *compose_mount_options(const char *sb_mountdata,
-                                  struct dentry *dentry,
+char *cifs_compose_mount_options(const char *sb_mountdata,
+                                  const char *fullpath,
                                   const struct dfs_info3_param *ref,
                                   char **devname)
 {
@@ -128,7 +128,6 @@ static char *compose_mount_options(const char *sb_mountdata,
        char *srvIP = NULL;
        char sep = ',';
        int off, noff;
-       char *fullpath;
 
        if (sb_mountdata == NULL)
                return ERR_PTR(-EINVAL);
@@ -202,17 +201,6 @@ static char *compose_mount_options(const char *sb_mountdata,
                goto compose_mount_options_err;
        }
 
-       /*
-        * this function gives us a path with a double backslash prefix. We
-        * require a single backslash for DFS. Temporarily increment fullpath
-        * to put it in the proper form and decrement before freeing it.
-        */
-       fullpath = build_path_from_dentry(dentry);
-       if (!fullpath) {
-               rc = -ENOMEM;
-               goto compose_mount_options_err;
-       }
-       ++fullpath;
        tkn_e = strchr(tkn_e + 1, '\\');
        if (tkn_e || (strlen(fullpath) - ref->path_consumed)) {
                strncat(mountdata, &sep, 1);
@@ -221,8 +209,6 @@ static char *compose_mount_options(const char *sb_mountdata,
                        strcat(mountdata, tkn_e + 1);
                strcat(mountdata, fullpath + ref->path_consumed);
        }
-       --fullpath;
-       kfree(fullpath);
 
        /*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/
        /*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/
@@ -245,10 +231,20 @@ static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
        struct vfsmount *mnt;
        char *mountdata;
        char *devname = NULL;
+       char *fullpath;
 
        cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
-       mountdata = compose_mount_options(cifs_sb->mountdata,
-                                               dentry, ref, &devname);
+       /*
+        * this function gives us a path with a double backslash prefix. We
+        * require a single backslash for DFS.
+        */
+       fullpath = build_path_from_dentry(dentry);
+       if (!fullpath)
+               return ERR_PTR(-ENOMEM);
+
+       mountdata = cifs_compose_mount_options(cifs_sb->mountdata,
+                       fullpath + 1, ref, &devname);
+       kfree(fullpath);
 
        if (IS_ERR(mountdata))
                return (struct vfsmount *)mountdata;
index c4c306f7b06fca1056a2d5325bf99541a82b8d5c..4797787c6a4450cc14c9faa062ee55fac762f03d 100644 (file)
@@ -32,6 +32,7 @@
 #define CIFS_MOUNT_OVERR_GID    0x800 /* override gid returned from server    */
 #define CIFS_MOUNT_DYNPERM      0x1000 /* allow in-memory only mode setting   */
 #define CIFS_MOUNT_NOPOSIXBRL   0x2000 /* mandatory not posix byte range lock */
+#define CIFS_MOUNT_NOSSYNC      0x4000 /* don't do slow SMBflush on every sync*/
 
 struct cifs_sb_info {
        struct cifsTconInfo *tcon;      /* primary mount */
index e004f6db5fc87904e21d6ebc4eb0cb56ccc15d29..9fbf4dff5da6100b5a5ad902ec0384e1e18cac02 100644 (file)
@@ -254,6 +254,7 @@ struct cifsTconInfo {
        atomic_t num_smbs_sent;
        atomic_t num_writes;
        atomic_t num_reads;
+       atomic_t num_flushes;
        atomic_t num_oplock_brks;
        atomic_t num_opens;
        atomic_t num_closes;
@@ -298,6 +299,7 @@ struct cifsTconInfo {
        bool unix_ext:1;  /* if false disable Linux extensions to CIFS protocol
                                for this mount even if server would support */
        bool local_lease:1; /* check leases (only) on local system not remote */
+       bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
        bool need_reconnect:1; /* connection reset, tid now invalid */
        /* BB add field for back pointer to sb struct(s)? */
 };
index b4e2e9f0ee3d754a4b3c879827a7bceb69ee8d9b..b370489c8da5dc3db8ad149936fab422fbecee6e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifspdu.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002,2008
+ *   Copyright (c) International Business Machines  Corp., 2002,2009
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -23,6 +23,7 @@
 #define _CIFSPDU_H
 
 #include <net/sock.h>
+#include "smbfsctl.h"
 
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
 #define LANMAN_PROT 0
 #define POSIX_PROT  (CIFS_PROT+1)
 #define BAD_PROT 0xFFFF
 
-/* SMB command codes */
-/*
- * Some commands have minimal (wct=0,bcc=0), or uninteresting, responses
+/* SMB command codes:
+ * Note some commands have minimal (wct=0,bcc=0), or uninteresting, responses
  * (ie which include no useful data other than the SMB error code itself).
- * Knowing this helps avoid response buffer allocations and copy in some cases
+ * This can allow us to avoid response buffer allocations and copy in some cases
  */
 #define SMB_COM_CREATE_DIRECTORY      0x00 /* trivial response */
 #define SMB_COM_DELETE_DIRECTORY      0x01 /* trivial response */
 #define SMB_COM_CLOSE                 0x04 /* triv req/rsp, timestamp ignored */
+#define SMB_COM_FLUSH                 0x05 /* triv req/rsp */
 #define SMB_COM_DELETE                0x06 /* trivial response */
 #define SMB_COM_RENAME                0x07 /* trivial response */
 #define SMB_COM_QUERY_INFORMATION     0x08 /* aka getattr */
@@ -790,6 +791,12 @@ typedef struct smb_com_close_rsp {
        __u16 ByteCount;        /* bct = 0 */
 } __attribute__((packed)) CLOSE_RSP;
 
+typedef struct smb_com_flush_req {
+       struct smb_hdr hdr;     /* wct = 1 */
+       __u16 FileID;
+       __u16 ByteCount;        /* 0 */
+} __attribute__((packed)) FLUSH_REQ;
+
 typedef struct smb_com_findclose_req {
        struct smb_hdr hdr; /* wct = 1 */
        __u16 FileID;
@@ -1924,19 +1931,19 @@ typedef struct smb_com_transaction2_get_dfs_refer_req {
 #define DFS_TYPE_ROOT 0x0001
 
 /* Referral Entry Flags */
-#define DFS_NAME_LIST_REF 0x0200
+#define DFS_NAME_LIST_REF 0x0200 /* set for domain or DC referral responses */
+#define DFS_TARGET_SET_BOUNDARY 0x0400 /* only valid with version 4 dfs req */
 
-typedef struct dfs_referral_level_3 {
-       __le16 VersionNumber;
+typedef struct dfs_referral_level_3 { /* version 4 is same, + one flag bit */
+       __le16 VersionNumber;  /* must be 3 or 4 */
        __le16 Size;
        __le16 ServerType; /* 0x0001 = root targets; 0x0000 = link targets */
-       __le16 ReferralEntryFlags; /* 0x0200 bit set only for domain
-                                     or DC referral responce */
+       __le16 ReferralEntryFlags;
        __le32 TimeToLive;
        __le16 DfsPathOffset;
        __le16 DfsAlternatePathOffset;
        __le16 NetworkAddressOffset; /* offset of the link target */
-       __le16 ServiceSiteGuid;
+       __u8   ServiceSiteGuid[16];  /* MBZ, ignored */
 } __attribute__((packed)) REFERRAL3;
 
 typedef struct smb_com_transaction_get_dfs_refer_rsp {
@@ -1946,48 +1953,15 @@ typedef struct smb_com_transaction_get_dfs_refer_rsp {
        __u8 Pad;
        __le16 PathConsumed;
        __le16 NumberOfReferrals;
-       __le16 DFSFlags;
-       __u16 Pad2;
+       __le32 DFSFlags;
        REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */
        /* followed by the strings pointed to by the referral structures */
 } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_RSP;
 
 /* DFS Flags */
-#define DFSREF_REFERRAL_SERVER  0x0001
-#define DFSREF_STORAGE_SERVER   0x0002
-
-/* IOCTL information */
-/*
- * List of ioctl function codes that look to be of interest to remote clients
- * like this one.  Need to do some experimentation to make sure they all work
- * remotely.  Some of the following, such as the encryption/compression ones
- * would be invoked from tools via a specialized hook into the VFS rather
- * than via the standard vfs entry points
- */
-#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000
-#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004
-#define FSCTL_REQUEST_BATCH_OPLOCK   0x00090008
-#define FSCTL_LOCK_VOLUME            0x00090018
-#define FSCTL_UNLOCK_VOLUME          0x0009001C
-#define FSCTL_GET_COMPRESSION        0x0009003C
-#define FSCTL_SET_COMPRESSION        0x0009C040
-#define FSCTL_REQUEST_FILTER_OPLOCK  0x0009008C
-#define FSCTL_FILESYS_GET_STATISTICS 0x00090090
-#define FSCTL_SET_REPARSE_POINT      0x000900A4
-#define FSCTL_GET_REPARSE_POINT      0x000900A8
-#define FSCTL_DELETE_REPARSE_POINT   0x000900AC
-#define FSCTL_SET_SPARSE             0x000900C4
-#define FSCTL_SET_ZERO_DATA          0x000900C8
-#define FSCTL_SET_ENCRYPTION         0x000900D7
-#define FSCTL_ENCRYPTION_FSCTL_IO    0x000900DB
-#define FSCTL_WRITE_RAW_ENCRYPTED    0x000900DF
-#define FSCTL_READ_RAW_ENCRYPTED     0x000900E3
-#define FSCTL_SIS_COPYFILE           0x00090100
-#define FSCTL_SIS_LINK_FILES         0x0009C104
-
-#define IO_REPARSE_TAG_MOUNT_POINT   0xA0000003
-#define IO_REPARSE_TAG_HSM           0xC0000004
-#define IO_REPARSE_TAG_SIS           0x80000007
+#define DFSREF_REFERRAL_SERVER  0x00000001 /* all targets are DFS roots */
+#define DFSREF_STORAGE_SERVER   0x00000002 /* no further ref requests needed */
+#define DFSREF_TARGET_FAILBACK  0x00000004 /* only for DFS referral version 4 */
 
 /*
  ************************************************************************
@@ -2508,8 +2482,6 @@ struct data_blob {
        6) Use nanosecond timestamps throughout all time fields if
           corresponding attribute flag is set
        7) sendfile - handle based copy
-       8) Direct i/o
-       9) Misc fcntls?
 
        what about fixing 64 bit alignment
 
@@ -2628,7 +2600,5 @@ typedef struct file_chattr_info {
        __le64  mode; /* list of actual attribute bits on this inode */
 } __attribute__((packed)) FILE_CHATTR_INFO;  /* ext attributes
                                                (chattr, chflags) level 0x206 */
-
-#endif
-
+#endif                                 /* POSIX */
 #endif                         /* _CIFSPDU_H */
index 083dfc57c7a3e53adf54f32e9af4c56a8c2eeb9f..4167716d32f26d7ee1c9e0d040ac93e5f28546dc 100644 (file)
@@ -44,6 +44,9 @@ extern void _FreeXid(unsigned int);
 extern char *build_path_from_dentry(struct dentry *);
 extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb);
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
+extern char *cifs_compose_mount_options(const char *sb_mountdata,
+               const char *fullpath, const struct dfs_info3_param *ref,
+               char **devname);
 /* extern void renew_parental_timestamps(struct dentry *direntry);*/
 extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
                        struct smb_hdr * /* input */ ,
@@ -92,6 +95,9 @@ extern u64 cifs_UnixTimeToNT(struct timespec);
 extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
 extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
 
+extern int cifs_posix_open(char *full_path, struct inode **pinode,
+                          struct super_block *sb, int mode, int oflags,
+                          int *poplock, __u16 *pnetfid, int xid);
 extern void posix_fill_in_inode(struct inode *tmp_inode,
                                FILE_UNIX_BASIC_INFO *pData, int isNewInode);
 extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum);
@@ -281,6 +287,9 @@ extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon,
 extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
                        const int smb_file_id);
 
+extern int CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon,
+                       const int smb_file_id);
+
 extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
                        const int netfid, unsigned int count,
                        const __u64 lseek, unsigned int *nbytes, char **buf,
index 939e2f76b9596203ab68276a59aad6fd8c36981e..bc09c998631f48dae30c6b004d9f6abdcba5b4ac 100644 (file)
@@ -1933,6 +1933,27 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
        return rc;
 }
 
+int
+CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
+{
+       int rc = 0;
+       FLUSH_REQ *pSMB = NULL;
+       cFYI(1, ("In CIFSSMBFlush"));
+
+       rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
+       if (rc)
+               return rc;
+
+       pSMB->FileID = (__u16) smb_file_id;
+       pSMB->ByteCount = 0;
+       rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+       cifs_stats_inc(&tcon->num_flushes);
+       if (rc)
+               cERROR(1, ("Send error in Flush = %d", rc));
+
+       return rc;
+}
+
 int
 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
              const char *fromName, const char *toName,
@@ -2356,8 +2377,10 @@ winCreateHardLinkRetry:
                                     PATH_MAX, nls_codepage, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
-               pSMB->OldFileName[name_len] = 0;        /* pad */
-               pSMB->OldFileName[name_len + 1] = 0x04;
+
+               /* protocol specifies ASCII buffer format (0x04) for unicode */
+               pSMB->OldFileName[name_len] = 0x04;
+               pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
                name_len2 =
                    cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
                                     toName, PATH_MAX, nls_codepage, remap);
index da0f4ffa06132f725570a79f7e0b5fb0b65d1eb6..0de3b5615a227ff06573b37ad829b13d3e60a1ed 100644 (file)
@@ -95,6 +95,7 @@ struct smb_vol {
        bool local_lease:1; /* check leases only on local system, not remote */
        bool noblocksnd:1;
        bool noautotune:1;
+       bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
        unsigned int rsize;
        unsigned int wsize;
        unsigned int sockopt;
@@ -1274,6 +1275,10 @@ cifs_parse_mount_options(char *options, const char *devname,
                        vol->intr = 0;
                } else if (strnicmp(data, "intr", 4) == 0) {
                        vol->intr = 1;
+               } else if (strnicmp(data, "nostrictsync", 12) == 0) {
+                       vol->nostrictsync = 1;
+               } else if (strnicmp(data, "strictsync", 10) == 0) {
+                       vol->nostrictsync = 0;
                } else if (strnicmp(data, "serverino", 7) == 0) {
                        vol->server_ino = 1;
                } else if (strnicmp(data, "noserverino", 9) == 0) {
@@ -2160,6 +2165,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
        if (pvolume_info->nobrl)
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
+       if (pvolume_info->nostrictsync)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC;
        if (pvolume_info->mand_lock)
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
        if (pvolume_info->cifs_acl)
@@ -3667,7 +3674,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                            BCC(smb_buffer_response)) {
                                kfree(tcon->nativeFileSystem);
                                tcon->nativeFileSystem =
-                                   kzalloc(length + 2, GFP_KERNEL);
+                                   kzalloc(2*(length + 1), GFP_KERNEL);
                                if (tcon->nativeFileSystem)
                                        cifs_strfromUCS_le(
                                                tcon->nativeFileSystem,
index 89fb728326523f6f3367a7343e057350341f423a..f9b6f68be976e062894da51dade4f78cedbdc8f1 100644 (file)
@@ -129,7 +129,7 @@ cifs_bp_rename_retry:
        return full_path;
 }
 
-static int cifs_posix_open(char *full_path, struct inode **pinode,
+int cifs_posix_open(char *full_path, struct inode **pinode,
                    struct super_block *sb, int mode, int oflags,
                    int *poplock, __u16 *pnetfid, int xid)
 {
@@ -187,7 +187,9 @@ static int cifs_posix_open(char *full_path, struct inode **pinode,
        if (!pinode)
                goto posix_open_ret; /* caller does not need info */
 
-       *pinode = cifs_new_inode(sb, &presp_data->UniqueId);
+       if (*pinode == NULL)
+               *pinode = cifs_new_inode(sb, &presp_data->UniqueId);
+       /* else an inode was passed in. Update its info, don't create one */
 
        /* We do not need to close the file if new_inode fails since
           the caller will retry qpathinfo as long as inode is null */
index 12bb656fbe75881354bdfe1550b453b90f3fa4a3..81747acca4c4774b48431eb0313d80d97ecc1c6c 100644 (file)
@@ -78,8 +78,36 @@ static inline int cifs_convert_flags(unsigned int flags)
        return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
                FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA |
                FILE_READ_DATA);
+}
 
+static inline fmode_t cifs_posix_convert_flags(unsigned int flags)
+{
+       fmode_t posix_flags = 0;
 
+       if ((flags & O_ACCMODE) == O_RDONLY)
+               posix_flags = FMODE_READ;
+       else if ((flags & O_ACCMODE) == O_WRONLY)
+               posix_flags = FMODE_WRITE;
+       else if ((flags & O_ACCMODE) == O_RDWR) {
+               /* GENERIC_ALL is too much permission to request
+                  can cause unnecessary access denied on create */
+               /* return GENERIC_ALL; */
+               posix_flags = FMODE_READ | FMODE_WRITE;
+       }
+       /* can not map O_CREAT or O_EXCL or O_TRUNC flags when
+          reopening a file.  They had their effect on the original open */
+       if (flags & O_APPEND)
+               posix_flags |= (fmode_t)O_APPEND;
+       if (flags & O_SYNC)
+               posix_flags |= (fmode_t)O_SYNC;
+       if (flags & O_DIRECTORY)
+               posix_flags |= (fmode_t)O_DIRECTORY;
+       if (flags & O_NOFOLLOW)
+               posix_flags |= (fmode_t)O_NOFOLLOW;
+       if (flags & O_DIRECT)
+               posix_flags |= (fmode_t)O_DIRECT;
+
+       return posix_flags;
 }
 
 static inline int cifs_get_disposition(unsigned int flags)
@@ -96,6 +124,80 @@ static inline int cifs_get_disposition(unsigned int flags)
                return FILE_OPEN;
 }
 
+/* all arguments to this function must be checked for validity in caller */
+static inline int cifs_posix_open_inode_helper(struct inode *inode,
+                       struct file *file, struct cifsInodeInfo *pCifsInode,
+                       struct cifsFileInfo *pCifsFile, int oplock, u16 netfid)
+{
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+/*     struct timespec temp; */   /* BB REMOVEME BB */
+
+       file->private_data = kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
+       if (file->private_data == NULL)
+               return -ENOMEM;
+       pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
+       write_lock(&GlobalSMBSeslock);
+       list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList);
+
+       pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
+       if (pCifsInode == NULL) {
+               write_unlock(&GlobalSMBSeslock);
+               return -EINVAL;
+       }
+
+       /* want handles we can use to read with first
+          in the list so we do not have to walk the
+          list to search for one in write_begin */
+       if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+               list_add_tail(&pCifsFile->flist,
+                             &pCifsInode->openFileList);
+       } else {
+               list_add(&pCifsFile->flist,
+                        &pCifsInode->openFileList);
+       }
+
+       if (pCifsInode->clientCanCacheRead) {
+               /* we have the inode open somewhere else
+                  no need to discard cache data */
+               goto psx_client_can_cache;
+       }
+
+       /* BB FIXME need to fix this check to move it earlier into posix_open
+          BB  fIX following section BB FIXME */
+
+       /* if not oplocked, invalidate inode pages if mtime or file
+          size changed */
+/*     temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
+       if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
+                          (file->f_path.dentry->d_inode->i_size ==
+                           (loff_t)le64_to_cpu(buf->EndOfFile))) {
+               cFYI(1, ("inode unchanged on server"));
+       } else {
+               if (file->f_path.dentry->d_inode->i_mapping) {
+                       rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
+                       if (rc != 0)
+                               CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
+               }
+               cFYI(1, ("invalidating remote inode since open detected it "
+                        "changed"));
+               invalidate_remote_inode(file->f_path.dentry->d_inode);
+       } */
+
+psx_client_can_cache:
+       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
+               pCifsInode->clientCanCacheAll = true;
+               pCifsInode->clientCanCacheRead = true;
+               cFYI(1, ("Exclusive Oplock granted on inode %p",
+                        file->f_path.dentry->d_inode));
+       } else if ((oplock & 0xF) == OPLOCK_READ)
+               pCifsInode->clientCanCacheRead = true;
+
+       /* will have to change the unlock if we reenable the
+          filemap_fdatawrite (which does not seem necessary */
+       write_unlock(&GlobalSMBSeslock);
+       return 0;
+}
+
 /* all arguments to this function must be checked for validity in caller */
 static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
        struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile,
@@ -167,7 +269,7 @@ int cifs_open(struct inode *inode, struct file *file)
        int rc = -EACCES;
        int xid, oplock;
        struct cifs_sb_info *cifs_sb;
-       struct cifsTconInfo *pTcon;
+       struct cifsTconInfo *tcon;
        struct cifsFileInfo *pCifsFile;
        struct cifsInodeInfo *pCifsInode;
        struct list_head *tmp;
@@ -180,7 +282,7 @@ int cifs_open(struct inode *inode, struct file *file)
        xid = GetXid();
 
        cifs_sb = CIFS_SB(inode->i_sb);
-       pTcon = cifs_sb->tcon;
+       tcon = cifs_sb->tcon;
 
        if (file->f_flags & O_CREAT) {
                /* search inode for this file and fill in file->private_data */
@@ -220,6 +322,45 @@ int cifs_open(struct inode *inode, struct file *file)
 
        cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
                 inode, file->f_flags, full_path));
+
+       if (oplockEnabled)
+               oplock = REQ_OPLOCK;
+       else
+               oplock = 0;
+
+       if (!tcon->broken_posix_open && tcon->unix_ext &&
+           (tcon->ses->capabilities & CAP_UNIX) &&
+           (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+                       le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+               int oflags = (int) cifs_posix_convert_flags(file->f_flags);
+               /* can not refresh inode info since size could be stale */
+               rc = cifs_posix_open(full_path, &inode, inode->i_sb,
+                                    cifs_sb->mnt_file_mode /* ignored */,
+                                    oflags, &oplock, &netfid, xid);
+               if (rc == 0) {
+                       cFYI(1, ("posix open succeeded"));
+                       /* no need for special case handling of setting mode
+                          on read only files needed here */
+
+                       cifs_posix_open_inode_helper(inode, file, pCifsInode,
+                                                    pCifsFile, oplock, netfid);
+                       goto out;
+               } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+                       if (tcon->ses->serverNOS)
+                               cERROR(1, ("server %s of type %s returned"
+                                          " unexpected error on SMB posix open"
+                                          ", disabling posix open support."
+                                          " Check if server update available.",
+                                          tcon->ses->serverName,
+                                          tcon->ses->serverNOS));
+                       tcon->broken_posix_open = true;
+               } else if ((rc != -EIO) && (rc != -EREMOTE) &&
+                        (rc != -EOPNOTSUPP)) /* path not found or net err */
+                       goto out;
+               /* else fallthrough to retry open the old way on network i/o
+                  or DFS errors */
+       }
+
        desiredAccess = cifs_convert_flags(file->f_flags);
 
 /*********************************************************************
@@ -248,11 +389,6 @@ int cifs_open(struct inode *inode, struct file *file)
 
        disposition = cifs_get_disposition(file->f_flags);
 
-       if (oplockEnabled)
-               oplock = REQ_OPLOCK;
-       else
-               oplock = 0;
-
        /* BB pass O_SYNC flag through on file attributes .. BB */
 
        /* Also refresh inode by passing in file_info buf returned by SMBOpen
@@ -269,7 +405,7 @@ int cifs_open(struct inode *inode, struct file *file)
        }
 
        if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
-               rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
+               rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
                         desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
                         cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
                                 & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -278,7 +414,7 @@ int cifs_open(struct inode *inode, struct file *file)
 
        if (rc == -EIO) {
                /* Old server, try legacy style OpenX */
-               rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
+               rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
                        desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
                        cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
                                & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -295,12 +431,12 @@ int cifs_open(struct inode *inode, struct file *file)
        }
        pCifsFile = cifs_init_private(file->private_data, inode, file, netfid);
        write_lock(&GlobalSMBSeslock);
-       list_add(&pCifsFile->tlist, &pTcon->openFileList);
+       list_add(&pCifsFile->tlist, &tcon->openFileList);
 
        pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
        if (pCifsInode) {
                rc = cifs_open_inode_helper(inode, file, pCifsInode,
-                                           pCifsFile, pTcon,
+                                           pCifsFile, tcon,
                                            &oplock, buf, full_path, xid);
        } else {
                write_unlock(&GlobalSMBSeslock);
@@ -309,7 +445,7 @@ int cifs_open(struct inode *inode, struct file *file)
        if (oplock & CIFS_CREATE_ACTION) {
                /* time to set mode which we can not set earlier due to
                   problems creating new read-only files */
-               if (pTcon->unix_ext) {
+               if (tcon->unix_ext) {
                        struct cifs_unix_set_info_args args = {
                                .mode   = inode->i_mode,
                                .uid    = NO_CHANGE_64,
@@ -319,7 +455,7 @@ int cifs_open(struct inode *inode, struct file *file)
                                .mtime  = NO_CHANGE_64,
                                .device = 0,
                        };
-                       CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
+                       CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
                                            cifs_sb->local_nls,
                                            cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -349,7 +485,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
        int rc = -EACCES;
        int xid, oplock;
        struct cifs_sb_info *cifs_sb;
-       struct cifsTconInfo *pTcon;
+       struct cifsTconInfo *tcon;
        struct cifsFileInfo *pCifsFile;
        struct cifsInodeInfo *pCifsInode;
        struct inode *inode;
@@ -387,7 +523,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
        }
 
        cifs_sb = CIFS_SB(inode->i_sb);
-       pTcon = cifs_sb->tcon;
+       tcon = cifs_sb->tcon;
 
 /* can not grab rename sem here because various ops, including
    those that already have the rename sem can end up causing writepage
@@ -404,20 +540,37 @@ reopen_error_exit:
 
        cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
                 inode, file->f_flags, full_path));
-       desiredAccess = cifs_convert_flags(file->f_flags);
 
        if (oplockEnabled)
                oplock = REQ_OPLOCK;
        else
                oplock = 0;
 
+       if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
+           (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+                       le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+               int oflags = (int) cifs_posix_convert_flags(file->f_flags);
+               /* can not refresh inode info since size could be stale */
+               rc = cifs_posix_open(full_path, NULL, inode->i_sb,
+                                    cifs_sb->mnt_file_mode /* ignored */,
+                                    oflags, &oplock, &netfid, xid);
+               if (rc == 0) {
+                       cFYI(1, ("posix reopen succeeded"));
+                       goto reopen_success;
+               }
+               /* fallthrough to retry open the old way on errors, especially
+                  in the reconnect path it is important to retry hard */
+       }
+
+       desiredAccess = cifs_convert_flags(file->f_flags);
+
        /* Can not refresh inode by passing in file_info buf to be returned
           by SMBOpen and then calling get_inode_info with returned buf
           since file might have write behind data that needs to be flushed
           and server version of file size can be stale. If we knew for sure
           that inode was not dirty locally we could do this */
 
-       rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
+       rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
                         CREATE_NOT_DIR, &netfid, &oplock, NULL,
                         cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -426,6 +579,7 @@ reopen_error_exit:
                cFYI(1, ("cifs_open returned 0x%x", rc));
                cFYI(1, ("oplock: %d", oplock));
        } else {
+reopen_success:
                pCifsFile->netfid = netfid;
                pCifsFile->invalidHandle = false;
                up(&pCifsFile->fh_sem);
@@ -439,7 +593,7 @@ reopen_error_exit:
                           go to server to get inode info */
                                pCifsInode->clientCanCacheAll = false;
                                pCifsInode->clientCanCacheRead = false;
-                               if (pTcon->unix_ext)
+                               if (tcon->unix_ext)
                                        rc = cifs_get_inode_info_unix(&inode,
                                                full_path, inode->i_sb, xid);
                                else
@@ -467,7 +621,6 @@ reopen_error_exit:
                        cifs_relock_file(pCifsFile);
                }
        }
-
        kfree(full_path);
        FreeXid(xid);
        return rc;
@@ -1523,6 +1676,9 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
 {
        int xid;
        int rc = 0;
+       struct cifsTconInfo *tcon;
+       struct cifsFileInfo *smbfile =
+               (struct cifsFileInfo *)file->private_data;
        struct inode *inode = file->f_path.dentry->d_inode;
 
        xid = GetXid();
@@ -1534,7 +1690,12 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
        if (rc == 0) {
                rc = CIFS_I(inode)->write_behind_rc;
                CIFS_I(inode)->write_behind_rc = 0;
+               tcon = CIFS_SB(inode->i_sb)->tcon;
+               if (!rc && tcon && smbfile &&
+                  !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
+                       rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
        }
+
        FreeXid(xid);
        return rc;
 }
index 4690a360c85587ed85a76db68ab4c5afed4f998e..a8797cc60805e4b732a4f1557f8590f353073455 100644 (file)
@@ -763,6 +763,9 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
        struct cifsTconInfo *pTcon = cifs_sb->tcon;
        FILE_BASIC_INFO info_buf;
 
+       if (attrs == NULL)
+               return -EINVAL;
+
        if (attrs->ia_valid & ATTR_ATIME) {
                set_time = true;
                info_buf.LastAccessTime =
diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h
new file mode 100644 (file)
index 0000000..7056b89
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ *   fs/cifs/smbfsctl.h: SMB, CIFS, SMB2 FSCTL definitions
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002,2009
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* IOCTL information */
+/*
+ * List of ioctl/fsctl function codes that are or could be useful in the
+ * future to remote clients like cifs or SMB2 client.  There is probably
+ * a slightly larger set of fsctls that NTFS local filesystem could handle,
+ * including the seven below that we do not have struct definitions for.
+ * Even with protocol definitions for most of these now available, we still
+ * need to do some experimentation to identify which are practical to do
+ * remotely.  Some of the following, such as the encryption/compression ones
+ * could be invoked from tools via a specialized hook into the VFS rather
+ * than via the standard vfs entry points
+ */
+#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000
+#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004
+#define FSCTL_REQUEST_BATCH_OPLOCK   0x00090008
+#define FSCTL_LOCK_VOLUME            0x00090018
+#define FSCTL_UNLOCK_VOLUME          0x0009001C
+#define FSCTL_IS_PATHNAME_VALID      0x0009002C /* BB add struct */
+#define FSCTL_GET_COMPRESSION        0x0009003C /* BB add struct */
+#define FSCTL_SET_COMPRESSION        0x0009C040 /* BB add struct */
+#define FSCTL_QUERY_FAT_BPB          0x00090058 /* BB add struct */
+/* Verify the next FSCTL number, we had it as 0x00090090 before */
+#define FSCTL_FILESYSTEM_GET_STATS   0x00090060 /* BB add struct */
+#define FSCTL_GET_NTFS_VOLUME_DATA   0x00090064 /* BB add struct */
+#define FSCTL_GET_RETRIEVAL_POINTERS 0x00090073 /* BB add struct */
+#define FSCTL_IS_VOLUME_DIRTY        0x00090078 /* BB add struct */
+#define FSCTL_ALLOW_EXTENDED_DASD_IO 0x00090083 /* BB add struct */
+#define FSCTL_REQUEST_FILTER_OPLOCK  0x0009008C
+#define FSCTL_FIND_FILES_BY_SID      0x0009008F /* BB add struct */
+#define FSCTL_SET_OBJECT_ID          0x00090098 /* BB add struct */
+#define FSCTL_GET_OBJECT_ID          0x0009009C /* BB add struct */
+#define FSCTL_DELETE_OBJECT_ID       0x000900A0 /* BB add struct */
+#define FSCTL_SET_REPARSE_POINT      0x000900A4 /* BB add struct */
+#define FSCTL_GET_REPARSE_POINT      0x000900A8 /* BB add struct */
+#define FSCTL_DELETE_REPARSE_POINT   0x000900AC /* BB add struct */
+#define FSCTL_SET_OBJECT_ID_EXTENDED 0x000900BC /* BB add struct */
+#define FSCTL_CREATE_OR_GET_OBJECT_ID 0x000900C0 /* BB add struct */
+#define FSCTL_SET_SPARSE             0x000900C4 /* BB add struct */
+#define FSCTL_SET_ZERO_DATA          0x000900C8 /* BB add struct */
+#define FSCTL_SET_ENCRYPTION         0x000900D7 /* BB add struct */
+#define FSCTL_ENCRYPTION_FSCTL_IO    0x000900DB /* BB add struct */
+#define FSCTL_WRITE_RAW_ENCRYPTED    0x000900DF /* BB add struct */
+#define FSCTL_READ_RAW_ENCRYPTED     0x000900E3 /* BB add struct */
+#define FSCTL_READ_FILE_USN_DATA     0x000900EB /* BB add struct */
+#define FSCTL_WRITE_USN_CLOSE_RECORD 0x000900EF /* BB add struct */
+#define FSCTL_SIS_COPYFILE           0x00090100 /* BB add struct */
+#define FSCTL_RECALL_FILE            0x00090117 /* BB add struct */
+#define FSCTL_QUERY_SPARING_INFO     0x00090138 /* BB add struct */
+#define FSCTL_SET_ZERO_ON_DEALLOC    0x00090194 /* BB add struct */
+#define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */
+#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF /* BB add struct */
+#define FSCTL_SET_DEFECT_MANAGEMENT  0x00098134 /* BB add struct */
+#define FSCTL_SIS_LINK_FILES         0x0009C104
+#define FSCTL_PIPE_PEEK              0x0011400C /* BB add struct */
+#define FSCTL_PIPE_TRANSCEIVE        0x0011C017 /* BB add struct */
+/* strange that the number for this op is not sequential with previous op */
+#define FSCTL_PIPE_WAIT              0x00110018 /* BB add struct */
+#define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */
+#define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */
+
+#define IO_REPARSE_TAG_MOUNT_POINT   0xA0000003
+#define IO_REPARSE_TAG_HSM           0xC0000004
+#define IO_REPARSE_TAG_SIS           0x80000007