Merge tag 'trace-seq-buf-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/roste...
[cascardo/linux.git] / fs / cifs / connect.c
index 239e1fb..2a772da 100644 (file)
@@ -70,6 +70,7 @@ enum {
        Opt_forcegid, Opt_noforcegid,
        Opt_noblocksend, Opt_noautotune,
        Opt_hard, Opt_soft, Opt_perm, Opt_noperm,
+       Opt_mapposix, Opt_nomapposix,
        Opt_mapchars, Opt_nomapchars, Opt_sfu,
        Opt_nosfu, Opt_nodfs, Opt_posixpaths,
        Opt_noposixpaths, Opt_nounix,
@@ -124,8 +125,10 @@ static const match_table_t cifs_mount_option_tokens = {
        { Opt_soft, "soft" },
        { Opt_perm, "perm" },
        { Opt_noperm, "noperm" },
-       { Opt_mapchars, "mapchars" },
+       { Opt_mapchars, "mapchars" }, /* SFU style */
        { Opt_nomapchars, "nomapchars" },
+       { Opt_mapposix, "mapposix" }, /* SFM style */
+       { Opt_nomapposix, "nomapposix" },
        { Opt_sfu, "sfu" },
        { Opt_nosfu, "nosfu" },
        { Opt_nodfs, "nodfs" },
@@ -1231,6 +1234,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
        vol->linux_uid = current_uid();
        vol->linux_gid = current_gid();
 
+       /*
+        * default to SFM style remapping of seven reserved characters
+        * unless user overrides it or we negotiate CIFS POSIX where
+        * it is unnecessary.  Can not simultaneously use more than one mapping
+        * since then readdir could list files that open could not open
+        */
+       vol->remap = true;
+
        /* default to only allowing write access to owner of the mount */
        vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
 
@@ -1338,10 +1349,18 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        vol->noperm = 1;
                        break;
                case Opt_mapchars:
-                       vol->remap = 1;
+                       vol->sfu_remap = true;
+                       vol->remap = false; /* disable SFM mapping */
                        break;
                case Opt_nomapchars:
-                       vol->remap = 0;
+                       vol->sfu_remap = false;
+                       break;
+               case Opt_mapposix:
+                       vol->remap = true;
+                       vol->sfu_remap = false; /* disable SFU mapping */
+                       break;
+               case Opt_nomapposix:
+                       vol->remap = false;
                        break;
                case Opt_sfu:
                        vol->sfu_emul = 1;
@@ -1447,9 +1466,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        vol->seal = 1;
                        break;
                case Opt_noac:
-                       printk(KERN_WARNING "CIFS: Mount option noac not "
-                               "supported. Instead set "
-                               "/proc/fs/cifs/LookupCacheEnabled to 0\n");
+                       pr_warn("CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
                        break;
                case Opt_fsc:
 #ifndef CONFIG_CIFS_FSCACHE
@@ -1579,7 +1596,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
 
                        if (strnlen(string, CIFS_MAX_USERNAME_LEN) >
                                                        CIFS_MAX_USERNAME_LEN) {
-                               printk(KERN_WARNING "CIFS: username too long\n");
+                               pr_warn("CIFS: username too long\n");
                                goto cifs_parse_mount_err;
                        }
                        vol->username = kstrdup(string, GFP_KERNEL);
@@ -1643,8 +1660,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        temp_len = strlen(value);
                        vol->password = kzalloc(temp_len+1, GFP_KERNEL);
                        if (vol->password == NULL) {
-                               printk(KERN_WARNING "CIFS: no memory "
-                                                   "for password\n");
+                               pr_warn("CIFS: no memory for password\n");
                                goto cifs_parse_mount_err;
                        }
 
@@ -1668,8 +1684,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
 
                        if (!cifs_convert_address(dstaddr, string,
                                        strlen(string))) {
-                               printk(KERN_ERR "CIFS: bad ip= option (%s).\n",
-                                       string);
+                               pr_err("CIFS: bad ip= option (%s).\n", string);
                                goto cifs_parse_mount_err;
                        }
                        got_ip = true;
@@ -1681,15 +1696,13 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
 
                        if (strnlen(string, CIFS_MAX_DOMAINNAME_LEN)
                                        == CIFS_MAX_DOMAINNAME_LEN) {
-                               printk(KERN_WARNING "CIFS: domain name too"
-                                                   " long\n");
+                               pr_warn("CIFS: domain name too long\n");
                                goto cifs_parse_mount_err;
                        }
 
                        vol->domainname = kstrdup(string, GFP_KERNEL);
                        if (!vol->domainname) {
-                               printk(KERN_WARNING "CIFS: no memory "
-                                                   "for domainname\n");
+                               pr_warn("CIFS: no memory for domainname\n");
                                goto cifs_parse_mount_err;
                        }
                        cifs_dbg(FYI, "Domain name set\n");
@@ -1702,8 +1715,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        if (!cifs_convert_address(
                                        (struct sockaddr *)&vol->srcaddr,
                                        string, strlen(string))) {
-                               printk(KERN_WARNING "CIFS:  Could not parse"
-                                                   " srcaddr: %s\n", string);
+                               pr_warn("CIFS: Could not parse srcaddr: %s\n",
+                                       string);
                                goto cifs_parse_mount_err;
                        }
                        break;
@@ -1713,8 +1726,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                                goto out_nomem;
 
                        if (strnlen(string, 1024) >= 65) {
-                               printk(KERN_WARNING "CIFS: iocharset name "
-                                                   "too long.\n");
+                               pr_warn("CIFS: iocharset name too long.\n");
                                goto cifs_parse_mount_err;
                        }
 
@@ -1722,8 +1734,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                                vol->iocharset = kstrdup(string,
                                                         GFP_KERNEL);
                                if (!vol->iocharset) {
-                                       printk(KERN_WARNING "CIFS: no memory"
-                                                           "for charset\n");
+                                       pr_warn("CIFS: no memory for charset\n");
                                        goto cifs_parse_mount_err;
                                }
                        }
@@ -1754,9 +1765,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                         * set at top of the function
                         */
                        if (i == RFC1001_NAME_LEN && string[i] != 0)
-                               printk(KERN_WARNING "CIFS: netbiosname"
-                                      " longer than 15 truncated.\n");
-
+                               pr_warn("CIFS: netbiosname longer than 15 truncated.\n");
                        break;
                case Opt_servern:
                        /* servernetbiosname specified override *SMBSERVER */
@@ -1782,8 +1791,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        /* The string has 16th byte zero still from
                           set at top of the function  */
                        if (i == RFC1001_NAME_LEN && string[i] != 0)
-                               printk(KERN_WARNING "CIFS: server net"
-                                      "biosname longer than 15 truncated.\n");
+                               pr_warn("CIFS: server netbiosname longer than 15 truncated.\n");
                        break;
                case Opt_ver:
                        string = match_strdup(args);
@@ -1795,8 +1803,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                                break;
                        }
                        /* For all other value, error */
-                       printk(KERN_WARNING "CIFS: Invalid version"
-                                           " specified\n");
+                       pr_warn("CIFS: Invalid version specified\n");
                        goto cifs_parse_mount_err;
                case Opt_vers:
                        string = match_strdup(args);
@@ -1837,7 +1844,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
        }
 
        if (!sloppy && invalid) {
-               printk(KERN_ERR "CIFS: Unknown mount option \"%s\"\n", invalid);
+               pr_err("CIFS: Unknown mount option \"%s\"\n", invalid);
                goto cifs_parse_mount_err;
        }
 
