[CIFS] Add new nostrictsync cifs mount option to avoid slow SMB flush
[safe/jmp/linux-2.6] / fs / cifs / connect.c
index e9ea394..18e84a4 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/string.h>
 #include <linux/list.h>
 #include <linux/wait.h>
-#include <linux/ipv6.h>
 #include <linux/pagemap.h>
 #include <linux/ctype.h>
 #include <linux/utsname.h>
@@ -35,6 +34,7 @@
 #include <linux/freezer.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
+#include <net/ipv6.h>
 #include "cifspdu.h"
 #include "cifsglob.h"
 #include "cifsproto.h"
@@ -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) {
@@ -1354,7 +1359,7 @@ cifs_parse_mount_options(char *options, const char *devname,
 }
 
 static struct TCP_Server_Info *
-cifs_find_tcp_session(struct sockaddr *addr)
+cifs_find_tcp_session(struct sockaddr_storage *addr)
 {
        struct list_head *tmp;
        struct TCP_Server_Info *server;
@@ -1374,13 +1379,13 @@ cifs_find_tcp_session(struct sockaddr *addr)
                if (server->tcpStatus == CifsNew)
                        continue;
 
-               if (addr->sa_family == AF_INET &&
+               if (addr->ss_family == AF_INET &&
                    (addr4->sin_addr.s_addr !=
                     server->addr.sockAddr.sin_addr.s_addr))
                        continue;
-               else if (addr->sa_family == AF_INET6 &&
-                        memcmp(&server->addr.sockAddr6.sin6_addr,
-                               &addr6->sin6_addr, sizeof(addr6->sin6_addr)))
+               else if (addr->ss_family == AF_INET6 &&
+                        !ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr,
+                                         &addr6->sin6_addr))
                        continue;
 
                ++server->srv_count;
@@ -1419,12 +1424,12 @@ static struct TCP_Server_Info *
 cifs_get_tcp_session(struct smb_vol *volume_info)
 {
        struct TCP_Server_Info *tcp_ses = NULL;
-       struct sockaddr addr;
+       struct sockaddr_storage addr;
        struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
        struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
        int rc;
 
-       memset(&addr, 0, sizeof(struct sockaddr));
+       memset(&addr, 0, sizeof(struct sockaddr_storage));
 
        if (volume_info->UNCip && volume_info->UNC) {
                rc = cifs_inet_pton(AF_INET, volume_info->UNCip,
@@ -1435,9 +1440,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
                        rc = cifs_inet_pton(AF_INET6, volume_info->UNCip,
                                            &sin_server6->sin6_addr.in6_u);
                        if (rc > 0)
-                               addr.sa_family = AF_INET6;
+                               addr.ss_family = AF_INET6;
                } else {
-                       addr.sa_family = AF_INET;
+                       addr.ss_family = AF_INET;
                }
 
                if (rc <= 0) {
@@ -1502,7 +1507,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
        tcp_ses->tcpStatus = CifsNew;
        ++tcp_ses->srv_count;
 
-       if (addr.sa_family == AF_INET6) {
+       if (addr.ss_family == AF_INET6) {
                cFYI(1, ("attempting ipv6 connect"));
                /* BB should we allow ipv6 on port 139? */
                /* other OS never observed in Wild doing 139 with v6 */
@@ -1802,7 +1807,7 @@ ipv4_connect(struct TCP_Server_Info *server)
         *  user space buffer
         */
        socket->sk->sk_rcvtimeo = 7 * HZ;
-       socket->sk->sk_sndtimeo = 3 * HZ;
+       socket->sk->sk_sndtimeo = 5 * HZ;
 
        /* make the bufsizes depend on wsize/rsize and max requests */
        if (server->noautotune) {
@@ -1860,9 +1865,7 @@ ipv4_connect(struct TCP_Server_Info *server)
                        smb_buf = (struct smb_hdr *)ses_init_buf;
                        /* sizeof RFC1002_SESSION_REQUEST with no scope */
                        smb_buf->smb_buf_length = 0x81000044;
-                       rc = smb_send(socket, smb_buf, 0x44,
-                               (struct sockaddr *) &server->addr.sockAddr,
-                               server->noblocksnd);
+                       rc = smb_send(server, smb_buf, 0x44);
                        kfree(ses_init_buf);
                        msleep(1); /* RFC1001 layer in at least one server
                                      requires very short break before negprot
@@ -1955,7 +1958,7 @@ ipv6_connect(struct TCP_Server_Info *server)
         * user space buffer
         */
        socket->sk->sk_rcvtimeo = 7 * HZ;
-       socket->sk->sk_sndtimeo = 3 * HZ;
+       socket->sk->sk_sndtimeo = 5 * HZ;
        server->ssocket = socket;
 
        return rc;
@@ -2162,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_NO_SSYNC;
        if (pvolume_info->mand_lock)
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
        if (pvolume_info->cifs_acl)
@@ -2182,6 +2187,33 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
                           "mount option supported"));
 }
 
+static int
+is_path_accessible(int xid, struct cifsTconInfo *tcon,
+                  struct cifs_sb_info *cifs_sb, const char *full_path)
+{
+       int rc;
+       __u64 inode_num;
+       FILE_ALL_INFO *pfile_info;
+
+       rc = CIFSGetSrvInodeNumber(xid, tcon, full_path, &inode_num,
+                                  cifs_sb->local_nls,
+                                  cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+       if (rc != -EOPNOTSUPP)
+               return rc;
+
+       pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
+       if (pfile_info == NULL)
+               return -ENOMEM;
+
+       rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info,
+                             0 /* not legacy */, cifs_sb->local_nls,
+                             cifs_sb->mnt_cifs_flags &
+                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+       kfree(pfile_info);
+       return rc;
+}
+
 int
 cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
           char *mount_data, const char *devname)
@@ -2192,6 +2224,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        struct cifsSesInfo *pSesInfo = NULL;
        struct cifsTconInfo *tcon = NULL;
        struct TCP_Server_Info *srvTcp = NULL;
+       char   *full_path;
 
        xid = GetXid();
 
@@ -2428,6 +2461,23 @@ mount_fail_check:
                cifs_sb->rsize = min(cifs_sb->rsize,
                               (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
 
+       if (!rc && cifs_sb->prepathlen) {
+               /* build_path_to_root works only when we have a valid tcon */
+               full_path = cifs_build_path_to_root(cifs_sb);
+               if (full_path == NULL) {
+                       rc = -ENOMEM;
+                       goto mount_fail_check;
+               }
+               rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
+               if (rc) {
+                       cERROR(1, ("Path %s in not accessible: %d",
+                                               full_path, rc));
+                       kfree(full_path);
+                       goto mount_fail_check;
+               }
+               kfree(full_path);
+       }
+
        /* volume_info->password is freed above when existing session found
        (in which case it is not needed anymore) but when new sesion is created
        the password ptr is put in the new session structure (in which case the