@@ -1863,8 +1870,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                /* No ip= option specified? Try to get it from UNC */
                if (!cifs_convert_address(dstaddr, &vol->UNC[2],
                                                strlen(&vol->UNC[2]))) {
-                       printk(KERN_ERR "Unable to determine destination "
-                                       "address.\n");
+                       pr_err("Unable to determine destination address.\n");
                        goto cifs_parse_mount_err;
                }
        }
@@ -1875,20 +1881,18 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
        if (uid_specified)
                vol->override_uid = override_uid;
        else if (override_uid == 1)
-               printk(KERN_NOTICE "CIFS: ignoring forceuid mount option "
-                                  "specified with no uid= option.\n");
+               pr_notice("CIFS: ignoring forceuid mount option specified with no uid= option.\n");
 
        if (gid_specified)
                vol->override_gid = override_gid;
        else if (override_gid == 1)
-               printk(KERN_NOTICE "CIFS: ignoring forcegid mount option "
-                                  "specified with no gid= option.\n");
+               pr_notice("CIFS: ignoring forcegid mount option specified with no gid= option.\n");
 
        kfree(mountdata_copy);
        return 0;
 
 out_nomem:
-       printk(KERN_WARNING "Could not allocate temporary buffer\n");
+       pr_warn("Could not allocate temporary buffer\n");
 cifs_parse_mount_err:
        kfree(string);
        kfree(mountdata_copy);
@@ -3197,6 +3201,8 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
        if (pvolume_info->server_ino)
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
        if (pvolume_info->remap)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SFM_CHR;
+       if (pvolume_info->sfu_remap)
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
        if (pvolume_info->no_xattr)
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
@@ -3239,10 +3245,20 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
        }
        if (pvolume_info->mfsymlinks) {
                if (pvolume_info->sfu_emul) {
-                       cifs_dbg(VFS, "mount option mfsymlinks ignored if sfu mount option is used\n");
-               } else {
-                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
+                       /*
+                        * Our SFU ("Services for Unix" emulation does not allow
+                        * creating symlinks but does allow reading existing SFU
+                        * symlinks (it does allow both creating and reading SFU
+                        * style mknod and FIFOs though). When "mfsymlinks" and
+                        * "sfu" are both enabled at the same time, it allows
+                        * reading both types of symlinks, but will only create
+                        * them with mfsymlinks format. This allows better
+                        * Apple compatibility (probably better for Samba too)
+                        * while still recognizing old Windows style symlinks.
+                        */
+                       cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n");
                }
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
        }
 
        if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
@@ -3330,8 +3346,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
        ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1;
 
        rc = get_dfs_path(xid, ses, ref_path, cifs_sb->local_nls,
-                         &num_referrals, &referrals,
-                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+                         &num_referrals, &referrals, cifs_remap(cifs_sb));
 
        if (!rc && num_referrals > 0) {
                char *fake_devname = NULL;